216 // Push the target offset into the branch instruction. |
216 // Push the target offset into the branch instruction. |
217 masm->pd_patch_instruction(branch, target, file, line); |
217 masm->pd_patch_instruction(branch, target, file, line); |
218 } |
218 } |
219 } |
219 } |
220 |
220 |
221 struct DelayedConstant { |
|
222 typedef void (*value_fn_t)(); |
|
223 BasicType type; |
|
224 intptr_t value; |
|
225 value_fn_t value_fn; |
|
226 // This limit of 20 is generous for initial uses. |
|
227 // The limit needs to be large enough to store the field offsets |
|
228 // into classes which do not have statically fixed layouts. |
|
229 // (Initial use is for method handle object offsets.) |
|
230 // Look for uses of "delayed_value" in the source code |
|
231 // and make sure this number is generous enough to handle all of them. |
|
232 enum { DC_LIMIT = 20 }; |
|
233 static DelayedConstant delayed_constants[DC_LIMIT]; |
|
234 static DelayedConstant* add(BasicType type, value_fn_t value_fn); |
|
235 bool match(BasicType t, value_fn_t cfn) { |
|
236 return type == t && value_fn == cfn; |
|
237 } |
|
238 static void update_all(); |
|
239 }; |
|
240 |
|
241 DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT]; |
|
242 // Default C structure initialization rules have the following effect here: |
|
243 // = { { (BasicType)0, (intptr_t)NULL }, ... }; |
|
244 |
|
245 DelayedConstant* DelayedConstant::add(BasicType type, |
|
246 DelayedConstant::value_fn_t cfn) { |
|
247 for (int i = 0; i < DC_LIMIT; i++) { |
|
248 DelayedConstant* dcon = &delayed_constants[i]; |
|
249 if (dcon->match(type, cfn)) |
|
250 return dcon; |
|
251 if (dcon->value_fn == NULL) { |
|
252 dcon->value_fn = cfn; |
|
253 dcon->type = type; |
|
254 return dcon; |
|
255 } |
|
256 } |
|
257 // If this assert is hit (in pre-integration testing!) then re-evaluate |
|
258 // the comment on the definition of DC_LIMIT. |
|
259 guarantee(false, "too many delayed constants"); |
|
260 return NULL; |
|
261 } |
|
262 |
|
263 void DelayedConstant::update_all() { |
|
264 for (int i = 0; i < DC_LIMIT; i++) { |
|
265 DelayedConstant* dcon = &delayed_constants[i]; |
|
266 if (dcon->value_fn != NULL && dcon->value == 0) { |
|
267 typedef int (*int_fn_t)(); |
|
268 typedef address (*address_fn_t)(); |
|
269 switch (dcon->type) { |
|
270 case T_INT: dcon->value = (intptr_t) ((int_fn_t) dcon->value_fn)(); break; |
|
271 case T_ADDRESS: dcon->value = (intptr_t) ((address_fn_t)dcon->value_fn)(); break; |
|
272 default: break; |
|
273 } |
|
274 } |
|
275 } |
|
276 } |
|
277 |
|
278 RegisterOrConstant AbstractAssembler::delayed_value(int(*value_fn)(), Register tmp, int offset) { |
|
279 intptr_t val = (intptr_t) (*value_fn)(); |
|
280 if (val != 0) return val + offset; |
|
281 return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset); |
|
282 } |
|
283 RegisterOrConstant AbstractAssembler::delayed_value(address(*value_fn)(), Register tmp, int offset) { |
|
284 intptr_t val = (intptr_t) (*value_fn)(); |
|
285 if (val != 0) return val + offset; |
|
286 return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset); |
|
287 } |
|
288 intptr_t* AbstractAssembler::delayed_value_addr(int(*value_fn)()) { |
|
289 DelayedConstant* dcon = DelayedConstant::add(T_INT, (DelayedConstant::value_fn_t) value_fn); |
|
290 return &dcon->value; |
|
291 } |
|
292 intptr_t* AbstractAssembler::delayed_value_addr(address(*value_fn)()) { |
|
293 DelayedConstant* dcon = DelayedConstant::add(T_ADDRESS, (DelayedConstant::value_fn_t) value_fn); |
|
294 return &dcon->value; |
|
295 } |
|
296 void AbstractAssembler::update_delayed_values() { |
|
297 DelayedConstant::update_all(); |
|
298 } |
|
299 |
|
300 void AbstractAssembler::block_comment(const char* comment) { |
221 void AbstractAssembler::block_comment(const char* comment) { |
301 if (sect() == CodeBuffer::SECT_INSTS) { |
222 if (sect() == CodeBuffer::SECT_INSTS) { |
302 code_section()->outer()->block_comment(offset(), comment); |
223 code_section()->outer()->block_comment(offset(), comment); |
303 } |
224 } |
304 } |
225 } |
311 } |
232 } |
312 |
233 |
313 bool MacroAssembler::uses_implicit_null_check(void* address) { |
234 bool MacroAssembler::uses_implicit_null_check(void* address) { |
314 // Exception handler checks the nmethod's implicit null checks table |
235 // Exception handler checks the nmethod's implicit null checks table |
315 // only when this method returns false. |
236 // only when this method returns false. |
316 intptr_t int_address = reinterpret_cast<intptr_t>(address); |
237 uintptr_t addr = reinterpret_cast<uintptr_t>(address); |
317 intptr_t cell_header_size = Universe::heap()->cell_header_size(); |
238 uintptr_t page_size = (uintptr_t)os::vm_page_size(); |
318 size_t region_size = os::vm_page_size() + cell_header_size; |
|
319 #ifdef _LP64 |
239 #ifdef _LP64 |
320 if (UseCompressedOops && CompressedOops::base() != NULL) { |
240 if (UseCompressedOops && CompressedOops::base() != NULL) { |
321 // A SEGV can legitimately happen in C2 code at address |
241 // A SEGV can legitimately happen in C2 code at address |
322 // (heap_base + offset) if Matcher::narrow_oop_use_complex_address |
242 // (heap_base + offset) if Matcher::narrow_oop_use_complex_address |
323 // is configured to allow narrow oops field loads to be implicitly |
243 // is configured to allow narrow oops field loads to be implicitly |
324 // null checked |
244 // null checked |
325 intptr_t start = ((intptr_t)CompressedOops::base()) - cell_header_size; |
245 uintptr_t start = (uintptr_t)CompressedOops::base(); |
326 intptr_t end = start + region_size; |
246 uintptr_t end = start + page_size; |
327 if (int_address >= start && int_address < end) { |
247 if (addr >= start && addr < end) { |
328 return true; |
248 return true; |
329 } |
249 } |
330 } |
250 } |
331 #endif |
251 #endif |
332 intptr_t start = -cell_header_size; |
252 return addr < page_size; |
333 intptr_t end = start + region_size; |
|
334 return int_address >= start && int_address < end; |
|
335 } |
253 } |
336 |
254 |
337 bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { |
255 bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { |
338 // The offset -1 is used (hardcoded) in a number of places in C1 and MacroAssembler |
256 // The offset -1 is used (hardcoded) in a number of places in C1 and MacroAssembler |
339 // to indicate an unknown offset. For example, TemplateTable::pop_and_check_object(Register r) |
257 // to indicate an unknown offset. For example, TemplateTable::pop_and_check_object(Register r) |
340 // calls MacroAssembler::null_check(Register reg, int offset = -1) which gets here |
258 // calls MacroAssembler::null_check(Register reg, int offset = -1) which gets here |
341 // with -1. Another example is GraphBuilder::access_field(...) which uses -1 as placeholder |
259 // with -1. Another example is GraphBuilder::access_field(...) which uses -1 as placeholder |
342 // for offsets to be patched in later. The -1 there means the offset is not yet known |
260 // for offsets to be patched in later. The -1 there means the offset is not yet known |
343 // and may lie outside of the zero-trapping page, and thus we need to ensure we're forcing |
261 // and may lie outside of the zero-trapping page, and thus we need to ensure we're forcing |
344 // an explicit null check for -1, even if it may otherwise be in the range |
262 // an explicit null check for -1. |
345 // [-cell_header_size, os::vm_page_size). |
263 |
346 // TODO: Find and replace all relevant uses of -1 with a reasonably named constant. |
264 // Check if offset is outside of [0, os::vm_page_size()] |
347 if (offset == -1) return true; |
265 return offset < 0 || offset >= os::vm_page_size(); |
348 |
266 } |
349 // Check if offset is outside of [-cell_header_size, os::vm_page_size) |
|
350 return offset < -Universe::heap()->cell_header_size() || |
|
351 offset >= os::vm_page_size(); |
|
352 } |
|