1// Copyright 2017 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#ifndef V8_OBJECTS_CODE_INL_H_ 6#define V8_OBJECTS_CODE_INL_H_ 7 8#include "src/base/memory.h" 9#include "src/baseline/bytecode-offset-iterator.h" 10#include "src/codegen/code-desc.h" 11#include "src/common/assert-scope.h" 12#include "src/common/globals.h" 13#include "src/execution/isolate.h" 14#include "src/heap/heap-inl.h" 15#include "src/interpreter/bytecode-register.h" 16#include "src/objects/code.h" 17#include "src/objects/dictionary.h" 18#include "src/objects/instance-type-inl.h" 19#include "src/objects/map-inl.h" 20#include "src/objects/maybe-object-inl.h" 21#include "src/objects/oddball.h" 22#include "src/objects/shared-function-info-inl.h" 23#include "src/objects/smi-inl.h" 24#include "src/utils/utils.h" 25 26// Has to be the last include (doesn't have include guards): 27#include "src/objects/object-macros.h" 28 29namespace v8 { 30namespace internal { 31 32#include "torque-generated/src/objects/code-tq-inl.inc" 33 34OBJECT_CONSTRUCTORS_IMPL(DeoptimizationData, FixedArray) 35TQ_OBJECT_CONSTRUCTORS_IMPL(BytecodeArray) 36OBJECT_CONSTRUCTORS_IMPL(AbstractCode, HeapObject) 37OBJECT_CONSTRUCTORS_IMPL(DependentCode, WeakArrayList) 38OBJECT_CONSTRUCTORS_IMPL(CodeDataContainer, HeapObject) 39NEVER_READ_ONLY_SPACE_IMPL(CodeDataContainer) 40 41NEVER_READ_ONLY_SPACE_IMPL(AbstractCode) 42 43CAST_ACCESSOR(AbstractCode) 44CAST_ACCESSOR(Code) 45CAST_ACCESSOR(CodeDataContainer) 46CAST_ACCESSOR(DependentCode) 47CAST_ACCESSOR(DeoptimizationData) 48CAST_ACCESSOR(DeoptimizationLiteralArray) 49 50int AbstractCode::raw_instruction_size() { 51 if (IsCode()) { 52 return GetCode().raw_instruction_size(); 53 } else { 54 return GetBytecodeArray().length(); 55 } 56} 57 58int AbstractCode::InstructionSize() { 59 if (IsCode()) { 60 return GetCode().InstructionSize(); 61 } else { 62 return GetBytecodeArray().length(); 63 } 64} 65 66ByteArray AbstractCode::SourcePositionTableInternal() { 67 if (IsCode()) { 68 DCHECK_NE(GetCode().kind(), CodeKind::BASELINE); 69 return GetCode().source_position_table(); 70 } else { 71 return GetBytecodeArray().SourcePositionTable(); 72 } 73} 74 75ByteArray AbstractCode::SourcePositionTable(SharedFunctionInfo sfi) { 76 if (IsCode()) { 77 return GetCode().SourcePositionTable(sfi); 78 } else { 79 return GetBytecodeArray().SourcePositionTable(); 80 } 81} 82 83int AbstractCode::SizeIncludingMetadata() { 84 if (IsCode()) { 85 return GetCode().SizeIncludingMetadata(); 86 } else { 87 return GetBytecodeArray().SizeIncludingMetadata(); 88 } 89} 90 91Address AbstractCode::raw_instruction_start() { 92 if (IsCode()) { 93 return GetCode().raw_instruction_start(); 94 } else { 95 return GetBytecodeArray().GetFirstBytecodeAddress(); 96 } 97} 98 99Address AbstractCode::InstructionStart() { 100 if (IsCode()) { 101 return GetCode().InstructionStart(); 102 } else { 103 return GetBytecodeArray().GetFirstBytecodeAddress(); 104 } 105} 106 107Address AbstractCode::raw_instruction_end() { 108 if (IsCode()) { 109 return GetCode().raw_instruction_end(); 110 } else { 111 return GetBytecodeArray().GetFirstBytecodeAddress() + 112 GetBytecodeArray().length(); 113 } 114} 115 116Address AbstractCode::InstructionEnd() { 117 if (IsCode()) { 118 return GetCode().InstructionEnd(); 119 } else { 120 return GetBytecodeArray().GetFirstBytecodeAddress() + 121 GetBytecodeArray().length(); 122 } 123} 124 125bool AbstractCode::contains(Isolate* isolate, Address inner_pointer) { 126 PtrComprCageBase cage_base(isolate); 127 if (IsCode(cage_base)) { 128 return GetCode().contains(isolate, inner_pointer); 129 } else { 130 return (address() <= inner_pointer) && 131 (inner_pointer <= address() + Size(cage_base)); 132 } 133} 134 135CodeKind AbstractCode::kind() { 136 return IsCode() ? GetCode().kind() : CodeKind::INTERPRETED_FUNCTION; 137} 138 139Code AbstractCode::GetCode() { return Code::cast(*this); } 140 141BytecodeArray AbstractCode::GetBytecodeArray() { 142 return BytecodeArray::cast(*this); 143} 144 145OBJECT_CONSTRUCTORS_IMPL(Code, HeapObject) 146NEVER_READ_ONLY_SPACE_IMPL(Code) 147 148INT_ACCESSORS(Code, raw_instruction_size, kInstructionSizeOffset) 149INT_ACCESSORS(Code, raw_metadata_size, kMetadataSizeOffset) 150INT_ACCESSORS(Code, handler_table_offset, kHandlerTableOffsetOffset) 151INT_ACCESSORS(Code, code_comments_offset, kCodeCommentsOffsetOffset) 152INT32_ACCESSORS(Code, unwinding_info_offset, kUnwindingInfoOffsetOffset) 153 154// Same as ACCESSORS_CHECKED2 macro but with Code as a host and using 155// main_cage_base() for computing the base. 156#define CODE_ACCESSORS_CHECKED2(name, type, offset, get_condition, \ 157 set_condition) \ 158 type Code::name() const { \ 159 PtrComprCageBase cage_base = main_cage_base(); \ 160 return Code::name(cage_base); \ 161 } \ 162 type Code::name(PtrComprCageBase cage_base) const { \ 163 type value = TaggedField<type, offset>::load(cage_base, *this); \ 164 DCHECK(get_condition); \ 165 return value; \ 166 } \ 167 void Code::set_##name(type value, WriteBarrierMode mode) { \ 168 DCHECK(set_condition); \ 169 TaggedField<type, offset>::store(*this, value); \ 170 CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); \ 171 } 172 173// Same as RELEASE_ACQUIRE_ACCESSORS_CHECKED2 macro but with Code as a host and 174// using main_cage_base(kRelaxedLoad) for computing the base. 175#define RELEASE_ACQUIRE_CODE_ACCESSORS_CHECKED2(name, type, offset, \ 176 get_condition, set_condition) \ 177 type Code::name(AcquireLoadTag tag) const { \ 178 PtrComprCageBase cage_base = main_cage_base(kRelaxedLoad); \ 179 return Code::name(cage_base, tag); \ 180 } \ 181 type Code::name(PtrComprCageBase cage_base, AcquireLoadTag) const { \ 182 type value = TaggedField<type, offset>::Acquire_Load(cage_base, *this); \ 183 DCHECK(get_condition); \ 184 return value; \ 185 } \ 186 void Code::set_##name(type value, ReleaseStoreTag, WriteBarrierMode mode) { \ 187 DCHECK(set_condition); \ 188 TaggedField<type, offset>::Release_Store(*this, value); \ 189 CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); \ 190 } 191 192#define CODE_ACCESSORS(name, type, offset) \ 193 CODE_ACCESSORS_CHECKED2(name, type, offset, true, true) 194 195#define RELEASE_ACQUIRE_CODE_ACCESSORS(name, type, offset) \ 196 RELEASE_ACQUIRE_CODE_ACCESSORS_CHECKED2(name, type, offset, \ 197 !ObjectInYoungGeneration(value), \ 198 !ObjectInYoungGeneration(value)) 199 200CODE_ACCESSORS(relocation_info, ByteArray, kRelocationInfoOffset) 201 202CODE_ACCESSORS_CHECKED2(deoptimization_data, FixedArray, 203 kDeoptimizationDataOrInterpreterDataOffset, 204 kind() != CodeKind::BASELINE, 205 kind() != CodeKind::BASELINE && 206 !ObjectInYoungGeneration(value)) 207CODE_ACCESSORS_CHECKED2(bytecode_or_interpreter_data, HeapObject, 208 kDeoptimizationDataOrInterpreterDataOffset, 209 kind() == CodeKind::BASELINE, 210 kind() == CodeKind::BASELINE && 211 !ObjectInYoungGeneration(value)) 212 213CODE_ACCESSORS_CHECKED2(source_position_table, ByteArray, kPositionTableOffset, 214 kind() != CodeKind::BASELINE, 215 kind() != CodeKind::BASELINE && 216 !ObjectInYoungGeneration(value)) 217CODE_ACCESSORS_CHECKED2(bytecode_offset_table, ByteArray, kPositionTableOffset, 218 kind() == CodeKind::BASELINE, 219 kind() == CodeKind::BASELINE && 220 !ObjectInYoungGeneration(value)) 221 222// Concurrent marker needs to access kind specific flags in code data container. 223RELEASE_ACQUIRE_CODE_ACCESSORS(code_data_container, CodeDataContainer, 224 kCodeDataContainerOffset) 225#undef CODE_ACCESSORS 226#undef CODE_ACCESSORS_CHECKED2 227#undef RELEASE_ACQUIRE_CODE_ACCESSORS 228#undef RELEASE_ACQUIRE_CODE_ACCESSORS_CHECKED2 229 230PtrComprCageBase Code::main_cage_base() const { 231#ifdef V8_EXTERNAL_CODE_SPACE 232 Address cage_base_hi = ReadField<Tagged_t>(kMainCageBaseUpper32BitsOffset); 233 return PtrComprCageBase(cage_base_hi << 32); 234#else 235 return GetPtrComprCageBase(*this); 236#endif 237} 238 239PtrComprCageBase Code::main_cage_base(RelaxedLoadTag) const { 240#ifdef V8_EXTERNAL_CODE_SPACE 241 Address cage_base_hi = 242 Relaxed_ReadField<Tagged_t>(kMainCageBaseUpper32BitsOffset); 243 return PtrComprCageBase(cage_base_hi << 32); 244#else 245 return GetPtrComprCageBase(*this); 246#endif 247} 248 249void Code::set_main_cage_base(Address cage_base, RelaxedStoreTag) { 250#ifdef V8_EXTERNAL_CODE_SPACE 251 Tagged_t cage_base_hi = static_cast<Tagged_t>(cage_base >> 32); 252 Relaxed_WriteField<Tagged_t>(kMainCageBaseUpper32BitsOffset, cage_base_hi); 253#else 254 UNREACHABLE(); 255#endif 256} 257 258CodeDataContainer Code::GCSafeCodeDataContainer(AcquireLoadTag) const { 259 PtrComprCageBase cage_base = main_cage_base(kRelaxedLoad); 260 HeapObject object = 261 TaggedField<HeapObject, kCodeDataContainerOffset>::Acquire_Load(cage_base, 262 *this); 263 DCHECK(!ObjectInYoungGeneration(object)); 264 CodeDataContainer code_data_container = 265 ForwardingAddress(CodeDataContainer::unchecked_cast(object)); 266 return code_data_container; 267} 268 269// Helper functions for converting Code objects to CodeDataContainer and back 270// when V8_EXTERNAL_CODE_SPACE is enabled. 271inline CodeT ToCodeT(Code code) { 272#ifdef V8_EXTERNAL_CODE_SPACE 273 return code.code_data_container(kAcquireLoad); 274#else 275 return code; 276#endif 277} 278 279inline Handle<CodeT> ToCodeT(Handle<Code> code, Isolate* isolate) { 280#ifdef V8_EXTERNAL_CODE_SPACE 281 return handle(ToCodeT(*code), isolate); 282#else 283 return code; 284#endif 285} 286 287inline MaybeHandle<CodeT> ToCodeT(MaybeHandle<Code> maybe_code, 288 Isolate* isolate) { 289#ifdef V8_EXTERNAL_CODE_SPACE 290 Handle<Code> code; 291 if (maybe_code.ToHandle(&code)) return ToCodeT(code, isolate); 292 return {}; 293#else 294 return maybe_code; 295#endif 296} 297 298inline Code FromCodeT(CodeT code) { 299#ifdef V8_EXTERNAL_CODE_SPACE 300 return code.code(); 301#else 302 return code; 303#endif 304} 305 306inline Code FromCodeT(CodeT code, RelaxedLoadTag) { 307#ifdef V8_EXTERNAL_CODE_SPACE 308 return code.code(kRelaxedLoad); 309#else 310 return code; 311#endif 312} 313 314inline Handle<Code> FromCodeT(Handle<CodeT> code, Isolate* isolate) { 315#ifdef V8_EXTERNAL_CODE_SPACE 316 return handle(FromCodeT(*code), isolate); 317#else 318 return code; 319#endif 320} 321 322inline Handle<AbstractCode> ToAbstractCode(Handle<CodeT> code, 323 Isolate* isolate) { 324 return Handle<AbstractCode>::cast(FromCodeT(code, isolate)); 325} 326 327inline CodeDataContainer CodeDataContainerFromCodeT(CodeT code) { 328#ifdef V8_EXTERNAL_CODE_SPACE 329 return code; 330#else 331 return code.code_data_container(kAcquireLoad); 332#endif 333} 334 335void Code::WipeOutHeader() { 336 WRITE_FIELD(*this, kRelocationInfoOffset, Smi::FromInt(0)); 337 WRITE_FIELD(*this, kDeoptimizationDataOrInterpreterDataOffset, 338 Smi::FromInt(0)); 339 WRITE_FIELD(*this, kPositionTableOffset, Smi::FromInt(0)); 340 WRITE_FIELD(*this, kCodeDataContainerOffset, Smi::FromInt(0)); 341 if (V8_EXTERNAL_CODE_SPACE_BOOL) { 342 set_main_cage_base(kNullAddress, kRelaxedStore); 343 } 344} 345 346void Code::clear_padding() { 347 // Clear the padding between the header and `raw_body_start`. 348 if (FIELD_SIZE(kOptionalPaddingOffset) != 0) { 349 memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0, 350 FIELD_SIZE(kOptionalPaddingOffset)); 351 } 352 353 // Clear the padding after `raw_body_end`. 354 size_t trailing_padding_size = 355 CodeSize() - Code::kHeaderSize - raw_body_size(); 356 memset(reinterpret_cast<void*>(raw_body_end()), 0, trailing_padding_size); 357} 358 359ByteArray Code::SourcePositionTable(SharedFunctionInfo sfi) const { 360 DisallowGarbageCollection no_gc; 361 if (kind() == CodeKind::BASELINE) { 362 return sfi.GetBytecodeArray(sfi.GetIsolate()).SourcePositionTable(); 363 } 364 return source_position_table(); 365} 366 367Object Code::next_code_link() const { 368 return code_data_container(kAcquireLoad).next_code_link(); 369} 370 371void Code::set_next_code_link(Object value) { 372 code_data_container(kAcquireLoad).set_next_code_link(value); 373} 374 375Address Code::raw_body_start() const { return raw_instruction_start(); } 376 377Address Code::raw_body_end() const { 378 return raw_body_start() + raw_body_size(); 379} 380 381int Code::raw_body_size() const { 382 return raw_instruction_size() + raw_metadata_size(); 383} 384 385int Code::InstructionSize() const { 386 return V8_UNLIKELY(is_off_heap_trampoline()) 387 ? OffHeapInstructionSize(*this, builtin_id()) 388 : raw_instruction_size(); 389} 390 391Address Code::raw_instruction_start() const { 392 return field_address(kHeaderSize); 393} 394 395Address Code::InstructionStart() const { 396 return V8_UNLIKELY(is_off_heap_trampoline()) 397 ? i::OffHeapInstructionStart(*this, builtin_id()) 398 : raw_instruction_start(); 399} 400 401Address Code::raw_instruction_end() const { 402 return raw_instruction_start() + raw_instruction_size(); 403} 404 405Address Code::InstructionEnd() const { 406 return V8_UNLIKELY(is_off_heap_trampoline()) 407 ? i::OffHeapInstructionEnd(*this, builtin_id()) 408 : raw_instruction_end(); 409} 410 411Address Code::raw_metadata_start() const { 412 return raw_instruction_start() + raw_instruction_size(); 413} 414 415Address Code::InstructionStart(Isolate* isolate, Address pc) const { 416 return V8_UNLIKELY(is_off_heap_trampoline()) 417 ? OffHeapInstructionStart(isolate, pc) 418 : raw_instruction_start(); 419} 420 421Address Code::InstructionEnd(Isolate* isolate, Address pc) const { 422 return V8_UNLIKELY(is_off_heap_trampoline()) 423 ? OffHeapInstructionEnd(isolate, pc) 424 : raw_instruction_end(); 425} 426 427int Code::GetOffsetFromInstructionStart(Isolate* isolate, Address pc) const { 428 Address instruction_start = InstructionStart(isolate, pc); 429 Address offset = pc - instruction_start; 430 DCHECK_LE(offset, InstructionSize()); 431 return static_cast<int>(offset); 432} 433 434Address Code::raw_metadata_end() const { 435 return raw_metadata_start() + raw_metadata_size(); 436} 437 438int Code::MetadataSize() const { 439 return V8_UNLIKELY(is_off_heap_trampoline()) 440 ? OffHeapMetadataSize(*this, builtin_id()) 441 : raw_metadata_size(); 442} 443 444int Code::SizeIncludingMetadata() const { 445 int size = CodeSize(); 446 size += relocation_info().Size(); 447 if (kind() != CodeKind::BASELINE) { 448 size += deoptimization_data().Size(); 449 } 450 return size; 451} 452 453Address Code::SafepointTableAddress() const { 454 return V8_UNLIKELY(is_off_heap_trampoline()) 455 ? OffHeapSafepointTableAddress(*this, builtin_id()) 456 : raw_metadata_start() + safepoint_table_offset(); 457} 458 459int Code::safepoint_table_size() const { 460 DCHECK_GE(handler_table_offset() - safepoint_table_offset(), 0); 461 return handler_table_offset() - safepoint_table_offset(); 462} 463 464bool Code::has_safepoint_table() const { return safepoint_table_size() > 0; } 465 466Address Code::HandlerTableAddress() const { 467 return V8_UNLIKELY(is_off_heap_trampoline()) 468 ? OffHeapHandlerTableAddress(*this, builtin_id()) 469 : raw_metadata_start() + handler_table_offset(); 470} 471 472int Code::handler_table_size() const { 473 DCHECK_GE(constant_pool_offset() - handler_table_offset(), 0); 474 return constant_pool_offset() - handler_table_offset(); 475} 476 477bool Code::has_handler_table() const { return handler_table_size() > 0; } 478 479int Code::constant_pool_size() const { 480 const int size = code_comments_offset() - constant_pool_offset(); 481 DCHECK_IMPLIES(!FLAG_enable_embedded_constant_pool, size == 0); 482 DCHECK_GE(size, 0); 483 return size; 484} 485 486bool Code::has_constant_pool() const { return constant_pool_size() > 0; } 487 488int Code::code_comments_size() const { 489 DCHECK_GE(unwinding_info_offset() - code_comments_offset(), 0); 490 return unwinding_info_offset() - code_comments_offset(); 491} 492 493bool Code::has_code_comments() const { return code_comments_size() > 0; } 494 495ByteArray Code::unchecked_relocation_info() const { 496 PtrComprCageBase cage_base = main_cage_base(); 497 return ByteArray::unchecked_cast( 498 TaggedField<HeapObject, kRelocationInfoOffset>::load(cage_base, *this)); 499} 500 501byte* Code::relocation_start() const { 502 return unchecked_relocation_info().GetDataStartAddress(); 503} 504 505byte* Code::relocation_end() const { 506 return unchecked_relocation_info().GetDataEndAddress(); 507} 508 509int Code::relocation_size() const { 510 return unchecked_relocation_info().length(); 511} 512 513Address Code::entry() const { return raw_instruction_start(); } 514 515bool Code::contains(Isolate* isolate, Address inner_pointer) { 516 if (is_off_heap_trampoline()) { 517 if (OffHeapInstructionStart(isolate, inner_pointer) <= inner_pointer && 518 inner_pointer < OffHeapInstructionEnd(isolate, inner_pointer)) { 519 return true; 520 } 521 } 522 return (address() <= inner_pointer) && 523 (inner_pointer < address() + CodeSize()); 524} 525 526// static 527void Code::CopyRelocInfoToByteArray(ByteArray dest, const CodeDesc& desc) { 528 DCHECK_EQ(dest.length(), desc.reloc_size); 529 CopyBytes(dest.GetDataStartAddress(), 530 desc.buffer + desc.buffer_size - desc.reloc_size, 531 static_cast<size_t>(desc.reloc_size)); 532} 533 534int Code::CodeSize() const { return SizeFor(raw_body_size()); } 535 536DEF_GETTER(Code, Size, int) { return CodeSize(); } 537 538CodeKind Code::kind() const { 539 STATIC_ASSERT(FIELD_SIZE(kFlagsOffset) == kInt32Size); 540 const uint32_t flags = RELAXED_READ_UINT32_FIELD(*this, kFlagsOffset); 541 return KindField::decode(flags); 542} 543 544int Code::GetBytecodeOffsetForBaselinePC(Address baseline_pc, 545 BytecodeArray bytecodes) { 546 DisallowGarbageCollection no_gc; 547 CHECK(!is_baseline_trampoline_builtin()); 548 if (is_baseline_leave_frame_builtin()) return kFunctionExitBytecodeOffset; 549 CHECK_EQ(kind(), CodeKind::BASELINE); 550 baseline::BytecodeOffsetIterator offset_iterator( 551 ByteArray::cast(bytecode_offset_table()), bytecodes); 552 Address pc = baseline_pc - InstructionStart(); 553 offset_iterator.AdvanceToPCOffset(pc); 554 return offset_iterator.current_bytecode_offset(); 555} 556 557uintptr_t Code::GetBaselinePCForBytecodeOffset(int bytecode_offset, 558 BytecodeToPCPosition position, 559 BytecodeArray bytecodes) { 560 DisallowGarbageCollection no_gc; 561 CHECK_EQ(kind(), CodeKind::BASELINE); 562 baseline::BytecodeOffsetIterator offset_iterator( 563 ByteArray::cast(bytecode_offset_table()), bytecodes); 564 offset_iterator.AdvanceToBytecodeOffset(bytecode_offset); 565 uintptr_t pc = 0; 566 if (position == kPcAtStartOfBytecode) { 567 pc = offset_iterator.current_pc_start_offset(); 568 } else { 569 DCHECK_EQ(position, kPcAtEndOfBytecode); 570 pc = offset_iterator.current_pc_end_offset(); 571 } 572 return pc; 573} 574 575uintptr_t Code::GetBaselineStartPCForBytecodeOffset(int bytecode_offset, 576 BytecodeArray bytecodes) { 577 return GetBaselinePCForBytecodeOffset(bytecode_offset, kPcAtStartOfBytecode, 578 bytecodes); 579} 580 581uintptr_t Code::GetBaselineEndPCForBytecodeOffset(int bytecode_offset, 582 BytecodeArray bytecodes) { 583 return GetBaselinePCForBytecodeOffset(bytecode_offset, kPcAtEndOfBytecode, 584 bytecodes); 585} 586 587uintptr_t Code::GetBaselinePCForNextExecutedBytecode(int bytecode_offset, 588 BytecodeArray bytecodes) { 589 DisallowGarbageCollection no_gc; 590 CHECK_EQ(kind(), CodeKind::BASELINE); 591 baseline::BytecodeOffsetIterator offset_iterator( 592 ByteArray::cast(bytecode_offset_table()), bytecodes); 593 Handle<BytecodeArray> bytecodes_handle( 594 reinterpret_cast<Address*>(&bytecodes)); 595 interpreter::BytecodeArrayIterator bytecode_iterator(bytecodes_handle, 596 bytecode_offset); 597 interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode(); 598 if (bytecode == interpreter::Bytecode::kJumpLoop) { 599 return GetBaselineStartPCForBytecodeOffset( 600 bytecode_iterator.GetJumpTargetOffset(), bytecodes); 601 } else { 602 DCHECK(!interpreter::Bytecodes::IsJump(bytecode)); 603 return GetBaselineEndPCForBytecodeOffset(bytecode_offset, bytecodes); 604 } 605} 606 607void Code::initialize_flags(CodeKind kind, bool is_turbofanned, int stack_slots, 608 bool is_off_heap_trampoline) { 609 CHECK(0 <= stack_slots && stack_slots < StackSlotsField::kMax); 610 DCHECK(!CodeKindIsInterpretedJSFunction(kind)); 611 uint32_t flags = KindField::encode(kind) | 612 IsTurbofannedField::encode(is_turbofanned) | 613 StackSlotsField::encode(stack_slots) | 614 IsOffHeapTrampoline::encode(is_off_heap_trampoline); 615 STATIC_ASSERT(FIELD_SIZE(kFlagsOffset) == kInt32Size); 616 RELAXED_WRITE_UINT32_FIELD(*this, kFlagsOffset, flags); 617 DCHECK_IMPLIES(stack_slots != 0, uses_safepoint_table()); 618 DCHECK_IMPLIES(!uses_safepoint_table(), stack_slots == 0); 619} 620 621inline bool Code::is_interpreter_trampoline_builtin() const { 622 return IsInterpreterTrampolineBuiltin(builtin_id()); 623} 624 625inline bool Code::is_baseline_trampoline_builtin() const { 626 return IsBaselineTrampolineBuiltin(builtin_id()); 627} 628 629inline bool Code::is_baseline_leave_frame_builtin() const { 630 return builtin_id() == Builtin::kBaselineLeaveFrame; 631} 632 633#ifdef V8_EXTERNAL_CODE_SPACE 634// Note, must be in sync with Code::checks_tiering_state(). 635inline bool CodeDataContainer::checks_tiering_state() const { 636 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 637 bool checks_state = (builtin_id() == Builtin::kCompileLazy || 638 builtin_id() == Builtin::kInterpreterEntryTrampoline || 639 CodeKindCanTierUp(kind())); 640 return checks_state || 641 (CodeKindCanDeoptimize(kind()) && marked_for_deoptimization()); 642} 643#endif // V8_EXTERNAL_CODE_SPACE 644 645// Note, must be in sync with CodeDataContainer::checks_tiering_state(). 646inline bool Code::checks_tiering_state() const { 647 bool checks_state = (builtin_id() == Builtin::kCompileLazy || 648 builtin_id() == Builtin::kInterpreterEntryTrampoline || 649 CodeKindCanTierUp(kind())); 650 return checks_state || 651 (CodeKindCanDeoptimize(kind()) && marked_for_deoptimization()); 652} 653 654inline bool Code::has_tagged_outgoing_params() const { 655 return kind() != CodeKind::JS_TO_WASM_FUNCTION && 656 kind() != CodeKind::C_WASM_ENTRY && kind() != CodeKind::WASM_FUNCTION; 657} 658 659inline bool Code::is_turbofanned() const { 660 const uint32_t flags = RELAXED_READ_UINT32_FIELD(*this, kFlagsOffset); 661 return IsTurbofannedField::decode(flags); 662} 663 664bool Code::is_maglevved() const { return kind() == CodeKind::MAGLEV; } 665 666inline bool Code::can_have_weak_objects() const { 667 DCHECK(CodeKindIsOptimizedJSFunction(kind())); 668 int32_t flags = 669 code_data_container(kAcquireLoad).kind_specific_flags(kRelaxedLoad); 670 return CanHaveWeakObjectsField::decode(flags); 671} 672 673inline void Code::set_can_have_weak_objects(bool value) { 674 DCHECK(CodeKindIsOptimizedJSFunction(kind())); 675 CodeDataContainer container = code_data_container(kAcquireLoad); 676 int32_t previous = container.kind_specific_flags(kRelaxedLoad); 677 int32_t updated = CanHaveWeakObjectsField::update(previous, value); 678 container.set_kind_specific_flags(updated, kRelaxedStore); 679} 680 681inline bool Code::is_promise_rejection() const { 682 DCHECK(kind() == CodeKind::BUILTIN); 683 int32_t flags = 684 code_data_container(kAcquireLoad).kind_specific_flags(kRelaxedLoad); 685 return IsPromiseRejectionField::decode(flags); 686} 687 688inline void Code::set_is_promise_rejection(bool value) { 689 DCHECK(kind() == CodeKind::BUILTIN); 690 CodeDataContainer container = code_data_container(kAcquireLoad); 691 int32_t previous = container.kind_specific_flags(kRelaxedLoad); 692 int32_t updated = IsPromiseRejectionField::update(previous, value); 693 container.set_kind_specific_flags(updated, kRelaxedStore); 694} 695 696inline bool Code::is_off_heap_trampoline() const { 697 const uint32_t flags = RELAXED_READ_UINT32_FIELD(*this, kFlagsOffset); 698 return IsOffHeapTrampoline::decode(flags); 699} 700 701inline HandlerTable::CatchPrediction Code::GetBuiltinCatchPrediction() { 702 if (is_promise_rejection()) return HandlerTable::PROMISE; 703 return HandlerTable::UNCAUGHT; 704} 705 706Builtin Code::builtin_id() const { 707 int index = RELAXED_READ_INT_FIELD(*this, kBuiltinIndexOffset); 708 DCHECK(index == static_cast<int>(Builtin::kNoBuiltinId) || 709 Builtins::IsBuiltinId(index)); 710 return static_cast<Builtin>(index); 711} 712 713void Code::set_builtin_id(Builtin builtin) { 714 DCHECK(builtin == Builtin::kNoBuiltinId || Builtins::IsBuiltinId(builtin)); 715 RELAXED_WRITE_INT_FIELD(*this, kBuiltinIndexOffset, 716 static_cast<int>(builtin)); 717} 718 719bool Code::is_builtin() const { return builtin_id() != Builtin::kNoBuiltinId; } 720 721unsigned Code::inlined_bytecode_size() const { 722 unsigned size = RELAXED_READ_UINT_FIELD(*this, kInlinedBytecodeSizeOffset); 723 DCHECK(CodeKindIsOptimizedJSFunction(kind()) || size == 0); 724 return size; 725} 726 727void Code::set_inlined_bytecode_size(unsigned size) { 728 DCHECK(CodeKindIsOptimizedJSFunction(kind()) || size == 0); 729 RELAXED_WRITE_UINT_FIELD(*this, kInlinedBytecodeSizeOffset, size); 730} 731 732bool Code::uses_safepoint_table() const { 733 return is_turbofanned() || is_maglevved() || is_wasm_code(); 734} 735 736int Code::stack_slots() const { 737 const uint32_t flags = RELAXED_READ_UINT32_FIELD(*this, kFlagsOffset); 738 const int slots = StackSlotsField::decode(flags); 739 DCHECK_IMPLIES(!uses_safepoint_table(), slots == 0); 740 return slots; 741} 742 743bool CodeDataContainer::marked_for_deoptimization() const { 744#ifdef V8_EXTERNAL_CODE_SPACE 745 // kind field is not available on CodeDataContainer when external code space 746 // is not enabled. 747 DCHECK(CodeKindCanDeoptimize(kind())); 748#endif // V8_EXTERNAL_CODE_SPACE 749 int32_t flags = kind_specific_flags(kRelaxedLoad); 750 return Code::MarkedForDeoptimizationField::decode(flags); 751} 752 753bool Code::marked_for_deoptimization() const { 754 DCHECK(CodeKindCanDeoptimize(kind())); 755 return code_data_container(kAcquireLoad).marked_for_deoptimization(); 756} 757 758void CodeDataContainer::set_marked_for_deoptimization(bool flag) { 759#ifdef V8_EXTERNAL_CODE_SPACE 760 // kind field is not available on CodeDataContainer when external code space 761 // is not enabled. 762 DCHECK(CodeKindCanDeoptimize(kind())); 763#endif // V8_EXTERNAL_CODE_SPACE 764 DCHECK_IMPLIES(flag, AllowDeoptimization::IsAllowed(GetIsolate())); 765 int32_t previous = kind_specific_flags(kRelaxedLoad); 766 int32_t updated = Code::MarkedForDeoptimizationField::update(previous, flag); 767 set_kind_specific_flags(updated, kRelaxedStore); 768} 769 770void Code::set_marked_for_deoptimization(bool flag) { 771 code_data_container(kAcquireLoad).set_marked_for_deoptimization(flag); 772} 773 774bool Code::embedded_objects_cleared() const { 775 DCHECK(CodeKindIsOptimizedJSFunction(kind())); 776 int32_t flags = 777 code_data_container(kAcquireLoad).kind_specific_flags(kRelaxedLoad); 778 return EmbeddedObjectsClearedField::decode(flags); 779} 780 781void Code::set_embedded_objects_cleared(bool flag) { 782 DCHECK(CodeKindIsOptimizedJSFunction(kind())); 783 DCHECK_IMPLIES(flag, marked_for_deoptimization()); 784 CodeDataContainer container = code_data_container(kAcquireLoad); 785 int32_t previous = container.kind_specific_flags(kRelaxedLoad); 786 int32_t updated = EmbeddedObjectsClearedField::update(previous, flag); 787 container.set_kind_specific_flags(updated, kRelaxedStore); 788} 789 790bool Code::is_optimized_code() const { 791 return CodeKindIsOptimizedJSFunction(kind()); 792} 793 794bool Code::is_wasm_code() const { return kind() == CodeKind::WASM_FUNCTION; } 795 796int Code::constant_pool_offset() const { 797 if (!FLAG_enable_embedded_constant_pool) { 798 // Redirection needed since the field doesn't exist in this case. 799 return code_comments_offset(); 800 } 801 return ReadField<int>(kConstantPoolOffsetOffset); 802} 803 804void Code::set_constant_pool_offset(int value) { 805 if (!FLAG_enable_embedded_constant_pool) { 806 // Redirection needed since the field doesn't exist in this case. 807 return; 808 } 809 DCHECK_LE(value, MetadataSize()); 810 WriteField<int>(kConstantPoolOffsetOffset, value); 811} 812 813Address Code::constant_pool() const { 814 if (!has_constant_pool()) return kNullAddress; 815 return V8_UNLIKELY(is_off_heap_trampoline()) 816 ? OffHeapConstantPoolAddress(*this, builtin_id()) 817 : raw_metadata_start() + constant_pool_offset(); 818} 819 820Address Code::code_comments() const { 821 return V8_UNLIKELY(is_off_heap_trampoline()) 822 ? OffHeapCodeCommentsAddress(*this, builtin_id()) 823 : raw_metadata_start() + code_comments_offset(); 824} 825 826Address Code::unwinding_info_start() const { 827 return V8_UNLIKELY(is_off_heap_trampoline()) 828 ? OffHeapUnwindingInfoAddress(*this, builtin_id()) 829 : raw_metadata_start() + unwinding_info_offset(); 830} 831 832Address Code::unwinding_info_end() const { 833 return V8_UNLIKELY(is_off_heap_trampoline()) 834 ? OffHeapMetadataEnd(*this, builtin_id()) 835 : raw_metadata_end(); 836} 837 838int Code::unwinding_info_size() const { 839 DCHECK_GE(unwinding_info_end(), unwinding_info_start()); 840 return static_cast<int>(unwinding_info_end() - unwinding_info_start()); 841} 842 843bool Code::has_unwinding_info() const { return unwinding_info_size() > 0; } 844 845Code Code::GetCodeFromTargetAddress(Address address) { 846 { 847 // TODO(jgruber,v8:6666): Support embedded builtins here. We'd need to pass 848 // in the current isolate. 849 Address start = 850 reinterpret_cast<Address>(Isolate::CurrentEmbeddedBlobCode()); 851 Address end = start + Isolate::CurrentEmbeddedBlobCodeSize(); 852 CHECK(address < start || address >= end); 853 } 854 855 HeapObject code = HeapObject::FromAddress(address - Code::kHeaderSize); 856 // Unchecked cast because we can't rely on the map currently 857 // not being a forwarding pointer. 858 return Code::unchecked_cast(code); 859} 860 861Code Code::GetObjectFromEntryAddress(Address location_of_address) { 862 Address code_entry = base::Memory<Address>(location_of_address); 863 HeapObject code = HeapObject::FromAddress(code_entry - Code::kHeaderSize); 864 // Unchecked cast because we can't rely on the map currently 865 // not being a forwarding pointer. 866 return Code::unchecked_cast(code); 867} 868 869bool Code::CanContainWeakObjects() { 870 return is_optimized_code() && can_have_weak_objects(); 871} 872 873bool Code::IsWeakObject(HeapObject object) { 874 return (CanContainWeakObjects() && IsWeakObjectInOptimizedCode(object)); 875} 876 877bool Code::IsWeakObjectInOptimizedCode(HeapObject object) { 878 Map map = object.map(kAcquireLoad); 879 InstanceType instance_type = map.instance_type(); 880 if (InstanceTypeChecker::IsMap(instance_type)) { 881 return Map::cast(object).CanTransition(); 882 } 883 return InstanceTypeChecker::IsPropertyCell(instance_type) || 884 InstanceTypeChecker::IsJSReceiver(instance_type) || 885 InstanceTypeChecker::IsContext(instance_type); 886} 887 888bool Code::IsWeakObjectInDeoptimizationLiteralArray(Object object) { 889 // Maps must be strong because they can be used as part of the description for 890 // how to materialize an object upon deoptimization, in which case it is 891 // possible to reach the code that requires the Map without anything else 892 // holding a strong pointer to that Map. 893 return object.IsHeapObject() && !object.IsMap() && 894 Code::IsWeakObjectInOptimizedCode(HeapObject::cast(object)); 895} 896 897bool Code::IsExecutable() { 898 return !Builtins::IsBuiltinId(builtin_id()) || !is_off_heap_trampoline() || 899 Builtins::CodeObjectIsExecutable(builtin_id()); 900} 901 902// This field has to have relaxed atomic accessors because it is accessed in the 903// concurrent marker. 904STATIC_ASSERT(FIELD_SIZE(CodeDataContainer::kKindSpecificFlagsOffset) == 905 kInt32Size); 906RELAXED_INT32_ACCESSORS(CodeDataContainer, kind_specific_flags, 907 kKindSpecificFlagsOffset) 908 909#if defined(V8_TARGET_LITTLE_ENDIAN) 910static_assert(!V8_EXTERNAL_CODE_SPACE_BOOL || 911 (CodeDataContainer::kCodeCageBaseUpper32BitsOffset == 912 CodeDataContainer::kCodeOffset + kTaggedSize), 913 "CodeDataContainer::code field layout requires updating " 914 "for little endian architectures"); 915#elif defined(V8_TARGET_BIG_ENDIAN) 916static_assert(!V8_EXTERNAL_CODE_SPACE_BOOL, 917 "CodeDataContainer::code field layout requires updating " 918 "for big endian architectures"); 919#endif 920 921Object CodeDataContainer::raw_code() const { 922 PtrComprCageBase cage_base = code_cage_base(); 923 return CodeDataContainer::raw_code(cage_base); 924} 925 926Object CodeDataContainer::raw_code(PtrComprCageBase cage_base) const { 927 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 928 Object value = TaggedField<Object, kCodeOffset>::load(cage_base, *this); 929 return value; 930} 931 932void CodeDataContainer::set_raw_code(Object value, WriteBarrierMode mode) { 933 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 934 TaggedField<Object, kCodeOffset>::store(*this, value); 935 CONDITIONAL_WRITE_BARRIER(*this, kCodeOffset, value, mode); 936} 937 938Object CodeDataContainer::raw_code(RelaxedLoadTag tag) const { 939 PtrComprCageBase cage_base = code_cage_base(tag); 940 return CodeDataContainer::raw_code(cage_base, tag); 941} 942 943Object CodeDataContainer::raw_code(PtrComprCageBase cage_base, 944 RelaxedLoadTag) const { 945 Object value = 946 TaggedField<Object, kCodeOffset>::Relaxed_Load(cage_base, *this); 947 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 948 return value; 949} 950 951ACCESSORS(CodeDataContainer, next_code_link, Object, kNextCodeLinkOffset) 952 953PtrComprCageBase CodeDataContainer::code_cage_base() const { 954#ifdef V8_EXTERNAL_CODE_SPACE 955 // TODO(v8:10391): consider protecting this value with the sandbox. 956 Address code_cage_base_hi = 957 ReadField<Tagged_t>(kCodeCageBaseUpper32BitsOffset); 958 return PtrComprCageBase(code_cage_base_hi << 32); 959#else 960 return GetPtrComprCageBase(*this); 961#endif 962} 963 964void CodeDataContainer::set_code_cage_base(Address code_cage_base) { 965#ifdef V8_EXTERNAL_CODE_SPACE 966 Tagged_t code_cage_base_hi = static_cast<Tagged_t>(code_cage_base >> 32); 967 WriteField<Tagged_t>(kCodeCageBaseUpper32BitsOffset, code_cage_base_hi); 968#else 969 UNREACHABLE(); 970#endif 971} 972 973PtrComprCageBase CodeDataContainer::code_cage_base(RelaxedLoadTag) const { 974#ifdef V8_EXTERNAL_CODE_SPACE 975 // TODO(v8:10391): consider protecting this value with the sandbox. 976 Address code_cage_base_hi = 977 Relaxed_ReadField<Tagged_t>(kCodeCageBaseUpper32BitsOffset); 978 return PtrComprCageBase(code_cage_base_hi << 32); 979#else 980 return GetPtrComprCageBase(*this); 981#endif 982} 983 984void CodeDataContainer::set_code_cage_base(Address code_cage_base, 985 RelaxedStoreTag) { 986#ifdef V8_EXTERNAL_CODE_SPACE 987 Tagged_t code_cage_base_hi = static_cast<Tagged_t>(code_cage_base >> 32); 988 Relaxed_WriteField<Tagged_t>(kCodeCageBaseUpper32BitsOffset, 989 code_cage_base_hi); 990#else 991 UNREACHABLE(); 992#endif 993} 994 995void CodeDataContainer::AllocateExternalPointerEntries(Isolate* isolate) { 996 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 997 InitExternalPointerField(kCodeEntryPointOffset, isolate, kCodeEntryPointTag); 998} 999 1000Code CodeDataContainer::code() const { 1001 PtrComprCageBase cage_base = code_cage_base(); 1002 return CodeDataContainer::code(cage_base); 1003} 1004Code CodeDataContainer::code(PtrComprCageBase cage_base) const { 1005 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1006 return Code::cast(raw_code(cage_base)); 1007} 1008 1009Code CodeDataContainer::code(RelaxedLoadTag tag) const { 1010 PtrComprCageBase cage_base = code_cage_base(tag); 1011 return CodeDataContainer::code(cage_base, tag); 1012} 1013 1014Code CodeDataContainer::code(PtrComprCageBase cage_base, 1015 RelaxedLoadTag tag) const { 1016 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1017 return Code::cast(raw_code(cage_base, tag)); 1018} 1019 1020DEF_GETTER(CodeDataContainer, code_entry_point, Address) { 1021 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1022 Isolate* isolate = GetIsolateForSandbox(*this); 1023 return ReadExternalPointerField(kCodeEntryPointOffset, isolate, 1024 kCodeEntryPointTag); 1025} 1026 1027void CodeDataContainer::set_code_entry_point(Isolate* isolate, Address value) { 1028 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1029 WriteExternalPointerField(kCodeEntryPointOffset, isolate, value, 1030 kCodeEntryPointTag); 1031} 1032 1033void CodeDataContainer::SetCodeAndEntryPoint(Isolate* isolate_for_sandbox, 1034 Code code, WriteBarrierMode mode) { 1035 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1036 set_raw_code(code, mode); 1037 set_code_entry_point(isolate_for_sandbox, code.InstructionStart()); 1038} 1039 1040void CodeDataContainer::UpdateCodeEntryPoint(Isolate* isolate_for_sandbox, 1041 Code code) { 1042 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1043 DCHECK_EQ(raw_code(), code); 1044 set_code_entry_point(isolate_for_sandbox, code.InstructionStart()); 1045} 1046 1047Address CodeDataContainer::InstructionStart() const { 1048 return code_entry_point(); 1049} 1050 1051Address CodeDataContainer::raw_instruction_start() { 1052 return code_entry_point(); 1053} 1054 1055Address CodeDataContainer::entry() const { return code_entry_point(); } 1056 1057void CodeDataContainer::clear_padding() { 1058 memset(reinterpret_cast<void*>(address() + kUnalignedSize), 0, 1059 kSize - kUnalignedSize); 1060} 1061 1062RELAXED_UINT16_ACCESSORS(CodeDataContainer, flags, kFlagsOffset) 1063 1064// Ensure builtin_id field fits into int16_t, so that we can rely on sign 1065// extension to convert int16_t{-1} to kNoBuiltinId. 1066// If the asserts fail, update the code that use kBuiltinIdOffset below. 1067STATIC_ASSERT(static_cast<int>(Builtin::kNoBuiltinId) == -1); 1068STATIC_ASSERT(Builtins::kBuiltinCount < std::numeric_limits<int16_t>::max()); 1069 1070void CodeDataContainer::initialize_flags(CodeKind kind, Builtin builtin_id) { 1071 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1072 uint16_t value = KindField::encode(kind); 1073 set_flags(value, kRelaxedStore); 1074 1075 WriteField<int16_t>(kBuiltinIdOffset, static_cast<int16_t>(builtin_id)); 1076} 1077 1078#ifdef V8_EXTERNAL_CODE_SPACE 1079 1080CodeKind CodeDataContainer::kind() const { 1081 return KindField::decode(flags(kRelaxedLoad)); 1082} 1083 1084Builtin CodeDataContainer::builtin_id() const { 1085 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1086 // Rely on sign-extension when converting int16_t to int to preserve 1087 // kNoBuiltinId value. 1088 STATIC_ASSERT(static_cast<int>(static_cast<int16_t>(Builtin::kNoBuiltinId)) == 1089 static_cast<int>(Builtin::kNoBuiltinId)); 1090 int value = ReadField<int16_t>(kBuiltinIdOffset); 1091 return static_cast<Builtin>(value); 1092} 1093 1094bool CodeDataContainer::is_builtin() const { 1095 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 1096 return builtin_id() != Builtin::kNoBuiltinId; 1097} 1098 1099bool CodeDataContainer::is_optimized_code() const { 1100 return CodeKindIsOptimizedJSFunction(kind()); 1101} 1102 1103inline bool CodeDataContainer::is_interpreter_trampoline_builtin() const { 1104 return IsInterpreterTrampolineBuiltin(builtin_id()); 1105} 1106 1107// 1108// A collection of getters and predicates that forward queries to associated 1109// Code object. 1110// 1111 1112#define DEF_PRIMITIVE_FORWARDING_CDC_GETTER(name, type) \ 1113 type CodeDataContainer::name() const { return FromCodeT(*this).name(); } 1114 1115#define DEF_FORWARDING_CDC_GETTER(name, type) \ 1116 DEF_GETTER(CodeDataContainer, name, type) { \ 1117 return FromCodeT(*this).name(cage_base); \ 1118 } 1119 1120DEF_PRIMITIVE_FORWARDING_CDC_GETTER(is_maglevved, bool) 1121DEF_PRIMITIVE_FORWARDING_CDC_GETTER(is_turbofanned, bool) 1122DEF_PRIMITIVE_FORWARDING_CDC_GETTER(is_off_heap_trampoline, bool) 1123 1124DEF_FORWARDING_CDC_GETTER(deoptimization_data, FixedArray) 1125DEF_FORWARDING_CDC_GETTER(bytecode_or_interpreter_data, HeapObject) 1126DEF_FORWARDING_CDC_GETTER(source_position_table, ByteArray) 1127DEF_FORWARDING_CDC_GETTER(bytecode_offset_table, ByteArray) 1128 1129#undef DEF_PRIMITIVE_FORWARDING_CDC_GETTER 1130#undef DEF_FORWARDING_CDC_GETTER 1131 1132#endif // V8_EXTERNAL_CODE_SPACE 1133 1134byte BytecodeArray::get(int index) const { 1135 DCHECK(index >= 0 && index < this->length()); 1136 return ReadField<byte>(kHeaderSize + index * kCharSize); 1137} 1138 1139void BytecodeArray::set(int index, byte value) { 1140 DCHECK(index >= 0 && index < this->length()); 1141 WriteField<byte>(kHeaderSize + index * kCharSize, value); 1142} 1143 1144void BytecodeArray::set_frame_size(int32_t frame_size) { 1145 DCHECK_GE(frame_size, 0); 1146 DCHECK(IsAligned(frame_size, kSystemPointerSize)); 1147 WriteField<int32_t>(kFrameSizeOffset, frame_size); 1148} 1149 1150int32_t BytecodeArray::frame_size() const { 1151 return ReadField<int32_t>(kFrameSizeOffset); 1152} 1153 1154int BytecodeArray::register_count() const { 1155 return static_cast<int>(frame_size()) / kSystemPointerSize; 1156} 1157 1158void BytecodeArray::set_parameter_count(int32_t number_of_parameters) { 1159 DCHECK_GE(number_of_parameters, 0); 1160 // Parameter count is stored as the size on stack of the parameters to allow 1161 // it to be used directly by generated code. 1162 WriteField<int32_t>(kParameterSizeOffset, 1163 (number_of_parameters << kSystemPointerSizeLog2)); 1164} 1165 1166interpreter::Register BytecodeArray::incoming_new_target_or_generator_register() 1167 const { 1168 int32_t register_operand = 1169 ReadField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset); 1170 if (register_operand == 0) { 1171 return interpreter::Register::invalid_value(); 1172 } else { 1173 return interpreter::Register::FromOperand(register_operand); 1174 } 1175} 1176 1177void BytecodeArray::set_incoming_new_target_or_generator_register( 1178 interpreter::Register incoming_new_target_or_generator_register) { 1179 if (!incoming_new_target_or_generator_register.is_valid()) { 1180 WriteField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset, 0); 1181 } else { 1182 DCHECK(incoming_new_target_or_generator_register.index() < 1183 register_count()); 1184 DCHECK_NE(0, incoming_new_target_or_generator_register.ToOperand()); 1185 WriteField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset, 1186 incoming_new_target_or_generator_register.ToOperand()); 1187 } 1188} 1189 1190int BytecodeArray::osr_urgency() const { 1191 return OsrUrgencyBits::decode(osr_urgency_and_install_target()); 1192} 1193 1194void BytecodeArray::set_osr_urgency(int urgency) { 1195 DCHECK(0 <= urgency && urgency <= BytecodeArray::kMaxOsrUrgency); 1196 STATIC_ASSERT(BytecodeArray::kMaxOsrUrgency <= OsrUrgencyBits::kMax); 1197 uint32_t value = osr_urgency_and_install_target(); 1198 set_osr_urgency_and_install_target(OsrUrgencyBits::update(value, urgency)); 1199} 1200 1201BytecodeArray::Age BytecodeArray::bytecode_age() const { 1202 // Bytecode is aged by the concurrent marker. 1203 static_assert(kBytecodeAgeSize == kUInt16Size); 1204 return static_cast<Age>(RELAXED_READ_INT16_FIELD(*this, kBytecodeAgeOffset)); 1205} 1206 1207void BytecodeArray::reset_osr_urgency() { set_osr_urgency(0); } 1208 1209void BytecodeArray::RequestOsrAtNextOpportunity() { 1210 set_osr_urgency(kMaxOsrUrgency); 1211} 1212 1213int BytecodeArray::osr_install_target() { 1214 return OsrInstallTargetBits::decode(osr_urgency_and_install_target()); 1215} 1216 1217void BytecodeArray::set_osr_install_target(BytecodeOffset jump_loop_offset) { 1218 DCHECK_LE(jump_loop_offset.ToInt(), length()); 1219 set_osr_urgency_and_install_target(OsrInstallTargetBits::update( 1220 osr_urgency_and_install_target(), OsrInstallTargetFor(jump_loop_offset))); 1221} 1222 1223void BytecodeArray::reset_osr_install_target() { 1224 uint32_t value = osr_urgency_and_install_target(); 1225 set_osr_urgency_and_install_target( 1226 OsrInstallTargetBits::update(value, kNoOsrInstallTarget)); 1227} 1228 1229void BytecodeArray::reset_osr_urgency_and_install_target() { 1230 set_osr_urgency_and_install_target(OsrUrgencyBits::encode(0) | 1231 OsrInstallTargetBits::encode(0)); 1232} 1233 1234void BytecodeArray::set_bytecode_age(BytecodeArray::Age age) { 1235 DCHECK_GE(age, kFirstBytecodeAge); 1236 DCHECK_LE(age, kLastBytecodeAge); 1237 static_assert(kLastBytecodeAge <= kMaxInt16); 1238 static_assert(kBytecodeAgeSize == kUInt16Size); 1239 // Bytecode is aged by the concurrent marker. 1240 RELAXED_WRITE_INT16_FIELD(*this, kBytecodeAgeOffset, 1241 static_cast<int16_t>(age)); 1242} 1243 1244int32_t BytecodeArray::parameter_count() const { 1245 // Parameter count is stored as the size on stack of the parameters to allow 1246 // it to be used directly by generated code. 1247 return ReadField<int32_t>(kParameterSizeOffset) >> kSystemPointerSizeLog2; 1248} 1249 1250void BytecodeArray::clear_padding() { 1251 int data_size = kHeaderSize + length(); 1252 memset(reinterpret_cast<void*>(address() + data_size), 0, 1253 SizeFor(length()) - data_size); 1254} 1255 1256Address BytecodeArray::GetFirstBytecodeAddress() { 1257 return ptr() - kHeapObjectTag + kHeaderSize; 1258} 1259 1260bool BytecodeArray::HasSourcePositionTable() const { 1261 Object maybe_table = source_position_table(kAcquireLoad); 1262 return !(maybe_table.IsUndefined() || DidSourcePositionGenerationFail()); 1263} 1264 1265bool BytecodeArray::DidSourcePositionGenerationFail() const { 1266 return source_position_table(kAcquireLoad).IsException(); 1267} 1268 1269void BytecodeArray::SetSourcePositionsFailedToCollect() { 1270 set_source_position_table(GetReadOnlyRoots().exception(), kReleaseStore); 1271} 1272 1273ByteArray BytecodeArray::SourcePositionTable() const { 1274 // WARNING: This function may be called from a background thread, hence 1275 // changes to how it accesses the heap can easily lead to bugs. 1276 Object maybe_table = source_position_table(kAcquireLoad); 1277 if (maybe_table.IsByteArray()) return ByteArray::cast(maybe_table); 1278 ReadOnlyRoots roots = GetReadOnlyRoots(); 1279 DCHECK(maybe_table.IsUndefined(roots) || maybe_table.IsException(roots)); 1280 return roots.empty_byte_array(); 1281} 1282 1283int BytecodeArray::BytecodeArraySize() { return SizeFor(this->length()); } 1284 1285int BytecodeArray::SizeIncludingMetadata() { 1286 int size = BytecodeArraySize(); 1287 size += constant_pool().Size(); 1288 size += handler_table().Size(); 1289 ByteArray table = SourcePositionTable(); 1290 if (table.length() != 0) { 1291 size += table.Size(); 1292 } 1293 return size; 1294} 1295 1296DEFINE_DEOPT_ELEMENT_ACCESSORS(TranslationByteArray, TranslationArray) 1297DEFINE_DEOPT_ELEMENT_ACCESSORS(InlinedFunctionCount, Smi) 1298DEFINE_DEOPT_ELEMENT_ACCESSORS(LiteralArray, DeoptimizationLiteralArray) 1299DEFINE_DEOPT_ELEMENT_ACCESSORS(OsrBytecodeOffset, Smi) 1300DEFINE_DEOPT_ELEMENT_ACCESSORS(OsrPcOffset, Smi) 1301DEFINE_DEOPT_ELEMENT_ACCESSORS(OptimizationId, Smi) 1302DEFINE_DEOPT_ELEMENT_ACCESSORS(InliningPositions, PodArray<InliningPosition>) 1303DEFINE_DEOPT_ELEMENT_ACCESSORS(DeoptExitStart, Smi) 1304DEFINE_DEOPT_ELEMENT_ACCESSORS(EagerDeoptCount, Smi) 1305DEFINE_DEOPT_ELEMENT_ACCESSORS(LazyDeoptCount, Smi) 1306 1307DEFINE_DEOPT_ENTRY_ACCESSORS(BytecodeOffsetRaw, Smi) 1308DEFINE_DEOPT_ENTRY_ACCESSORS(TranslationIndex, Smi) 1309DEFINE_DEOPT_ENTRY_ACCESSORS(Pc, Smi) 1310#ifdef DEBUG 1311DEFINE_DEOPT_ENTRY_ACCESSORS(NodeId, Smi) 1312#endif // DEBUG 1313 1314BytecodeOffset DeoptimizationData::GetBytecodeOffset(int i) { 1315 return BytecodeOffset(BytecodeOffsetRaw(i).value()); 1316} 1317 1318void DeoptimizationData::SetBytecodeOffset(int i, BytecodeOffset value) { 1319 SetBytecodeOffsetRaw(i, Smi::FromInt(value.ToInt())); 1320} 1321 1322int DeoptimizationData::DeoptCount() { 1323 return (length() - kFirstDeoptEntryIndex) / kDeoptEntrySize; 1324} 1325 1326inline DeoptimizationLiteralArray::DeoptimizationLiteralArray(Address ptr) 1327 : WeakFixedArray(ptr) { 1328 // No type check is possible beyond that for WeakFixedArray. 1329} 1330 1331inline Object DeoptimizationLiteralArray::get(int index) const { 1332 return get(GetPtrComprCageBase(*this), index); 1333} 1334 1335inline Object DeoptimizationLiteralArray::get(PtrComprCageBase cage_base, 1336 int index) const { 1337 MaybeObject maybe = Get(cage_base, index); 1338 1339 // Slots in the DeoptimizationLiteralArray should only be cleared when there 1340 // is no possible code path that could need that slot. This works because the 1341 // weakly-held deoptimization literals are basically local variables that 1342 // TurboFan has decided not to keep on the stack. Thus, if the deoptimization 1343 // literal goes away, then whatever code needed it should be unreachable. The 1344 // exception is currently running Code: in that case, the deoptimization 1345 // literals array might be the only thing keeping the target object alive. 1346 // Thus, when a Code is running, we strongly mark all of its deoptimization 1347 // literals. 1348 CHECK(!maybe.IsCleared()); 1349 1350 return maybe.GetHeapObjectOrSmi(); 1351} 1352 1353inline void DeoptimizationLiteralArray::set(int index, Object value) { 1354 MaybeObject maybe = MaybeObject::FromObject(value); 1355 if (Code::IsWeakObjectInDeoptimizationLiteralArray(value)) { 1356 maybe = MaybeObject::MakeWeak(maybe); 1357 } 1358 Set(index, maybe); 1359} 1360 1361} // namespace internal 1362} // namespace v8 1363 1364#include "src/objects/object-macros-undef.h" 1365 1366#endif // V8_OBJECTS_CODE_INL_H_ 1367