1 | // Copyright 2018 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "src/reloc-info.h" |
6 | |
7 | #include "src/assembler-inl.h" |
8 | #include "src/code-reference.h" |
9 | #include "src/deoptimize-reason.h" |
10 | #include "src/deoptimizer.h" |
11 | #include "src/heap/heap-write-barrier-inl.h" |
12 | #include "src/objects/code-inl.h" |
13 | #include "src/snapshot/snapshot.h" |
14 | |
15 | namespace v8 { |
16 | namespace internal { |
17 | |
18 | const char* const RelocInfo:: = "DEOPTIMIZATION PADDING" ; |
19 | |
20 | // ----------------------------------------------------------------------------- |
21 | // Implementation of RelocInfoWriter and RelocIterator |
22 | // |
23 | // Relocation information is written backwards in memory, from high addresses |
24 | // towards low addresses, byte by byte. Therefore, in the encodings listed |
25 | // below, the first byte listed it at the highest address, and successive |
26 | // bytes in the record are at progressively lower addresses. |
27 | // |
28 | // Encoding |
29 | // |
30 | // The most common modes are given single-byte encodings. Also, it is |
31 | // easy to identify the type of reloc info and skip unwanted modes in |
32 | // an iteration. |
33 | // |
34 | // The encoding relies on the fact that there are fewer than 14 |
35 | // different relocation modes using standard non-compact encoding. |
36 | // |
37 | // The first byte of a relocation record has a tag in its low 2 bits: |
38 | // Here are the record schemes, depending on the low tag and optional higher |
39 | // tags. |
40 | // |
41 | // Low tag: |
42 | // 00: embedded_object: [6-bit pc delta] 00 |
43 | // |
44 | // 01: code_target: [6-bit pc delta] 01 |
45 | // |
46 | // 10: wasm_stub_call: [6-bit pc delta] 10 |
47 | // |
48 | // 11: long_record [6 bit reloc mode] 11 |
49 | // followed by pc delta |
50 | // followed by optional data depending on type. |
51 | // |
52 | // If a pc delta exceeds 6 bits, it is split into a remainder that fits into |
53 | // 6 bits and a part that does not. The latter is encoded as a long record |
54 | // with PC_JUMP as pseudo reloc info mode. The former is encoded as part of |
55 | // the following record in the usual way. The long pc jump record has variable |
56 | // length: |
57 | // pc-jump: [PC_JUMP] 11 |
58 | // [7 bits data] 0 |
59 | // ... |
60 | // [7 bits data] 1 |
61 | // (Bits 6..31 of pc delta, with leading zeroes |
62 | // dropped, and last non-zero chunk tagged with 1.) |
63 | |
64 | const int kTagBits = 2; |
65 | const int kTagMask = (1 << kTagBits) - 1; |
66 | const int kLongTagBits = 6; |
67 | |
68 | const int kEmbeddedObjectTag = 0; |
69 | const int kCodeTargetTag = 1; |
70 | const int kWasmStubCallTag = 2; |
71 | const int kDefaultTag = 3; |
72 | |
73 | const int kSmallPCDeltaBits = kBitsPerByte - kTagBits; |
74 | const int kSmallPCDeltaMask = (1 << kSmallPCDeltaBits) - 1; |
75 | const int RelocInfo::kMaxSmallPCDelta = kSmallPCDeltaMask; |
76 | |
77 | const int kChunkBits = 7; |
78 | const int kChunkMask = (1 << kChunkBits) - 1; |
79 | const int kLastChunkTagBits = 1; |
80 | const int kLastChunkTagMask = 1; |
81 | const int kLastChunkTag = 1; |
82 | |
83 | uint32_t RelocInfoWriter::WriteLongPCJump(uint32_t pc_delta) { |
84 | // Return if the pc_delta can fit in kSmallPCDeltaBits bits. |
85 | // Otherwise write a variable length PC jump for the bits that do |
86 | // not fit in the kSmallPCDeltaBits bits. |
87 | if (is_uintn(pc_delta, kSmallPCDeltaBits)) return pc_delta; |
88 | WriteMode(RelocInfo::PC_JUMP); |
89 | uint32_t pc_jump = pc_delta >> kSmallPCDeltaBits; |
90 | DCHECK_GT(pc_jump, 0); |
91 | // Write kChunkBits size chunks of the pc_jump. |
92 | for (; pc_jump > 0; pc_jump = pc_jump >> kChunkBits) { |
93 | byte b = pc_jump & kChunkMask; |
94 | *--pos_ = b << kLastChunkTagBits; |
95 | } |
96 | // Tag the last chunk so it can be identified. |
97 | *pos_ = *pos_ | kLastChunkTag; |
98 | // Return the remaining kSmallPCDeltaBits of the pc_delta. |
99 | return pc_delta & kSmallPCDeltaMask; |
100 | } |
101 | |
102 | void RelocInfoWriter::WriteShortTaggedPC(uint32_t pc_delta, int tag) { |
103 | // Write a byte of tagged pc-delta, possibly preceded by an explicit pc-jump. |
104 | pc_delta = WriteLongPCJump(pc_delta); |
105 | *--pos_ = pc_delta << kTagBits | tag; |
106 | } |
107 | |
108 | void RelocInfoWriter::WriteShortData(intptr_t data_delta) { |
109 | *--pos_ = static_cast<byte>(data_delta); |
110 | } |
111 | |
112 | void RelocInfoWriter::WriteMode(RelocInfo::Mode rmode) { |
113 | STATIC_ASSERT(RelocInfo::NUMBER_OF_MODES <= (1 << kLongTagBits)); |
114 | *--pos_ = static_cast<int>((rmode << kTagBits) | kDefaultTag); |
115 | } |
116 | |
117 | void RelocInfoWriter::WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode) { |
118 | // Write two-byte tagged pc-delta, possibly preceded by var. length pc-jump. |
119 | pc_delta = WriteLongPCJump(pc_delta); |
120 | WriteMode(rmode); |
121 | *--pos_ = pc_delta; |
122 | } |
123 | |
124 | void RelocInfoWriter::WriteIntData(int number) { |
125 | for (int i = 0; i < kIntSize; i++) { |
126 | *--pos_ = static_cast<byte>(number); |
127 | // Signed right shift is arithmetic shift. Tested in test-utils.cc. |
128 | number = number >> kBitsPerByte; |
129 | } |
130 | } |
131 | |
132 | void RelocInfoWriter::WriteData(intptr_t data_delta) { |
133 | for (int i = 0; i < kIntptrSize; i++) { |
134 | *--pos_ = static_cast<byte>(data_delta); |
135 | // Signed right shift is arithmetic shift. Tested in test-utils.cc. |
136 | data_delta = data_delta >> kBitsPerByte; |
137 | } |
138 | } |
139 | |
140 | void RelocInfoWriter::Write(const RelocInfo* rinfo) { |
141 | RelocInfo::Mode rmode = rinfo->rmode(); |
142 | #ifdef DEBUG |
143 | byte* begin_pos = pos_; |
144 | #endif |
145 | DCHECK(rinfo->rmode() < RelocInfo::NUMBER_OF_MODES); |
146 | DCHECK_GE(rinfo->pc() - reinterpret_cast<Address>(last_pc_), 0); |
147 | // Use unsigned delta-encoding for pc. |
148 | uint32_t pc_delta = |
149 | static_cast<uint32_t>(rinfo->pc() - reinterpret_cast<Address>(last_pc_)); |
150 | |
151 | // The two most common modes are given small tags, and usually fit in a byte. |
152 | if (rmode == RelocInfo::EMBEDDED_OBJECT) { |
153 | WriteShortTaggedPC(pc_delta, kEmbeddedObjectTag); |
154 | } else if (rmode == RelocInfo::CODE_TARGET) { |
155 | WriteShortTaggedPC(pc_delta, kCodeTargetTag); |
156 | DCHECK_LE(begin_pos - pos_, RelocInfo::kMaxCallSize); |
157 | } else if (rmode == RelocInfo::WASM_STUB_CALL) { |
158 | WriteShortTaggedPC(pc_delta, kWasmStubCallTag); |
159 | } else { |
160 | WriteModeAndPC(pc_delta, rmode); |
161 | if (RelocInfo::IsDeoptReason(rmode)) { |
162 | DCHECK_LT(rinfo->data(), 1 << kBitsPerByte); |
163 | WriteShortData(rinfo->data()); |
164 | } else if (RelocInfo::IsConstPool(rmode) || |
165 | RelocInfo::IsVeneerPool(rmode) || RelocInfo::IsDeoptId(rmode) || |
166 | RelocInfo::IsDeoptPosition(rmode)) { |
167 | WriteIntData(static_cast<int>(rinfo->data())); |
168 | } |
169 | } |
170 | last_pc_ = reinterpret_cast<byte*>(rinfo->pc()); |
171 | #ifdef DEBUG |
172 | DCHECK_LE(begin_pos - pos_, kMaxSize); |
173 | #endif |
174 | } |
175 | |
176 | inline int RelocIterator::AdvanceGetTag() { return *--pos_ & kTagMask; } |
177 | |
178 | inline RelocInfo::Mode RelocIterator::GetMode() { |
179 | return static_cast<RelocInfo::Mode>((*pos_ >> kTagBits) & |
180 | ((1 << kLongTagBits) - 1)); |
181 | } |
182 | |
183 | inline void RelocIterator::ReadShortTaggedPC() { |
184 | rinfo_.pc_ += *pos_ >> kTagBits; |
185 | } |
186 | |
187 | inline void RelocIterator::AdvanceReadPC() { rinfo_.pc_ += *--pos_; } |
188 | |
189 | void RelocIterator::AdvanceReadInt() { |
190 | int x = 0; |
191 | for (int i = 0; i < kIntSize; i++) { |
192 | x |= static_cast<int>(*--pos_) << i * kBitsPerByte; |
193 | } |
194 | rinfo_.data_ = x; |
195 | } |
196 | |
197 | void RelocIterator::AdvanceReadData() { |
198 | intptr_t x = 0; |
199 | for (int i = 0; i < kIntptrSize; i++) { |
200 | x |= static_cast<intptr_t>(*--pos_) << i * kBitsPerByte; |
201 | } |
202 | rinfo_.data_ = x; |
203 | } |
204 | |
205 | void RelocIterator::AdvanceReadLongPCJump() { |
206 | // Read the 32-kSmallPCDeltaBits most significant bits of the |
207 | // pc jump in kChunkBits bit chunks and shift them into place. |
208 | // Stop when the last chunk is encountered. |
209 | uint32_t pc_jump = 0; |
210 | for (int i = 0; i < kIntSize; i++) { |
211 | byte pc_jump_part = *--pos_; |
212 | pc_jump |= (pc_jump_part >> kLastChunkTagBits) << i * kChunkBits; |
213 | if ((pc_jump_part & kLastChunkTagMask) == 1) break; |
214 | } |
215 | // The least significant kSmallPCDeltaBits bits will be added |
216 | // later. |
217 | rinfo_.pc_ += pc_jump << kSmallPCDeltaBits; |
218 | } |
219 | |
220 | inline void RelocIterator::ReadShortData() { |
221 | uint8_t unsigned_b = *pos_; |
222 | rinfo_.data_ = unsigned_b; |
223 | } |
224 | |
225 | void RelocIterator::next() { |
226 | DCHECK(!done()); |
227 | // Basically, do the opposite of RelocInfoWriter::Write. |
228 | // Reading of data is as far as possible avoided for unwanted modes, |
229 | // but we must always update the pc. |
230 | // |
231 | // We exit this loop by returning when we find a mode we want. |
232 | while (pos_ > end_) { |
233 | int tag = AdvanceGetTag(); |
234 | if (tag == kEmbeddedObjectTag) { |
235 | ReadShortTaggedPC(); |
236 | if (SetMode(RelocInfo::EMBEDDED_OBJECT)) return; |
237 | } else if (tag == kCodeTargetTag) { |
238 | ReadShortTaggedPC(); |
239 | if (SetMode(RelocInfo::CODE_TARGET)) return; |
240 | } else if (tag == kWasmStubCallTag) { |
241 | ReadShortTaggedPC(); |
242 | if (SetMode(RelocInfo::WASM_STUB_CALL)) return; |
243 | } else { |
244 | DCHECK_EQ(tag, kDefaultTag); |
245 | RelocInfo::Mode rmode = GetMode(); |
246 | if (rmode == RelocInfo::PC_JUMP) { |
247 | AdvanceReadLongPCJump(); |
248 | } else { |
249 | AdvanceReadPC(); |
250 | if (RelocInfo::IsDeoptReason(rmode)) { |
251 | Advance(); |
252 | if (SetMode(rmode)) { |
253 | ReadShortData(); |
254 | return; |
255 | } |
256 | } else if (RelocInfo::IsConstPool(rmode) || |
257 | RelocInfo::IsVeneerPool(rmode) || |
258 | RelocInfo::IsDeoptId(rmode) || |
259 | RelocInfo::IsDeoptPosition(rmode)) { |
260 | if (SetMode(rmode)) { |
261 | AdvanceReadInt(); |
262 | return; |
263 | } |
264 | Advance(kIntSize); |
265 | } else if (SetMode(static_cast<RelocInfo::Mode>(rmode))) { |
266 | return; |
267 | } |
268 | } |
269 | } |
270 | } |
271 | done_ = true; |
272 | } |
273 | |
274 | RelocIterator::RelocIterator(Code code, int mode_mask) |
275 | : RelocIterator(code, code->unchecked_relocation_info(), mode_mask) {} |
276 | |
277 | RelocIterator::RelocIterator(Code code, ByteArray relocation_info, |
278 | int mode_mask) |
279 | : RelocIterator(code, code->raw_instruction_start(), code->constant_pool(), |
280 | relocation_info->GetDataEndAddress(), |
281 | relocation_info->GetDataStartAddress(), mode_mask) {} |
282 | |
283 | RelocIterator::RelocIterator(const CodeReference code_reference, int mode_mask) |
284 | : RelocIterator(Code(), code_reference.instruction_start(), |
285 | code_reference.constant_pool(), |
286 | code_reference.relocation_end(), |
287 | code_reference.relocation_start(), mode_mask) {} |
288 | |
289 | RelocIterator::RelocIterator(EmbeddedData* embedded_data, Code code, |
290 | int mode_mask) |
291 | : RelocIterator( |
292 | code, embedded_data->InstructionStartOfBuiltin(code->builtin_index()), |
293 | code->constant_pool(), |
294 | code->relocation_start() + code->relocation_size(), |
295 | code->relocation_start(), mode_mask) {} |
296 | |
297 | RelocIterator::RelocIterator(const CodeDesc& desc, int mode_mask) |
298 | : RelocIterator(Code(), reinterpret_cast<Address>(desc.buffer), 0, |
299 | desc.buffer + desc.buffer_size, |
300 | desc.buffer + desc.buffer_size - desc.reloc_size, |
301 | mode_mask) {} |
302 | |
303 | RelocIterator::RelocIterator(Vector<byte> instructions, |
304 | Vector<const byte> reloc_info, Address const_pool, |
305 | int mode_mask) |
306 | : RelocIterator(Code(), reinterpret_cast<Address>(instructions.start()), |
307 | const_pool, reloc_info.start() + reloc_info.size(), |
308 | reloc_info.start(), mode_mask) {} |
309 | |
310 | RelocIterator::RelocIterator(Code host, Address pc, Address constant_pool, |
311 | const byte* pos, const byte* end, int mode_mask) |
312 | : pos_(pos), end_(end), mode_mask_(mode_mask) { |
313 | // Relocation info is read backwards. |
314 | DCHECK_GE(pos_, end_); |
315 | rinfo_.host_ = host; |
316 | rinfo_.pc_ = pc; |
317 | rinfo_.constant_pool_ = constant_pool; |
318 | if (mode_mask_ == 0) pos_ = end_; |
319 | next(); |
320 | } |
321 | |
322 | // ----------------------------------------------------------------------------- |
323 | // Implementation of RelocInfo |
324 | |
325 | // static |
326 | bool RelocInfo::OffHeapTargetIsCodedSpecially() { |
327 | #if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_ARM64) || \ |
328 | defined(V8_TARGET_ARCH_X64) |
329 | return false; |
330 | #elif defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_MIPS) || \ |
331 | defined(V8_TARGET_ARCH_MIPS64) || defined(V8_TARGET_ARCH_PPC) || \ |
332 | defined(V8_TARGET_ARCH_S390) |
333 | return true; |
334 | #endif |
335 | } |
336 | |
337 | Address RelocInfo::wasm_call_address() const { |
338 | DCHECK_EQ(rmode_, WASM_CALL); |
339 | return Assembler::target_address_at(pc_, constant_pool_); |
340 | } |
341 | |
342 | void RelocInfo::set_wasm_call_address(Address address, |
343 | ICacheFlushMode icache_flush_mode) { |
344 | DCHECK_EQ(rmode_, WASM_CALL); |
345 | Assembler::set_target_address_at(pc_, constant_pool_, address, |
346 | icache_flush_mode); |
347 | } |
348 | |
349 | Address RelocInfo::wasm_stub_call_address() const { |
350 | DCHECK_EQ(rmode_, WASM_STUB_CALL); |
351 | return Assembler::target_address_at(pc_, constant_pool_); |
352 | } |
353 | |
354 | void RelocInfo::set_wasm_stub_call_address(Address address, |
355 | ICacheFlushMode icache_flush_mode) { |
356 | DCHECK_EQ(rmode_, WASM_STUB_CALL); |
357 | Assembler::set_target_address_at(pc_, constant_pool_, address, |
358 | icache_flush_mode); |
359 | } |
360 | |
361 | void RelocInfo::set_target_address(Address target, |
362 | WriteBarrierMode write_barrier_mode, |
363 | ICacheFlushMode icache_flush_mode) { |
364 | DCHECK(IsCodeTargetMode(rmode_) || IsRuntimeEntry(rmode_) || |
365 | IsWasmCall(rmode_)); |
366 | Assembler::set_target_address_at(pc_, constant_pool_, target, |
367 | icache_flush_mode); |
368 | if (write_barrier_mode == UPDATE_WRITE_BARRIER && !host().is_null() && |
369 | IsCodeTargetMode(rmode_)) { |
370 | Code target_code = Code::GetCodeFromTargetAddress(target); |
371 | MarkingBarrierForCode(host(), this, target_code); |
372 | } |
373 | } |
374 | |
375 | bool RelocInfo::HasTargetAddressAddress() const { |
376 | // TODO(jgruber): Investigate whether WASM_CALL is still appropriate on |
377 | // non-intel platforms now that wasm code is no longer on the heap. |
378 | #if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64) |
379 | static constexpr int kTargetAddressAddressModeMask = |
380 | ModeMask(CODE_TARGET) | ModeMask(EMBEDDED_OBJECT) | |
381 | ModeMask(EXTERNAL_REFERENCE) | ModeMask(OFF_HEAP_TARGET) | |
382 | ModeMask(RUNTIME_ENTRY) | ModeMask(WASM_CALL) | ModeMask(WASM_STUB_CALL); |
383 | #else |
384 | static constexpr int kTargetAddressAddressModeMask = |
385 | ModeMask(CODE_TARGET) | ModeMask(RELATIVE_CODE_TARGET) | |
386 | ModeMask(EMBEDDED_OBJECT) | ModeMask(EXTERNAL_REFERENCE) | |
387 | ModeMask(OFF_HEAP_TARGET) | ModeMask(RUNTIME_ENTRY) | ModeMask(WASM_CALL); |
388 | #endif |
389 | return (ModeMask(rmode_) & kTargetAddressAddressModeMask) != 0; |
390 | } |
391 | |
392 | bool RelocInfo::RequiresRelocationAfterCodegen(const CodeDesc& desc) { |
393 | RelocIterator it(desc, RelocInfo::PostCodegenRelocationMask()); |
394 | return !it.done(); |
395 | } |
396 | |
397 | bool RelocInfo::RequiresRelocation(Code code) { |
398 | RelocIterator it(code, RelocInfo::kApplyMask); |
399 | return !it.done(); |
400 | } |
401 | |
402 | #ifdef ENABLE_DISASSEMBLER |
403 | const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) { |
404 | switch (rmode) { |
405 | case NONE: |
406 | return "no reloc" ; |
407 | case EMBEDDED_OBJECT: |
408 | return "embedded object" ; |
409 | case CODE_TARGET: |
410 | return "code target" ; |
411 | case RELATIVE_CODE_TARGET: |
412 | return "relative code target" ; |
413 | case RUNTIME_ENTRY: |
414 | return "runtime entry" ; |
415 | case EXTERNAL_REFERENCE: |
416 | return "external reference" ; |
417 | case INTERNAL_REFERENCE: |
418 | return "internal reference" ; |
419 | case INTERNAL_REFERENCE_ENCODED: |
420 | return "encoded internal reference" ; |
421 | case OFF_HEAP_TARGET: |
422 | return "off heap target" ; |
423 | case DEOPT_SCRIPT_OFFSET: |
424 | return "deopt script offset" ; |
425 | case DEOPT_INLINING_ID: |
426 | return "deopt inlining id" ; |
427 | case DEOPT_REASON: |
428 | return "deopt reason" ; |
429 | case DEOPT_ID: |
430 | return "deopt index" ; |
431 | case CONST_POOL: |
432 | return "constant pool" ; |
433 | case VENEER_POOL: |
434 | return "veneer pool" ; |
435 | case WASM_CALL: |
436 | return "internal wasm call" ; |
437 | case WASM_STUB_CALL: |
438 | return "wasm stub call" ; |
439 | case NUMBER_OF_MODES: |
440 | case PC_JUMP: |
441 | UNREACHABLE(); |
442 | } |
443 | return "unknown relocation type" ; |
444 | } |
445 | |
446 | void RelocInfo::Print(Isolate* isolate, std::ostream& os) { // NOLINT |
447 | os << reinterpret_cast<const void*>(pc_) << " " << RelocModeName(rmode_); |
448 | if (rmode_ == DEOPT_SCRIPT_OFFSET || rmode_ == DEOPT_INLINING_ID) { |
449 | os << " (" << data() << ")" ; |
450 | } else if (rmode_ == DEOPT_REASON) { |
451 | os << " (" |
452 | << DeoptimizeReasonToString(static_cast<DeoptimizeReason>(data_)) << ")" ; |
453 | } else if (rmode_ == EMBEDDED_OBJECT) { |
454 | os << " (" << Brief(target_object()) << ")" ; |
455 | } else if (rmode_ == EXTERNAL_REFERENCE) { |
456 | if (isolate) { |
457 | ExternalReferenceEncoder ref_encoder(isolate); |
458 | os << " (" |
459 | << ref_encoder.NameOfAddress(isolate, target_external_reference()) |
460 | << ") " ; |
461 | } |
462 | os << " (" << reinterpret_cast<const void*>(target_external_reference()) |
463 | << ")" ; |
464 | } else if (IsCodeTargetMode(rmode_)) { |
465 | const Address code_target = target_address(); |
466 | Code code = Code::GetCodeFromTargetAddress(code_target); |
467 | DCHECK(code->IsCode()); |
468 | os << " (" << Code::Kind2String(code->kind()); |
469 | if (Builtins::IsBuiltin(code)) { |
470 | os << " " << Builtins::name(code->builtin_index()); |
471 | } |
472 | os << ") (" << reinterpret_cast<const void*>(target_address()) << ")" ; |
473 | } else if (IsRuntimeEntry(rmode_) && isolate->deoptimizer_data() != nullptr) { |
474 | // Deoptimization bailouts are stored as runtime entries. |
475 | DeoptimizeKind type; |
476 | if (Deoptimizer::IsDeoptimizationEntry(isolate, target_address(), &type)) { |
477 | os << " (" << Deoptimizer::MessageFor(type) |
478 | << " deoptimization bailout)" ; |
479 | } |
480 | } else if (IsConstPool(rmode_)) { |
481 | os << " (size " << static_cast<int>(data_) << ")" ; |
482 | } |
483 | |
484 | os << "\n" ; |
485 | } |
486 | #endif // ENABLE_DISASSEMBLER |
487 | |
488 | #ifdef VERIFY_HEAP |
489 | void RelocInfo::Verify(Isolate* isolate) { |
490 | switch (rmode_) { |
491 | case EMBEDDED_OBJECT: |
492 | Object::VerifyPointer(isolate, target_object()); |
493 | break; |
494 | case CODE_TARGET: |
495 | case RELATIVE_CODE_TARGET: { |
496 | // convert inline target address to code object |
497 | Address addr = target_address(); |
498 | CHECK_NE(addr, kNullAddress); |
499 | // Check that we can find the right code object. |
500 | Code code = Code::GetCodeFromTargetAddress(addr); |
501 | Object found = isolate->FindCodeObject(addr); |
502 | CHECK(found->IsCode()); |
503 | CHECK(code->address() == HeapObject::cast(found)->address()); |
504 | break; |
505 | } |
506 | case INTERNAL_REFERENCE: |
507 | case INTERNAL_REFERENCE_ENCODED: { |
508 | Address target = target_internal_reference(); |
509 | Address pc = target_internal_reference_address(); |
510 | Code code = Code::cast(isolate->FindCodeObject(pc)); |
511 | CHECK(target >= code->InstructionStart()); |
512 | CHECK(target <= code->InstructionEnd()); |
513 | break; |
514 | } |
515 | case OFF_HEAP_TARGET: { |
516 | Address addr = target_off_heap_target(); |
517 | CHECK_NE(addr, kNullAddress); |
518 | CHECK(!InstructionStream::TryLookupCode(isolate, addr).is_null()); |
519 | break; |
520 | } |
521 | case RUNTIME_ENTRY: |
522 | case EXTERNAL_REFERENCE: |
523 | case DEOPT_SCRIPT_OFFSET: |
524 | case DEOPT_INLINING_ID: |
525 | case DEOPT_REASON: |
526 | case DEOPT_ID: |
527 | case CONST_POOL: |
528 | case VENEER_POOL: |
529 | case WASM_CALL: |
530 | case WASM_STUB_CALL: |
531 | case NONE: |
532 | break; |
533 | case NUMBER_OF_MODES: |
534 | case PC_JUMP: |
535 | UNREACHABLE(); |
536 | break; |
537 | } |
538 | } |
539 | #endif // VERIFY_HEAP |
540 | |
541 | } // namespace internal |
542 | } // namespace v8 |
543 | |