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)
CAST_ACCESSOR(BytecodeArray)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 
InstructionSize()38 int AbstractCode::InstructionSize() {
39   if (IsCode()) {
40     return GetCode()->InstructionSize();
41   } else {
42     return GetBytecodeArray()->length();
43   }
44 }
45 
source_position_table()46 ByteArray* AbstractCode::source_position_table() {
47   if (IsCode()) {
48     return GetCode()->SourcePositionTable();
49   } else {
50     return GetBytecodeArray()->SourcePositionTable();
51   }
52 }
53 
stack_frame_cache()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 
SizeIncludingMetadata()68 int AbstractCode::SizeIncludingMetadata() {
69   if (IsCode()) {
70     return GetCode()->SizeIncludingMetadata();
71   } else {
72     return GetBytecodeArray()->SizeIncludingMetadata();
73   }
74 }
ExecutableSize()75 int AbstractCode::ExecutableSize() {
76   if (IsCode()) {
77     return GetCode()->ExecutableSize();
78   } else {
79     return GetBytecodeArray()->BytecodeArraySize();
80   }
81 }
82 
raw_instruction_start()83 Address AbstractCode::raw_instruction_start() {
84   if (IsCode()) {
85     return GetCode()->raw_instruction_start();
86   } else {
87     return GetBytecodeArray()->GetFirstBytecodeAddress();
88   }
89 }
90 
InstructionStart()91 Address AbstractCode::InstructionStart() {
92   if (IsCode()) {
93     return GetCode()->InstructionStart();
94   } else {
95     return GetBytecodeArray()->GetFirstBytecodeAddress();
96   }
97 }
98 
raw_instruction_end()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 
InstructionEnd()108 Address AbstractCode::InstructionEnd() {
109   if (IsCode()) {
110     return GetCode()->InstructionEnd();
111   } else {
112     return GetBytecodeArray()->GetFirstBytecodeAddress() +
113            GetBytecodeArray()->length();
114   }
115 }
116 
contains(Address inner_pointer)117 bool AbstractCode::contains(Address inner_pointer) {
118   return (address() <= inner_pointer) && (inner_pointer <= address() + Size());
119 }
120 
kind()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 
GetCode()129 Code* AbstractCode::GetCode() { return Code::cast(this); }
130 
GetBytecodeArray()131 BytecodeArray* AbstractCode::GetBytecodeArray() {
132   return BytecodeArray::cast(this);
133 }
134 
next_link()135 DependentCode* DependentCode::next_link() {
136   return DependentCode::cast(Get(kNextLinkIndex)->ToStrongHeapObject());
137 }
138 
set_next_link(DependentCode * next)139 void DependentCode::set_next_link(DependentCode* next) {
140   Set(kNextLinkIndex, HeapObjectReference::Strong(next));
141 }
142 
flags()143 int DependentCode::flags() { return Smi::ToInt(Get(kFlagsIndex)->ToSmi()); }
144 
set_flags(int flags)145 void DependentCode::set_flags(int flags) {
146   Set(kFlagsIndex, MaybeObject::FromObject(Smi::FromInt(flags)));
147 }
148 
count()149 int DependentCode::count() { return CountField::decode(flags()); }
150 
set_count(int value)151 void DependentCode::set_count(int value) {
152   set_flags(CountField::update(flags(), value));
153 }
154 
group()155 DependentCode::DependencyGroup DependentCode::group() {
156   return static_cast<DependencyGroup>(GroupField::decode(flags()));
157 }
158 
set_object_at(int i,MaybeObject * object)159 void DependentCode::set_object_at(int i, MaybeObject* object) {
160   Set(kCodesStartIndex + i, object);
161 }
162 
object_at(int i)163 MaybeObject* DependentCode::object_at(int i) {
164   return Get(kCodesStartIndex + i);
165 }
166 
clear_at(int i)167 void DependentCode::clear_at(int i) {
168   Set(kCodesStartIndex + i,
169       HeapObjectReference::Strong(GetReadOnlyRoots().undefined_value()));
170 }
171 
copy(int from,int to)172 void DependentCode::copy(int from, int to) {
173   Set(kCodesStartIndex + to, Get(kCodesStartIndex + from));
174 }
175 
INT_ACCESSORS(Code,raw_instruction_size,kInstructionSizeOffset)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 
clear_padding()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 
SourcePositionTable()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 
stub_key()210 uint32_t Code::stub_key() const {
211   DCHECK(is_stub());
212   return READ_UINT32_FIELD(this, kStubKeyOffset);
213 }
214 
set_stub_key(uint32_t key)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 
next_code_link()220 Object* Code::next_code_link() const {
221   return code_data_container()->next_code_link();
222 }
223 
set_next_code_link(Object * value)224 void Code::set_next_code_link(Object* value) {
225   code_data_container()->set_next_code_link(value);
226 }
227 
InstructionSize()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 
raw_instruction_start()236 Address Code::raw_instruction_start() const {
237   return FIELD_ADDR(this, kHeaderSize);
238 }
239 
InstructionStart()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 
raw_instruction_end()248 Address Code::raw_instruction_end() const {
249   return raw_instruction_start() + raw_instruction_size();
250 }
251 
InstructionEnd()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 
GetUnwindingInfoSizeOffset()260 int Code::GetUnwindingInfoSizeOffset() const {
261   DCHECK(has_unwinding_info());
262   return RoundUp(kHeaderSize + raw_instruction_size(), kInt64Size);
263 }
264 
unwinding_info_size()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 
set_unwinding_info_size(int value)271 void Code::set_unwinding_info_size(int value) {
272   DCHECK(has_unwinding_info());
273   WRITE_UINT64_FIELD(this, GetUnwindingInfoSizeOffset(), value);
274 }
275 
unwinding_info_start()276 Address Code::unwinding_info_start() const {
277   DCHECK(has_unwinding_info());
278   return FIELD_ADDR(this, GetUnwindingInfoSizeOffset()) + kInt64Size;
279 }
280 
unwinding_info_end()281 Address Code::unwinding_info_end() const {
282   DCHECK(has_unwinding_info());
283   return unwinding_info_start() + unwinding_info_size();
284 }
285 
body_size()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 
SizeIncludingMetadata()294 int Code::SizeIncludingMetadata() const {
295   int size = CodeSize();
296   size += relocation_info()->Size();
297   size += deoptimization_data()->Size();
298   return size;
299 }
300 
unchecked_relocation_info()301 ByteArray* Code::unchecked_relocation_info() const {
302   return reinterpret_cast<ByteArray*>(READ_FIELD(this, kRelocationInfoOffset));
303 }
304 
relocation_start()305 byte* Code::relocation_start() const {
306   return unchecked_relocation_info()->GetDataStartAddress();
307 }
308 
relocation_end()309 byte* Code::relocation_end() const {
310   return unchecked_relocation_info()->GetDataStartAddress() +
311          unchecked_relocation_info()->length();
312 }
313 
relocation_size()314 int Code::relocation_size() const {
315   return unchecked_relocation_info()->length();
316 }
317 
entry()318 Address Code::entry() const { return raw_instruction_start(); }
319 
contains(Address inner_pointer)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 
ExecutableSize()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 
CodeSize()338 int Code::CodeSize() const { return SizeFor(body_size()); }
339 
kind()340 Code::Kind Code::kind() const {
341   return KindField::decode(READ_UINT32_FIELD(this, kFlagsOffset));
342 }
343 
initialize_flags(Kind kind,bool has_unwinding_info,bool is_turbofanned,int stack_slots,bool is_off_heap_trampoline)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 
is_interpreter_trampoline_builtin()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 
checks_optimization_marker()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 
has_tagged_params()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 
has_unwinding_info()387 inline bool Code::has_unwinding_info() const {
388   return HasUnwindingInfoField::decode(READ_UINT32_FIELD(this, kFlagsOffset));
389 }
390 
is_turbofanned()391 inline bool Code::is_turbofanned() const {
392   return IsTurbofannedField::decode(READ_UINT32_FIELD(this, kFlagsOffset));
393 }
394 
can_have_weak_objects()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 
set_can_have_weak_objects(bool value)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 
is_construct_stub()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 
set_is_construct_stub(bool value)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 
is_promise_rejection()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 
set_is_promise_rejection(bool value)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 
is_exception_caught()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 
set_is_exception_caught(bool value)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 
is_off_heap_trampoline()447 inline bool Code::is_off_heap_trampoline() const {
448   return IsOffHeapTrampoline::decode(READ_UINT32_FIELD(this, kFlagsOffset));
449 }
450 
GetBuiltinCatchPrediction()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 
builtin_index()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 
set_builtin_index(int index)463 void Code::set_builtin_index(int index) {
464   DCHECK(index == -1 || Builtins::IsBuiltinId(index));
465   WRITE_INT_FIELD(this, kBuiltinIndexOffset, index);
466 }
467 
is_builtin()468 bool Code::is_builtin() const { return builtin_index() != -1; }
469 
has_safepoint_info()470 bool Code::has_safepoint_info() const {
471   return is_turbofanned() || is_wasm_code();
472 }
473 
stack_slots()474 int Code::stack_slots() const {
475   DCHECK(has_safepoint_info());
476   return StackSlotsField::decode(READ_UINT32_FIELD(this, kFlagsOffset));
477 }
478 
safepoint_table_offset()479 int Code::safepoint_table_offset() const {
480   DCHECK(has_safepoint_info());
481   return READ_INT32_FIELD(this, kSafepointTableOffsetOffset);
482 }
483 
set_safepoint_table_offset(int offset)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 
marked_for_deoptimization()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 
set_marked_for_deoptimization(bool flag)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 
deopt_already_counted()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 
set_deopt_already_counted(bool flag)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 
is_stub()519 bool Code::is_stub() const { return kind() == STUB; }
is_optimized_code()520 bool Code::is_optimized_code() const { return kind() == OPTIMIZED_FUNCTION; }
is_wasm_code()521 bool Code::is_wasm_code() const { return kind() == WASM_FUNCTION; }
522 
constant_pool_offset()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 
set_constant_pool_offset(int value)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 
constant_pool()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 
GetCodeFromTargetAddress(Address address)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 
GetObjectFromCodeEntry(Address code_entry)561 Object* Code::GetObjectFromCodeEntry(Address code_entry) {
562   return HeapObject::FromAddress(code_entry - Code::kHeaderSize);
563 }
564 
GetObjectFromEntryAddress(Address location_of_address)565 Object* Code::GetObjectFromEntryAddress(Address location_of_address) {
566   return GetObjectFromCodeEntry(Memory<Address>(location_of_address));
567 }
568 
CanContainWeakObjects()569 bool Code::CanContainWeakObjects() {
570   return is_optimized_code() && can_have_weak_objects();
571 }
572 
IsWeakObject(Object * object)573 bool Code::IsWeakObject(Object* object) {
574   return (CanContainWeakObjects() && IsWeakObjectInOptimizedCode(object));
575 }
576 
IsWeakObjectInOptimizedCode(Object * object)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 
INT_ACCESSORS(CodeDataContainer,kind_specific_flags,kKindSpecificFlagsOffset)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 
get(int index)600 byte BytecodeArray::get(int index) {
601   DCHECK(index >= 0 && index < this->length());
602   return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
603 }
604 
set(int index,byte value)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 
set_frame_size(int frame_size)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 
frame_size()616 int BytecodeArray::frame_size() const {
617   return READ_INT_FIELD(this, kFrameSizeOffset);
618 }
619 
register_count()620 int BytecodeArray::register_count() const {
621   return frame_size() / kPointerSize;
622 }
623 
set_parameter_count(int number_of_parameters)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 
incoming_new_target_or_generator_register()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 
set_incoming_new_target_or_generator_register(interpreter::Register incoming_new_target_or_generator_register)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 
interrupt_budget()656 int BytecodeArray::interrupt_budget() const {
657   return READ_INT_FIELD(this, kInterruptBudgetOffset);
658 }
659 
set_interrupt_budget(int interrupt_budget)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 
osr_loop_nesting_level()665 int BytecodeArray::osr_loop_nesting_level() const {
666   return READ_INT8_FIELD(this, kOSRNestingLevelOffset);
667 }
668 
set_osr_loop_nesting_level(int depth)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 
bytecode_age()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 
set_bytecode_age(BytecodeArray::Age age)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 
parameter_count()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 
ACCESSORS(BytecodeArray,constant_pool,FixedArray,kConstantPoolOffset)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 
GetFirstBytecodeAddress()705 Address BytecodeArray::GetFirstBytecodeAddress() {
706   return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
707 }
708 
SourcePositionTable()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 
ClearFrameCacheFromSourcePositionTable()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 
BytecodeArraySize()725 int BytecodeArray::BytecodeArraySize() { return SizeFor(this->length()); }
726 
SizeIncludingMetadata()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 
BytecodeOffset(int i)735 BailoutId DeoptimizationData::BytecodeOffset(int i) {
736   return BailoutId(BytecodeOffsetRaw(i)->value());
737 }
738 
SetBytecodeOffset(int i,BailoutId value)739 void DeoptimizationData::SetBytecodeOffset(int i, BailoutId value) {
740   SetBytecodeOffsetRaw(i, Smi::FromInt(value.ToInt()));
741 }
742 
DeoptCount()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