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/objects/code.h" 9 10 #include "src/interpreter/bytecode-register.h" 11 #include "src/isolate.h" 12 #include "src/objects/dictionary.h" 13 #include "src/objects/map-inl.h" 14 #include "src/objects/maybe-object-inl.h" 15 #include "src/v8memory.h" 16 17 // Has to be the last include (doesn't have include guards): 18 #include "src/objects/object-macros.h" 19 20 namespace v8 { 21 namespace internal { 22 23 CAST_ACCESSOR(AbstractCode) 24 CAST_ACCESSOR(BytecodeArray) 25 CAST_ACCESSOR(Code) 26 CAST_ACCESSOR(CodeDataContainer) 27 CAST_ACCESSOR(DependentCode) 28 CAST_ACCESSOR(DeoptimizationData) 29 30 int AbstractCode::raw_instruction_size() { 31 if (IsCode()) { 32 return GetCode()->raw_instruction_size(); 33 } else { 34 return GetBytecodeArray()->length(); 35 } 36 } 37 38 int AbstractCode::InstructionSize() { 39 if (IsCode()) { 40 return GetCode()->InstructionSize(); 41 } else { 42 return GetBytecodeArray()->length(); 43 } 44 } 45 46 ByteArray* AbstractCode::source_position_table() { 47 if (IsCode()) { 48 return GetCode()->SourcePositionTable(); 49 } else { 50 return GetBytecodeArray()->SourcePositionTable(); 51 } 52 } 53 54 Object* AbstractCode::stack_frame_cache() { 55 Object* maybe_table; 56 if (IsCode()) { 57 maybe_table = GetCode()->source_position_table(); 58 } else { 59 maybe_table = GetBytecodeArray()->source_position_table(); 60 } 61 if (maybe_table->IsSourcePositionTableWithFrameCache()) { 62 return SourcePositionTableWithFrameCache::cast(maybe_table) 63 ->stack_frame_cache(); 64 } 65 return Smi::kZero; 66 } 67 68 int AbstractCode::SizeIncludingMetadata() { 69 if (IsCode()) { 70 return GetCode()->SizeIncludingMetadata(); 71 } else { 72 return GetBytecodeArray()->SizeIncludingMetadata(); 73 } 74 } 75 int AbstractCode::ExecutableSize() { 76 if (IsCode()) { 77 return GetCode()->ExecutableSize(); 78 } else { 79 return GetBytecodeArray()->BytecodeArraySize(); 80 } 81 } 82 83 Address AbstractCode::raw_instruction_start() { 84 if (IsCode()) { 85 return GetCode()->raw_instruction_start(); 86 } else { 87 return GetBytecodeArray()->GetFirstBytecodeAddress(); 88 } 89 } 90 91 Address AbstractCode::InstructionStart() { 92 if (IsCode()) { 93 return GetCode()->InstructionStart(); 94 } else { 95 return GetBytecodeArray()->GetFirstBytecodeAddress(); 96 } 97 } 98 99 Address AbstractCode::raw_instruction_end() { 100 if (IsCode()) { 101 return GetCode()->raw_instruction_end(); 102 } else { 103 return GetBytecodeArray()->GetFirstBytecodeAddress() + 104 GetBytecodeArray()->length(); 105 } 106 } 107 108 Address AbstractCode::InstructionEnd() { 109 if (IsCode()) { 110 return GetCode()->InstructionEnd(); 111 } else { 112 return GetBytecodeArray()->GetFirstBytecodeAddress() + 113 GetBytecodeArray()->length(); 114 } 115 } 116 117 bool AbstractCode::contains(Address inner_pointer) { 118 return (address() <= inner_pointer) && (inner_pointer <= address() + Size()); 119 } 120 121 AbstractCode::Kind AbstractCode::kind() { 122 if (IsCode()) { 123 return static_cast<AbstractCode::Kind>(GetCode()->kind()); 124 } else { 125 return INTERPRETED_FUNCTION; 126 } 127 } 128 129 Code* AbstractCode::GetCode() { return Code::cast(this); } 130 131 BytecodeArray* AbstractCode::GetBytecodeArray() { 132 return BytecodeArray::cast(this); 133 } 134 135 DependentCode* DependentCode::next_link() { 136 return DependentCode::cast(Get(kNextLinkIndex)->ToStrongHeapObject()); 137 } 138 139 void DependentCode::set_next_link(DependentCode* next) { 140 Set(kNextLinkIndex, HeapObjectReference::Strong(next)); 141 } 142 143 int DependentCode::flags() { return Smi::ToInt(Get(kFlagsIndex)->ToSmi()); } 144 145 void DependentCode::set_flags(int flags) { 146 Set(kFlagsIndex, MaybeObject::FromObject(Smi::FromInt(flags))); 147 } 148 149 int DependentCode::count() { return CountField::decode(flags()); } 150 151 void DependentCode::set_count(int value) { 152 set_flags(CountField::update(flags(), value)); 153 } 154 155 DependentCode::DependencyGroup DependentCode::group() { 156 return static_cast<DependencyGroup>(GroupField::decode(flags())); 157 } 158 159 void DependentCode::set_object_at(int i, MaybeObject* object) { 160 Set(kCodesStartIndex + i, object); 161 } 162 163 MaybeObject* DependentCode::object_at(int i) { 164 return Get(kCodesStartIndex + i); 165 } 166 167 void DependentCode::clear_at(int i) { 168 Set(kCodesStartIndex + i, 169 HeapObjectReference::Strong(GetReadOnlyRoots().undefined_value())); 170 } 171 172 void DependentCode::copy(int from, int to) { 173 Set(kCodesStartIndex + to, Get(kCodesStartIndex + from)); 174 } 175 176 INT_ACCESSORS(Code, raw_instruction_size, kInstructionSizeOffset) 177 INT_ACCESSORS(Code, handler_table_offset, kHandlerTableOffsetOffset) 178 #define CODE_ACCESSORS(name, type, offset) \ 179 ACCESSORS_CHECKED2(Code, name, type, offset, true, !Heap::InNewSpace(value)) 180 CODE_ACCESSORS(relocation_info, ByteArray, kRelocationInfoOffset) 181 CODE_ACCESSORS(deoptimization_data, FixedArray, kDeoptimizationDataOffset) 182 CODE_ACCESSORS(source_position_table, Object, kSourcePositionTableOffset) 183 CODE_ACCESSORS(code_data_container, CodeDataContainer, kCodeDataContainerOffset) 184 #undef CODE_ACCESSORS 185 186 void Code::WipeOutHeader() { 187 WRITE_FIELD(this, kRelocationInfoOffset, nullptr); 188 WRITE_FIELD(this, kDeoptimizationDataOffset, nullptr); 189 WRITE_FIELD(this, kSourcePositionTableOffset, nullptr); 190 WRITE_FIELD(this, kCodeDataContainerOffset, nullptr); 191 } 192 193 void Code::clear_padding() { 194 memset(reinterpret_cast<void*>(address() + kHeaderPaddingStart), 0, 195 kHeaderSize - kHeaderPaddingStart); 196 Address data_end = 197 has_unwinding_info() ? unwinding_info_end() : raw_instruction_end(); 198 memset(reinterpret_cast<void*>(data_end), 0, 199 CodeSize() - (data_end - address())); 200 } 201 202 ByteArray* Code::SourcePositionTable() const { 203 Object* maybe_table = source_position_table(); 204 if (maybe_table->IsByteArray()) return ByteArray::cast(maybe_table); 205 DCHECK(maybe_table->IsSourcePositionTableWithFrameCache()); 206 return SourcePositionTableWithFrameCache::cast(maybe_table) 207 ->source_position_table(); 208 } 209 210 uint32_t Code::stub_key() const { 211 DCHECK(is_stub()); 212 return READ_UINT32_FIELD(this, kStubKeyOffset); 213 } 214 215 void Code::set_stub_key(uint32_t key) { 216 DCHECK(is_stub() || key == 0); // Allow zero initialization. 217 WRITE_UINT32_FIELD(this, kStubKeyOffset, key); 218 } 219 220 Object* Code::next_code_link() const { 221 return code_data_container()->next_code_link(); 222 } 223 224 void Code::set_next_code_link(Object* value) { 225 code_data_container()->set_next_code_link(value); 226 } 227 228 int Code::InstructionSize() const { 229 if (is_off_heap_trampoline()) { 230 DCHECK(FLAG_embedded_builtins); 231 return OffHeapInstructionSize(); 232 } 233 return raw_instruction_size(); 234 } 235 236 Address Code::raw_instruction_start() const { 237 return FIELD_ADDR(this, kHeaderSize); 238 } 239 240 Address Code::InstructionStart() const { 241 if (is_off_heap_trampoline()) { 242 DCHECK(FLAG_embedded_builtins); 243 return OffHeapInstructionStart(); 244 } 245 return raw_instruction_start(); 246 } 247 248 Address Code::raw_instruction_end() const { 249 return raw_instruction_start() + raw_instruction_size(); 250 } 251 252 Address Code::InstructionEnd() const { 253 if (is_off_heap_trampoline()) { 254 DCHECK(FLAG_embedded_builtins); 255 return OffHeapInstructionEnd(); 256 } 257 return raw_instruction_end(); 258 } 259 260 int Code::GetUnwindingInfoSizeOffset() const { 261 DCHECK(has_unwinding_info()); 262 return RoundUp(kHeaderSize + raw_instruction_size(), kInt64Size); 263 } 264 265 int Code::unwinding_info_size() const { 266 DCHECK(has_unwinding_info()); 267 return static_cast<int>( 268 READ_UINT64_FIELD(this, GetUnwindingInfoSizeOffset())); 269 } 270 271 void Code::set_unwinding_info_size(int value) { 272 DCHECK(has_unwinding_info()); 273 WRITE_UINT64_FIELD(this, GetUnwindingInfoSizeOffset(), value); 274 } 275 276 Address Code::unwinding_info_start() const { 277 DCHECK(has_unwinding_info()); 278 return FIELD_ADDR(this, GetUnwindingInfoSizeOffset()) + kInt64Size; 279 } 280 281 Address Code::unwinding_info_end() const { 282 DCHECK(has_unwinding_info()); 283 return unwinding_info_start() + unwinding_info_size(); 284 } 285 286 int Code::body_size() const { 287 int unpadded_body_size = 288 has_unwinding_info() 289 ? static_cast<int>(unwinding_info_end() - raw_instruction_start()) 290 : raw_instruction_size(); 291 return RoundUp(unpadded_body_size, kObjectAlignment); 292 } 293 294 int Code::SizeIncludingMetadata() const { 295 int size = CodeSize(); 296 size += relocation_info()->Size(); 297 size += deoptimization_data()->Size(); 298 return size; 299 } 300 301 ByteArray* Code::unchecked_relocation_info() const { 302 return reinterpret_cast<ByteArray*>(READ_FIELD(this, kRelocationInfoOffset)); 303 } 304 305 byte* Code::relocation_start() const { 306 return unchecked_relocation_info()->GetDataStartAddress(); 307 } 308 309 byte* Code::relocation_end() const { 310 return unchecked_relocation_info()->GetDataStartAddress() + 311 unchecked_relocation_info()->length(); 312 } 313 314 int Code::relocation_size() const { 315 return unchecked_relocation_info()->length(); 316 } 317 318 Address Code::entry() const { return raw_instruction_start(); } 319 320 bool Code::contains(Address inner_pointer) { 321 if (is_off_heap_trampoline()) { 322 DCHECK(FLAG_embedded_builtins); 323 if (OffHeapInstructionStart() <= inner_pointer && 324 inner_pointer < OffHeapInstructionEnd()) { 325 return true; 326 } 327 } 328 return (address() <= inner_pointer) && (inner_pointer < address() + Size()); 329 } 330 331 int Code::ExecutableSize() const { 332 // Check that the assumptions about the layout of the code object holds. 333 DCHECK_EQ(static_cast<int>(raw_instruction_start() - address()), 334 Code::kHeaderSize); 335 return raw_instruction_size() + Code::kHeaderSize; 336 } 337 338 int Code::CodeSize() const { return SizeFor(body_size()); } 339 340 Code::Kind Code::kind() const { 341 return KindField::decode(READ_UINT32_FIELD(this, kFlagsOffset)); 342 } 343 344 void Code::initialize_flags(Kind kind, bool has_unwinding_info, 345 bool is_turbofanned, int stack_slots, 346 bool is_off_heap_trampoline) { 347 CHECK(0 <= stack_slots && stack_slots < StackSlotsField::kMax); 348 static_assert(Code::NUMBER_OF_KINDS <= KindField::kMax + 1, "field overflow"); 349 uint32_t flags = HasUnwindingInfoField::encode(has_unwinding_info) | 350 KindField::encode(kind) | 351 IsTurbofannedField::encode(is_turbofanned) | 352 StackSlotsField::encode(stack_slots) | 353 IsOffHeapTrampoline::encode(is_off_heap_trampoline); 354 WRITE_UINT32_FIELD(this, kFlagsOffset, flags); 355 DCHECK_IMPLIES(stack_slots != 0, has_safepoint_info()); 356 } 357 358 inline bool Code::is_interpreter_trampoline_builtin() const { 359 Builtins* builtins = GetIsolate()->builtins(); 360 Code* interpreter_entry_trampoline = 361 builtins->builtin(Builtins::kInterpreterEntryTrampoline); 362 bool is_interpreter_trampoline = 363 (builtin_index() == interpreter_entry_trampoline->builtin_index() || 364 this == builtins->builtin(Builtins::kInterpreterEnterBytecodeAdvance) || 365 this == builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch)); 366 DCHECK_IMPLIES(is_interpreter_trampoline, !Builtins::IsLazy(builtin_index())); 367 return is_interpreter_trampoline; 368 } 369 370 inline bool Code::checks_optimization_marker() const { 371 Builtins* builtins = GetIsolate()->builtins(); 372 Code* interpreter_entry_trampoline = 373 builtins->builtin(Builtins::kInterpreterEntryTrampoline); 374 bool checks_marker = 375 (this == builtins->builtin(Builtins::kCompileLazy) || 376 builtin_index() == interpreter_entry_trampoline->builtin_index()); 377 DCHECK_IMPLIES(checks_marker, !Builtins::IsLazy(builtin_index())); 378 return checks_marker || 379 (kind() == OPTIMIZED_FUNCTION && marked_for_deoptimization()); 380 } 381 382 inline bool Code::has_tagged_params() const { 383 return kind() != JS_TO_WASM_FUNCTION && kind() != C_WASM_ENTRY && 384 kind() != WASM_FUNCTION; 385 } 386 387 inline bool Code::has_unwinding_info() const { 388 return HasUnwindingInfoField::decode(READ_UINT32_FIELD(this, kFlagsOffset)); 389 } 390 391 inline bool Code::is_turbofanned() const { 392 return IsTurbofannedField::decode(READ_UINT32_FIELD(this, kFlagsOffset)); 393 } 394 395 inline bool Code::can_have_weak_objects() const { 396 DCHECK(kind() == OPTIMIZED_FUNCTION); 397 int flags = code_data_container()->kind_specific_flags(); 398 return CanHaveWeakObjectsField::decode(flags); 399 } 400 401 inline void Code::set_can_have_weak_objects(bool value) { 402 DCHECK(kind() == OPTIMIZED_FUNCTION); 403 int previous = code_data_container()->kind_specific_flags(); 404 int updated = CanHaveWeakObjectsField::update(previous, value); 405 code_data_container()->set_kind_specific_flags(updated); 406 } 407 408 inline bool Code::is_construct_stub() const { 409 DCHECK(kind() == BUILTIN); 410 int flags = code_data_container()->kind_specific_flags(); 411 return IsConstructStubField::decode(flags); 412 } 413 414 inline void Code::set_is_construct_stub(bool value) { 415 DCHECK(kind() == BUILTIN); 416 int previous = code_data_container()->kind_specific_flags(); 417 int updated = IsConstructStubField::update(previous, value); 418 code_data_container()->set_kind_specific_flags(updated); 419 } 420 421 inline bool Code::is_promise_rejection() const { 422 DCHECK(kind() == BUILTIN); 423 int flags = code_data_container()->kind_specific_flags(); 424 return IsPromiseRejectionField::decode(flags); 425 } 426 427 inline void Code::set_is_promise_rejection(bool value) { 428 DCHECK(kind() == BUILTIN); 429 int previous = code_data_container()->kind_specific_flags(); 430 int updated = IsPromiseRejectionField::update(previous, value); 431 code_data_container()->set_kind_specific_flags(updated); 432 } 433 434 inline bool Code::is_exception_caught() const { 435 DCHECK(kind() == BUILTIN); 436 int flags = code_data_container()->kind_specific_flags(); 437 return IsExceptionCaughtField::decode(flags); 438 } 439 440 inline void Code::set_is_exception_caught(bool value) { 441 DCHECK(kind() == BUILTIN); 442 int previous = code_data_container()->kind_specific_flags(); 443 int updated = IsExceptionCaughtField::update(previous, value); 444 code_data_container()->set_kind_specific_flags(updated); 445 } 446 447 inline bool Code::is_off_heap_trampoline() const { 448 return IsOffHeapTrampoline::decode(READ_UINT32_FIELD(this, kFlagsOffset)); 449 } 450 451 inline HandlerTable::CatchPrediction Code::GetBuiltinCatchPrediction() { 452 if (is_promise_rejection()) return HandlerTable::PROMISE; 453 if (is_exception_caught()) return HandlerTable::CAUGHT; 454 return HandlerTable::UNCAUGHT; 455 } 456 457 int Code::builtin_index() const { 458 int index = READ_INT_FIELD(this, kBuiltinIndexOffset); 459 DCHECK(index == -1 || Builtins::IsBuiltinId(index)); 460 return index; 461 } 462 463 void Code::set_builtin_index(int index) { 464 DCHECK(index == -1 || Builtins::IsBuiltinId(index)); 465 WRITE_INT_FIELD(this, kBuiltinIndexOffset, index); 466 } 467 468 bool Code::is_builtin() const { return builtin_index() != -1; } 469 470 bool Code::has_safepoint_info() const { 471 return is_turbofanned() || is_wasm_code(); 472 } 473 474 int Code::stack_slots() const { 475 DCHECK(has_safepoint_info()); 476 return StackSlotsField::decode(READ_UINT32_FIELD(this, kFlagsOffset)); 477 } 478 479 int Code::safepoint_table_offset() const { 480 DCHECK(has_safepoint_info()); 481 return READ_INT32_FIELD(this, kSafepointTableOffsetOffset); 482 } 483 484 void Code::set_safepoint_table_offset(int offset) { 485 CHECK_LE(0, offset); 486 DCHECK(has_safepoint_info() || offset == 0); // Allow zero initialization. 487 DCHECK(IsAligned(offset, static_cast<unsigned>(kIntSize))); 488 WRITE_INT32_FIELD(this, kSafepointTableOffsetOffset, offset); 489 } 490 491 bool Code::marked_for_deoptimization() const { 492 DCHECK(kind() == OPTIMIZED_FUNCTION); 493 int flags = code_data_container()->kind_specific_flags(); 494 return MarkedForDeoptimizationField::decode(flags); 495 } 496 497 void Code::set_marked_for_deoptimization(bool flag) { 498 DCHECK(kind() == OPTIMIZED_FUNCTION); 499 DCHECK_IMPLIES(flag, AllowDeoptimization::IsAllowed(GetIsolate())); 500 int previous = code_data_container()->kind_specific_flags(); 501 int updated = MarkedForDeoptimizationField::update(previous, flag); 502 code_data_container()->set_kind_specific_flags(updated); 503 } 504 505 bool Code::deopt_already_counted() const { 506 DCHECK(kind() == OPTIMIZED_FUNCTION); 507 int flags = code_data_container()->kind_specific_flags(); 508 return DeoptAlreadyCountedField::decode(flags); 509 } 510 511 void Code::set_deopt_already_counted(bool flag) { 512 DCHECK(kind() == OPTIMIZED_FUNCTION); 513 DCHECK_IMPLIES(flag, AllowDeoptimization::IsAllowed(GetIsolate())); 514 int previous = code_data_container()->kind_specific_flags(); 515 int updated = DeoptAlreadyCountedField::update(previous, flag); 516 code_data_container()->set_kind_specific_flags(updated); 517 } 518 519 bool Code::is_stub() const { return kind() == STUB; } 520 bool Code::is_optimized_code() const { return kind() == OPTIMIZED_FUNCTION; } 521 bool Code::is_wasm_code() const { return kind() == WASM_FUNCTION; } 522 523 int Code::constant_pool_offset() const { 524 if (!FLAG_enable_embedded_constant_pool) return InstructionSize(); 525 return READ_INT_FIELD(this, kConstantPoolOffset); 526 } 527 528 void Code::set_constant_pool_offset(int value) { 529 if (!FLAG_enable_embedded_constant_pool) return; 530 WRITE_INT_FIELD(this, kConstantPoolOffset, value); 531 } 532 533 Address Code::constant_pool() const { 534 if (FLAG_enable_embedded_constant_pool) { 535 int offset = constant_pool_offset(); 536 if (offset < InstructionSize()) { 537 return InstructionStart() + offset; 538 } 539 } 540 return kNullAddress; 541 } 542 543 Code* Code::GetCodeFromTargetAddress(Address address) { 544 { 545 // TODO(jgruber,v8:6666): Support embedded builtins here. We'd need to pass 546 // in the current isolate. 547 Address start = reinterpret_cast<Address>(Isolate::CurrentEmbeddedBlob()); 548 Address end = start + Isolate::CurrentEmbeddedBlobSize(); 549 CHECK(address < start || address >= end); 550 } 551 552 HeapObject* code = HeapObject::FromAddress(address - Code::kHeaderSize); 553 // GetCodeFromTargetAddress might be called when marking objects during mark 554 // sweep. reinterpret_cast is therefore used instead of the more appropriate 555 // Code::cast. Code::cast does not work when the object's map is 556 // marked. 557 Code* result = reinterpret_cast<Code*>(code); 558 return result; 559 } 560 561 Object* Code::GetObjectFromCodeEntry(Address code_entry) { 562 return HeapObject::FromAddress(code_entry - Code::kHeaderSize); 563 } 564 565 Object* Code::GetObjectFromEntryAddress(Address location_of_address) { 566 return GetObjectFromCodeEntry(Memory<Address>(location_of_address)); 567 } 568 569 bool Code::CanContainWeakObjects() { 570 return is_optimized_code() && can_have_weak_objects(); 571 } 572 573 bool Code::IsWeakObject(Object* object) { 574 return (CanContainWeakObjects() && IsWeakObjectInOptimizedCode(object)); 575 } 576 577 bool Code::IsWeakObjectInOptimizedCode(Object* object) { 578 if (object->IsMap()) { 579 return Map::cast(object)->CanTransition(); 580 } 581 if (object->IsCell()) { 582 object = Cell::cast(object)->value(); 583 } else if (object->IsPropertyCell()) { 584 object = PropertyCell::cast(object)->value(); 585 } 586 if (object->IsJSReceiver() || object->IsContext()) { 587 return true; 588 } 589 return false; 590 } 591 592 INT_ACCESSORS(CodeDataContainer, kind_specific_flags, kKindSpecificFlagsOffset) 593 ACCESSORS(CodeDataContainer, next_code_link, Object, kNextCodeLinkOffset) 594 595 void CodeDataContainer::clear_padding() { 596 memset(reinterpret_cast<void*>(address() + kUnalignedSize), 0, 597 kSize - kUnalignedSize); 598 } 599 600 byte BytecodeArray::get(int index) { 601 DCHECK(index >= 0 && index < this->length()); 602 return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); 603 } 604 605 void BytecodeArray::set(int index, byte value) { 606 DCHECK(index >= 0 && index < this->length()); 607 WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value); 608 } 609 610 void BytecodeArray::set_frame_size(int frame_size) { 611 DCHECK_GE(frame_size, 0); 612 DCHECK(IsAligned(frame_size, static_cast<unsigned>(kPointerSize))); 613 WRITE_INT_FIELD(this, kFrameSizeOffset, frame_size); 614 } 615 616 int BytecodeArray::frame_size() const { 617 return READ_INT_FIELD(this, kFrameSizeOffset); 618 } 619 620 int BytecodeArray::register_count() const { 621 return frame_size() / kPointerSize; 622 } 623 624 void BytecodeArray::set_parameter_count(int number_of_parameters) { 625 DCHECK_GE(number_of_parameters, 0); 626 // Parameter count is stored as the size on stack of the parameters to allow 627 // it to be used directly by generated code. 628 WRITE_INT_FIELD(this, kParameterSizeOffset, 629 (number_of_parameters << kPointerSizeLog2)); 630 } 631 632 interpreter::Register BytecodeArray::incoming_new_target_or_generator_register() 633 const { 634 int register_operand = 635 READ_INT_FIELD(this, kIncomingNewTargetOrGeneratorRegisterOffset); 636 if (register_operand == 0) { 637 return interpreter::Register::invalid_value(); 638 } else { 639 return interpreter::Register::FromOperand(register_operand); 640 } 641 } 642 643 void BytecodeArray::set_incoming_new_target_or_generator_register( 644 interpreter::Register incoming_new_target_or_generator_register) { 645 if (!incoming_new_target_or_generator_register.is_valid()) { 646 WRITE_INT_FIELD(this, kIncomingNewTargetOrGeneratorRegisterOffset, 0); 647 } else { 648 DCHECK(incoming_new_target_or_generator_register.index() < 649 register_count()); 650 DCHECK_NE(0, incoming_new_target_or_generator_register.ToOperand()); 651 WRITE_INT_FIELD(this, kIncomingNewTargetOrGeneratorRegisterOffset, 652 incoming_new_target_or_generator_register.ToOperand()); 653 } 654 } 655 656 int BytecodeArray::interrupt_budget() const { 657 return READ_INT_FIELD(this, kInterruptBudgetOffset); 658 } 659 660 void BytecodeArray::set_interrupt_budget(int interrupt_budget) { 661 DCHECK_GE(interrupt_budget, 0); 662 WRITE_INT_FIELD(this, kInterruptBudgetOffset, interrupt_budget); 663 } 664 665 int BytecodeArray::osr_loop_nesting_level() const { 666 return READ_INT8_FIELD(this, kOSRNestingLevelOffset); 667 } 668 669 void BytecodeArray::set_osr_loop_nesting_level(int depth) { 670 DCHECK(0 <= depth && depth <= AbstractCode::kMaxLoopNestingMarker); 671 STATIC_ASSERT(AbstractCode::kMaxLoopNestingMarker < kMaxInt8); 672 WRITE_INT8_FIELD(this, kOSRNestingLevelOffset, depth); 673 } 674 675 BytecodeArray::Age BytecodeArray::bytecode_age() const { 676 // Bytecode is aged by the concurrent marker. 677 return static_cast<Age>(RELAXED_READ_INT8_FIELD(this, kBytecodeAgeOffset)); 678 } 679 680 void BytecodeArray::set_bytecode_age(BytecodeArray::Age age) { 681 DCHECK_GE(age, kFirstBytecodeAge); 682 DCHECK_LE(age, kLastBytecodeAge); 683 STATIC_ASSERT(kLastBytecodeAge <= kMaxInt8); 684 // Bytecode is aged by the concurrent marker. 685 RELAXED_WRITE_INT8_FIELD(this, kBytecodeAgeOffset, static_cast<int8_t>(age)); 686 } 687 688 int BytecodeArray::parameter_count() const { 689 // Parameter count is stored as the size on stack of the parameters to allow 690 // it to be used directly by generated code. 691 return READ_INT_FIELD(this, kParameterSizeOffset) >> kPointerSizeLog2; 692 } 693 694 ACCESSORS(BytecodeArray, constant_pool, FixedArray, kConstantPoolOffset) 695 ACCESSORS(BytecodeArray, handler_table, ByteArray, kHandlerTableOffset) 696 ACCESSORS(BytecodeArray, source_position_table, Object, 697 kSourcePositionTableOffset) 698 699 void BytecodeArray::clear_padding() { 700 int data_size = kHeaderSize + length(); 701 memset(reinterpret_cast<void*>(address() + data_size), 0, 702 SizeFor(length()) - data_size); 703 } 704 705 Address BytecodeArray::GetFirstBytecodeAddress() { 706 return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize; 707 } 708 709 ByteArray* BytecodeArray::SourcePositionTable() { 710 Object* maybe_table = source_position_table(); 711 if (maybe_table->IsByteArray()) return ByteArray::cast(maybe_table); 712 DCHECK(maybe_table->IsSourcePositionTableWithFrameCache()); 713 return SourcePositionTableWithFrameCache::cast(maybe_table) 714 ->source_position_table(); 715 } 716 717 void BytecodeArray::ClearFrameCacheFromSourcePositionTable() { 718 Object* maybe_table = source_position_table(); 719 if (maybe_table->IsByteArray()) return; 720 DCHECK(maybe_table->IsSourcePositionTableWithFrameCache()); 721 set_source_position_table(SourcePositionTableWithFrameCache::cast(maybe_table) 722 ->source_position_table()); 723 } 724 725 int BytecodeArray::BytecodeArraySize() { return SizeFor(this->length()); } 726 727 int BytecodeArray::SizeIncludingMetadata() { 728 int size = BytecodeArraySize(); 729 size += constant_pool()->Size(); 730 size += handler_table()->Size(); 731 size += SourcePositionTable()->Size(); 732 return size; 733 } 734 735 BailoutId DeoptimizationData::BytecodeOffset(int i) { 736 return BailoutId(BytecodeOffsetRaw(i)->value()); 737 } 738 739 void DeoptimizationData::SetBytecodeOffset(int i, BailoutId value) { 740 SetBytecodeOffsetRaw(i, Smi::FromInt(value.ToInt())); 741 } 742 743 int DeoptimizationData::DeoptCount() { 744 return (length() - kFirstDeoptEntryIndex) / kDeoptEntrySize; 745 } 746 747 } // namespace internal 748 } // namespace v8 749 750 #include "src/objects/object-macros-undef.h" 751 752 #endif // V8_OBJECTS_CODE_INL_H_ 753