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/base/memory.h"
11 #include "src/codegen/code-desc.h"
12 #include "src/execution/isolate.h"
13 #include "src/interpreter/bytecode-register.h"
14 #include "src/objects/dictionary.h"
15 #include "src/objects/instance-type-inl.h"
16 #include "src/objects/map-inl.h"
17 #include "src/objects/maybe-object-inl.h"
18 #include "src/objects/oddball.h"
19 #include "src/objects/smi-inl.h"
20
21 // Has to be the last include (doesn't have include guards):
22 #include "src/objects/object-macros.h"
23
24 namespace v8 {
25 namespace internal {
26
OBJECT_CONSTRUCTORS_IMPL(DeoptimizationData,FixedArray)27 OBJECT_CONSTRUCTORS_IMPL(DeoptimizationData, FixedArray)
28 OBJECT_CONSTRUCTORS_IMPL(BytecodeArray, FixedArrayBase)
29 OBJECT_CONSTRUCTORS_IMPL(AbstractCode, HeapObject)
30 OBJECT_CONSTRUCTORS_IMPL(DependentCode, WeakFixedArray)
31 OBJECT_CONSTRUCTORS_IMPL(CodeDataContainer, HeapObject)
32
33 NEVER_READ_ONLY_SPACE_IMPL(AbstractCode)
34
35 CAST_ACCESSOR(AbstractCode)
36 CAST_ACCESSOR(BytecodeArray)
37 CAST_ACCESSOR(Code)
38 CAST_ACCESSOR(CodeDataContainer)
39 CAST_ACCESSOR(DependentCode)
40 CAST_ACCESSOR(DeoptimizationData)
41
42 int AbstractCode::raw_instruction_size() {
43 if (IsCode()) {
44 return GetCode().raw_instruction_size();
45 } else {
46 return GetBytecodeArray().length();
47 }
48 }
49
InstructionSize()50 int AbstractCode::InstructionSize() {
51 if (IsCode()) {
52 return GetCode().InstructionSize();
53 } else {
54 return GetBytecodeArray().length();
55 }
56 }
57
source_position_table()58 ByteArray AbstractCode::source_position_table() {
59 if (IsCode()) {
60 return GetCode().SourcePositionTable();
61 } else {
62 return GetBytecodeArray().SourcePositionTable();
63 }
64 }
65
SizeIncludingMetadata()66 int AbstractCode::SizeIncludingMetadata() {
67 if (IsCode()) {
68 return GetCode().SizeIncludingMetadata();
69 } else {
70 return GetBytecodeArray().SizeIncludingMetadata();
71 }
72 }
73
raw_instruction_start()74 Address AbstractCode::raw_instruction_start() {
75 if (IsCode()) {
76 return GetCode().raw_instruction_start();
77 } else {
78 return GetBytecodeArray().GetFirstBytecodeAddress();
79 }
80 }
81
InstructionStart()82 Address AbstractCode::InstructionStart() {
83 if (IsCode()) {
84 return GetCode().InstructionStart();
85 } else {
86 return GetBytecodeArray().GetFirstBytecodeAddress();
87 }
88 }
89
raw_instruction_end()90 Address AbstractCode::raw_instruction_end() {
91 if (IsCode()) {
92 return GetCode().raw_instruction_end();
93 } else {
94 return GetBytecodeArray().GetFirstBytecodeAddress() +
95 GetBytecodeArray().length();
96 }
97 }
98
InstructionEnd()99 Address AbstractCode::InstructionEnd() {
100 if (IsCode()) {
101 return GetCode().InstructionEnd();
102 } else {
103 return GetBytecodeArray().GetFirstBytecodeAddress() +
104 GetBytecodeArray().length();
105 }
106 }
107
contains(Address inner_pointer)108 bool AbstractCode::contains(Address inner_pointer) {
109 return (address() <= inner_pointer) && (inner_pointer <= address() + Size());
110 }
111
kind()112 CodeKind AbstractCode::kind() {
113 return IsCode() ? GetCode().kind() : CodeKind::INTERPRETED_FUNCTION;
114 }
115
GetCode()116 Code AbstractCode::GetCode() { return Code::cast(*this); }
117
GetBytecodeArray()118 BytecodeArray AbstractCode::GetBytecodeArray() {
119 return BytecodeArray::cast(*this);
120 }
121
next_link()122 DependentCode DependentCode::next_link() {
123 return DependentCode::cast(Get(kNextLinkIndex)->GetHeapObjectAssumeStrong());
124 }
125
set_next_link(DependentCode next)126 void DependentCode::set_next_link(DependentCode next) {
127 Set(kNextLinkIndex, HeapObjectReference::Strong(next));
128 }
129
flags()130 int DependentCode::flags() { return Smi::ToInt(Get(kFlagsIndex)->ToSmi()); }
131
set_flags(int flags)132 void DependentCode::set_flags(int flags) {
133 Set(kFlagsIndex, MaybeObject::FromObject(Smi::FromInt(flags)));
134 }
135
count()136 int DependentCode::count() { return CountField::decode(flags()); }
137
set_count(int value)138 void DependentCode::set_count(int value) {
139 set_flags(CountField::update(flags(), value));
140 }
141
group()142 DependentCode::DependencyGroup DependentCode::group() {
143 return static_cast<DependencyGroup>(GroupField::decode(flags()));
144 }
145
set_object_at(int i,MaybeObject object)146 void DependentCode::set_object_at(int i, MaybeObject object) {
147 Set(kCodesStartIndex + i, object);
148 }
149
object_at(int i)150 MaybeObject DependentCode::object_at(int i) {
151 return Get(kCodesStartIndex + i);
152 }
153
clear_at(int i)154 void DependentCode::clear_at(int i) {
155 Set(kCodesStartIndex + i,
156 HeapObjectReference::Strong(GetReadOnlyRoots().undefined_value()));
157 }
158
copy(int from,int to)159 void DependentCode::copy(int from, int to) {
160 Set(kCodesStartIndex + to, Get(kCodesStartIndex + from));
161 }
162
OBJECT_CONSTRUCTORS_IMPL(Code,HeapObject)163 OBJECT_CONSTRUCTORS_IMPL(Code, HeapObject)
164 NEVER_READ_ONLY_SPACE_IMPL(Code)
165
166 INT_ACCESSORS(Code, raw_instruction_size, kInstructionSizeOffset)
167 INT_ACCESSORS(Code, raw_metadata_size, kMetadataSizeOffset)
168 INT_ACCESSORS(Code, handler_table_offset, kHandlerTableOffsetOffset)
169 INT_ACCESSORS(Code, code_comments_offset, kCodeCommentsOffsetOffset)
170 INT32_ACCESSORS(Code, unwinding_info_offset, kUnwindingInfoOffsetOffset)
171 #define CODE_ACCESSORS(name, type, offset) \
172 ACCESSORS_CHECKED2(Code, name, type, offset, true, \
173 !ObjectInYoungGeneration(value))
174 #define RELEASE_ACQUIRE_CODE_ACCESSORS(name, type, offset) \
175 RELEASE_ACQUIRE_ACCESSORS_CHECKED2(Code, name, type, offset, true, \
176 !ObjectInYoungGeneration(value))
177
178 CODE_ACCESSORS(relocation_info, ByteArray, kRelocationInfoOffset)
179 CODE_ACCESSORS(deoptimization_data, FixedArray, kDeoptimizationDataOffset)
180 CODE_ACCESSORS(source_position_table, Object, kSourcePositionTableOffset)
181 // Concurrent marker needs to access kind specific flags in code data container.
182 RELEASE_ACQUIRE_CODE_ACCESSORS(code_data_container, CodeDataContainer,
183 kCodeDataContainerOffset)
184 #undef CODE_ACCESSORS
185 #undef RELEASE_ACQUIRE_CODE_ACCESSORS
186
187 void Code::WipeOutHeader() {
188 WRITE_FIELD(*this, kRelocationInfoOffset, Smi::FromInt(0));
189 WRITE_FIELD(*this, kDeoptimizationDataOffset, Smi::FromInt(0));
190 WRITE_FIELD(*this, kSourcePositionTableOffset, Smi::FromInt(0));
191 WRITE_FIELD(*this, kCodeDataContainerOffset, Smi::FromInt(0));
192 }
193
clear_padding()194 void Code::clear_padding() {
195 // Clear the padding between the header and `raw_body_start`.
196 if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
197 memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
198 FIELD_SIZE(kOptionalPaddingOffset));
199 }
200
201 // Clear the padding after `raw_body_end`.
202 size_t trailing_padding_size =
203 CodeSize() - Code::kHeaderSize - raw_body_size();
204 memset(reinterpret_cast<void*>(raw_body_end()), 0, trailing_padding_size);
205 }
206
SourcePositionTable()207 ByteArray Code::SourcePositionTable() const {
208 Object maybe_table = source_position_table();
209 if (maybe_table.IsByteArray()) return ByteArray::cast(maybe_table);
210 ReadOnlyRoots roots = GetReadOnlyRoots();
211 DCHECK(maybe_table.IsUndefined(roots) || maybe_table.IsException(roots));
212 return roots.empty_byte_array();
213 }
214
next_code_link()215 Object Code::next_code_link() const {
216 return code_data_container(kAcquireLoad).next_code_link();
217 }
218
set_next_code_link(Object value)219 void Code::set_next_code_link(Object value) {
220 code_data_container(kAcquireLoad).set_next_code_link(value);
221 }
222
raw_body_start()223 Address Code::raw_body_start() const { return raw_instruction_start(); }
224
raw_body_end()225 Address Code::raw_body_end() const {
226 return raw_body_start() + raw_body_size();
227 }
228
raw_body_size()229 int Code::raw_body_size() const {
230 return raw_instruction_size() + raw_metadata_size();
231 }
232
InstructionSize()233 int Code::InstructionSize() const {
234 return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapInstructionSize()
235 : raw_instruction_size();
236 }
237
raw_instruction_start()238 Address Code::raw_instruction_start() const {
239 return field_address(kHeaderSize);
240 }
241
InstructionStart()242 Address Code::InstructionStart() const {
243 return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapInstructionStart()
244 : raw_instruction_start();
245 }
246
raw_instruction_end()247 Address Code::raw_instruction_end() const {
248 return raw_instruction_start() + raw_instruction_size();
249 }
250
InstructionEnd()251 Address Code::InstructionEnd() const {
252 return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapInstructionEnd()
253 : raw_instruction_end();
254 }
255
raw_metadata_start()256 Address Code::raw_metadata_start() const {
257 return raw_instruction_start() + raw_instruction_size();
258 }
259
MetadataStart()260 Address Code::MetadataStart() const {
261 STATIC_ASSERT(kOnHeapBodyIsContiguous);
262 return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapMetadataStart()
263 : raw_metadata_start();
264 }
265
raw_metadata_end()266 Address Code::raw_metadata_end() const {
267 return raw_metadata_start() + raw_metadata_size();
268 }
269
MetadataEnd()270 Address Code::MetadataEnd() const {
271 return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapMetadataEnd()
272 : raw_metadata_end();
273 }
274
MetadataSize()275 int Code::MetadataSize() const {
276 return V8_UNLIKELY(is_off_heap_trampoline()) ? OffHeapMetadataSize()
277 : raw_metadata_size();
278 }
279
SizeIncludingMetadata()280 int Code::SizeIncludingMetadata() const {
281 int size = CodeSize();
282 size += relocation_info().Size();
283 size += deoptimization_data().Size();
284 return size;
285 }
286
unchecked_relocation_info()287 ByteArray Code::unchecked_relocation_info() const {
288 IsolateRoot isolate = GetIsolateForPtrCompr(*this);
289 return ByteArray::unchecked_cast(
290 TaggedField<HeapObject, kRelocationInfoOffset>::load(isolate, *this));
291 }
292
relocation_start()293 byte* Code::relocation_start() const {
294 return unchecked_relocation_info().GetDataStartAddress();
295 }
296
relocation_end()297 byte* Code::relocation_end() const {
298 return unchecked_relocation_info().GetDataEndAddress();
299 }
300
relocation_size()301 int Code::relocation_size() const {
302 return unchecked_relocation_info().length();
303 }
304
entry()305 Address Code::entry() const { return raw_instruction_start(); }
306
contains(Address inner_pointer)307 bool Code::contains(Address inner_pointer) {
308 if (is_off_heap_trampoline()) {
309 if (OffHeapInstructionStart() <= inner_pointer &&
310 inner_pointer < OffHeapInstructionEnd()) {
311 return true;
312 }
313 }
314 return (address() <= inner_pointer) && (inner_pointer < address() + Size());
315 }
316
317 // static
CopyRelocInfoToByteArray(ByteArray dest,const CodeDesc & desc)318 void Code::CopyRelocInfoToByteArray(ByteArray dest, const CodeDesc& desc) {
319 DCHECK_EQ(dest.length(), desc.reloc_size);
320 CopyBytes(dest.GetDataStartAddress(),
321 desc.buffer + desc.buffer_size - desc.reloc_size,
322 static_cast<size_t>(desc.reloc_size));
323 }
324
CodeSize()325 int Code::CodeSize() const { return SizeFor(raw_body_size()); }
326
kind()327 CodeKind Code::kind() const {
328 STATIC_ASSERT(FIELD_SIZE(kFlagsOffset) == kInt32Size);
329 return KindField::decode(ReadField<uint32_t>(kFlagsOffset));
330 }
331
initialize_flags(CodeKind kind,bool is_turbofanned,int stack_slots,bool is_off_heap_trampoline)332 void Code::initialize_flags(CodeKind kind, bool is_turbofanned, int stack_slots,
333 bool is_off_heap_trampoline) {
334 CHECK(0 <= stack_slots && stack_slots < StackSlotsField::kMax);
335 DCHECK(!CodeKindIsInterpretedJSFunction(kind));
336 uint32_t flags = KindField::encode(kind) |
337 IsTurbofannedField::encode(is_turbofanned) |
338 StackSlotsField::encode(stack_slots) |
339 IsOffHeapTrampoline::encode(is_off_heap_trampoline);
340 STATIC_ASSERT(FIELD_SIZE(kFlagsOffset) == kInt32Size);
341 WriteField<uint32_t>(kFlagsOffset, flags);
342 DCHECK_IMPLIES(stack_slots != 0, has_safepoint_info());
343 }
344
is_interpreter_trampoline_builtin()345 inline bool Code::is_interpreter_trampoline_builtin() const {
346 // Check for kNoBuiltinId first to abort early when the current Code object
347 // is not a builtin.
348 const int index = builtin_index();
349 return index != Builtins::kNoBuiltinId &&
350 (index == Builtins::kInterpreterEntryTrampoline ||
351 index == Builtins::kInterpreterEnterBytecodeAdvance ||
352 index == Builtins::kInterpreterEnterBytecodeDispatch);
353 }
354
checks_optimization_marker()355 inline bool Code::checks_optimization_marker() const {
356 bool checks_marker =
357 (builtin_index() == Builtins::kCompileLazy ||
358 builtin_index() == Builtins::kInterpreterEntryTrampoline ||
359 CodeKindCanTierUp(kind()));
360 return checks_marker ||
361 (CodeKindCanDeoptimize(kind()) && marked_for_deoptimization());
362 }
363
has_tagged_params()364 inline bool Code::has_tagged_params() const {
365 return kind() != CodeKind::JS_TO_WASM_FUNCTION &&
366 kind() != CodeKind::C_WASM_ENTRY && kind() != CodeKind::WASM_FUNCTION;
367 }
368
is_turbofanned()369 inline bool Code::is_turbofanned() const {
370 return IsTurbofannedField::decode(ReadField<uint32_t>(kFlagsOffset));
371 }
372
can_have_weak_objects()373 inline bool Code::can_have_weak_objects() const {
374 DCHECK(CodeKindIsOptimizedJSFunction(kind()));
375 int32_t flags = code_data_container(kAcquireLoad).kind_specific_flags();
376 return CanHaveWeakObjectsField::decode(flags);
377 }
378
set_can_have_weak_objects(bool value)379 inline void Code::set_can_have_weak_objects(bool value) {
380 DCHECK(CodeKindIsOptimizedJSFunction(kind()));
381 CodeDataContainer container = code_data_container(kAcquireLoad);
382 int32_t previous = container.kind_specific_flags();
383 int32_t updated = CanHaveWeakObjectsField::update(previous, value);
384 container.set_kind_specific_flags(updated);
385 }
386
is_promise_rejection()387 inline bool Code::is_promise_rejection() const {
388 DCHECK(kind() == CodeKind::BUILTIN);
389 int32_t flags = code_data_container(kAcquireLoad).kind_specific_flags();
390 return IsPromiseRejectionField::decode(flags);
391 }
392
set_is_promise_rejection(bool value)393 inline void Code::set_is_promise_rejection(bool value) {
394 DCHECK(kind() == CodeKind::BUILTIN);
395 CodeDataContainer container = code_data_container(kAcquireLoad);
396 int32_t previous = container.kind_specific_flags();
397 int32_t updated = IsPromiseRejectionField::update(previous, value);
398 container.set_kind_specific_flags(updated);
399 }
400
is_exception_caught()401 inline bool Code::is_exception_caught() const {
402 DCHECK(kind() == CodeKind::BUILTIN);
403 int32_t flags = code_data_container(kAcquireLoad).kind_specific_flags();
404 return IsExceptionCaughtField::decode(flags);
405 }
406
set_is_exception_caught(bool value)407 inline void Code::set_is_exception_caught(bool value) {
408 DCHECK(kind() == CodeKind::BUILTIN);
409 CodeDataContainer container = code_data_container(kAcquireLoad);
410 int32_t previous = container.kind_specific_flags();
411 int32_t updated = IsExceptionCaughtField::update(previous, value);
412 container.set_kind_specific_flags(updated);
413 }
414
is_off_heap_trampoline()415 inline bool Code::is_off_heap_trampoline() const {
416 return IsOffHeapTrampoline::decode(ReadField<uint32_t>(kFlagsOffset));
417 }
418
GetBuiltinCatchPrediction()419 inline HandlerTable::CatchPrediction Code::GetBuiltinCatchPrediction() {
420 if (is_promise_rejection()) return HandlerTable::PROMISE;
421 if (is_exception_caught()) return HandlerTable::CAUGHT;
422 return HandlerTable::UNCAUGHT;
423 }
424
builtin_index()425 int Code::builtin_index() const {
426 int index = ReadField<int>(kBuiltinIndexOffset);
427 DCHECK(index == Builtins::kNoBuiltinId || Builtins::IsBuiltinId(index));
428 return index;
429 }
430
set_builtin_index(int index)431 void Code::set_builtin_index(int index) {
432 DCHECK(index == Builtins::kNoBuiltinId || Builtins::IsBuiltinId(index));
433 WriteField<int>(kBuiltinIndexOffset, index);
434 }
435
is_builtin()436 bool Code::is_builtin() const {
437 return builtin_index() != Builtins::kNoBuiltinId;
438 }
439
inlined_bytecode_size()440 unsigned Code::inlined_bytecode_size() const {
441 DCHECK(CodeKindIsOptimizedJSFunction(kind()) ||
442 ReadField<unsigned>(kInlinedBytecodeSizeOffset) == 0);
443 return ReadField<unsigned>(kInlinedBytecodeSizeOffset);
444 }
445
set_inlined_bytecode_size(unsigned size)446 void Code::set_inlined_bytecode_size(unsigned size) {
447 DCHECK(CodeKindIsOptimizedJSFunction(kind()) || size == 0);
448 WriteField<unsigned>(kInlinedBytecodeSizeOffset, size);
449 }
450
has_safepoint_info()451 bool Code::has_safepoint_info() const {
452 return is_turbofanned() || is_wasm_code();
453 }
454
stack_slots()455 int Code::stack_slots() const {
456 DCHECK(has_safepoint_info());
457 return StackSlotsField::decode(ReadField<uint32_t>(kFlagsOffset));
458 }
459
marked_for_deoptimization()460 bool Code::marked_for_deoptimization() const {
461 DCHECK(CodeKindCanDeoptimize(kind()));
462 int32_t flags = code_data_container(kAcquireLoad).kind_specific_flags();
463 return MarkedForDeoptimizationField::decode(flags);
464 }
465
set_marked_for_deoptimization(bool flag)466 void Code::set_marked_for_deoptimization(bool flag) {
467 DCHECK(CodeKindCanDeoptimize(kind()));
468 DCHECK_IMPLIES(flag, AllowDeoptimization::IsAllowed(GetIsolate()));
469 CodeDataContainer container = code_data_container(kAcquireLoad);
470 int32_t previous = container.kind_specific_flags();
471 int32_t updated = MarkedForDeoptimizationField::update(previous, flag);
472 container.set_kind_specific_flags(updated);
473 }
474
deoptimization_count()475 int Code::deoptimization_count() const {
476 DCHECK(CodeKindCanDeoptimize(kind()));
477 int32_t flags = code_data_container(kAcquireLoad).kind_specific_flags();
478 int count = DeoptCountField::decode(flags);
479 DCHECK_GE(count, 0);
480 return count;
481 }
482
increment_deoptimization_count()483 void Code::increment_deoptimization_count() {
484 DCHECK(CodeKindCanDeoptimize(kind()));
485 CodeDataContainer container = code_data_container(kAcquireLoad);
486 int32_t flags = container.kind_specific_flags();
487 int32_t count = DeoptCountField::decode(flags);
488 DCHECK_GE(count, 0);
489 CHECK_LE(count + 1, DeoptCountField::kMax);
490 int32_t updated = DeoptCountField::update(flags, count + 1);
491 container.set_kind_specific_flags(updated);
492 }
493
embedded_objects_cleared()494 bool Code::embedded_objects_cleared() const {
495 DCHECK(CodeKindIsOptimizedJSFunction(kind()));
496 int32_t flags = code_data_container(kAcquireLoad).kind_specific_flags();
497 return EmbeddedObjectsClearedField::decode(flags);
498 }
499
set_embedded_objects_cleared(bool flag)500 void Code::set_embedded_objects_cleared(bool flag) {
501 DCHECK(CodeKindIsOptimizedJSFunction(kind()));
502 DCHECK_IMPLIES(flag, marked_for_deoptimization());
503 CodeDataContainer container = code_data_container(kAcquireLoad);
504 int32_t previous = container.kind_specific_flags();
505 int32_t updated = EmbeddedObjectsClearedField::update(previous, flag);
506 container.set_kind_specific_flags(updated);
507 }
508
deopt_already_counted()509 bool Code::deopt_already_counted() const {
510 DCHECK(CodeKindCanDeoptimize(kind()));
511 int32_t flags = code_data_container(kAcquireLoad).kind_specific_flags();
512 return DeoptAlreadyCountedField::decode(flags);
513 }
514
set_deopt_already_counted(bool flag)515 void Code::set_deopt_already_counted(bool flag) {
516 DCHECK(CodeKindCanDeoptimize(kind()));
517 DCHECK_IMPLIES(flag, AllowDeoptimization::IsAllowed(GetIsolate()));
518 CodeDataContainer container = code_data_container(kAcquireLoad);
519 int32_t previous = container.kind_specific_flags();
520 int32_t updated = DeoptAlreadyCountedField::update(previous, flag);
521 container.set_kind_specific_flags(updated);
522 }
523
is_optimized_code()524 bool Code::is_optimized_code() const {
525 return CodeKindIsOptimizedJSFunction(kind());
526 }
is_wasm_code()527 bool Code::is_wasm_code() const { return kind() == CodeKind::WASM_FUNCTION; }
528
constant_pool_offset()529 int Code::constant_pool_offset() const {
530 if (!FLAG_enable_embedded_constant_pool) {
531 // Redirection needed since the field doesn't exist in this case.
532 return code_comments_offset();
533 }
534 return ReadField<int>(kConstantPoolOffsetOffset);
535 }
536
set_constant_pool_offset(int value)537 void Code::set_constant_pool_offset(int value) {
538 if (!FLAG_enable_embedded_constant_pool) {
539 // Redirection needed since the field doesn't exist in this case.
540 return;
541 }
542 DCHECK_LE(value, MetadataSize());
543 WriteField<int>(kConstantPoolOffsetOffset, value);
544 }
545
constant_pool()546 Address Code::constant_pool() const {
547 if (!has_constant_pool()) return kNullAddress;
548 return MetadataStart() + constant_pool_offset();
549 }
550
code_comments()551 Address Code::code_comments() const {
552 return MetadataStart() + code_comments_offset();
553 }
554
unwinding_info_start()555 Address Code::unwinding_info_start() const {
556 return MetadataStart() + unwinding_info_offset();
557 }
558
unwinding_info_end()559 Address Code::unwinding_info_end() const { return MetadataEnd(); }
560
unwinding_info_size()561 int Code::unwinding_info_size() const {
562 DCHECK_GE(unwinding_info_end(), unwinding_info_start());
563 return static_cast<int>(unwinding_info_end() - unwinding_info_start());
564 }
565
has_unwinding_info()566 bool Code::has_unwinding_info() const { return unwinding_info_size() > 0; }
567
GetCodeFromTargetAddress(Address address)568 Code Code::GetCodeFromTargetAddress(Address address) {
569 {
570 // TODO(jgruber,v8:6666): Support embedded builtins here. We'd need to pass
571 // in the current isolate.
572 Address start =
573 reinterpret_cast<Address>(Isolate::CurrentEmbeddedBlobCode());
574 Address end = start + Isolate::CurrentEmbeddedBlobCodeSize();
575 CHECK(address < start || address >= end);
576 }
577
578 HeapObject code = HeapObject::FromAddress(address - Code::kHeaderSize);
579 // Unchecked cast because we can't rely on the map currently
580 // not being a forwarding pointer.
581 return Code::unchecked_cast(code);
582 }
583
GetObjectFromEntryAddress(Address location_of_address)584 Code Code::GetObjectFromEntryAddress(Address location_of_address) {
585 Address code_entry = base::Memory<Address>(location_of_address);
586 HeapObject code = HeapObject::FromAddress(code_entry - Code::kHeaderSize);
587 // Unchecked cast because we can't rely on the map currently
588 // not being a forwarding pointer.
589 return Code::unchecked_cast(code);
590 }
591
CanContainWeakObjects()592 bool Code::CanContainWeakObjects() {
593 return is_optimized_code() && can_have_weak_objects();
594 }
595
IsWeakObject(HeapObject object)596 bool Code::IsWeakObject(HeapObject object) {
597 return (CanContainWeakObjects() && IsWeakObjectInOptimizedCode(object));
598 }
599
IsWeakObjectInOptimizedCode(HeapObject object)600 bool Code::IsWeakObjectInOptimizedCode(HeapObject object) {
601 Map map = object.synchronized_map();
602 InstanceType instance_type = map.instance_type();
603 if (InstanceTypeChecker::IsMap(instance_type)) {
604 return Map::cast(object).CanTransition();
605 }
606 return InstanceTypeChecker::IsPropertyCell(instance_type) ||
607 InstanceTypeChecker::IsJSReceiver(instance_type) ||
608 InstanceTypeChecker::IsContext(instance_type);
609 }
610
IsExecutable()611 bool Code::IsExecutable() {
612 return !Builtins::IsBuiltinId(builtin_index()) || !is_off_heap_trampoline() ||
613 Builtins::CodeObjectIsExecutable(builtin_index());
614 }
615
616 // This field has to have relaxed atomic accessors because it is accessed in the
617 // concurrent marker.
618 STATIC_ASSERT(FIELD_SIZE(CodeDataContainer::kKindSpecificFlagsOffset) ==
619 kInt32Size);
RELAXED_INT32_ACCESSORS(CodeDataContainer,kind_specific_flags,kKindSpecificFlagsOffset)620 RELAXED_INT32_ACCESSORS(CodeDataContainer, kind_specific_flags,
621 kKindSpecificFlagsOffset)
622 ACCESSORS(CodeDataContainer, next_code_link, Object, kNextCodeLinkOffset)
623
624 void CodeDataContainer::clear_padding() {
625 memset(reinterpret_cast<void*>(address() + kUnalignedSize), 0,
626 kSize - kUnalignedSize);
627 }
628
get(int index)629 byte BytecodeArray::get(int index) const {
630 DCHECK(index >= 0 && index < this->length());
631 return ReadField<byte>(kHeaderSize + index * kCharSize);
632 }
633
set(int index,byte value)634 void BytecodeArray::set(int index, byte value) {
635 DCHECK(index >= 0 && index < this->length());
636 WriteField<byte>(kHeaderSize + index * kCharSize, value);
637 }
638
set_frame_size(int32_t frame_size)639 void BytecodeArray::set_frame_size(int32_t frame_size) {
640 DCHECK_GE(frame_size, 0);
641 DCHECK(IsAligned(frame_size, kSystemPointerSize));
642 WriteField<int32_t>(kFrameSizeOffset, frame_size);
643 }
644
frame_size()645 int32_t BytecodeArray::frame_size() const {
646 return ReadField<int32_t>(kFrameSizeOffset);
647 }
648
register_count()649 int BytecodeArray::register_count() const {
650 return static_cast<int>(frame_size()) / kSystemPointerSize;
651 }
652
set_parameter_count(int32_t number_of_parameters)653 void BytecodeArray::set_parameter_count(int32_t number_of_parameters) {
654 DCHECK_GE(number_of_parameters, 0);
655 // Parameter count is stored as the size on stack of the parameters to allow
656 // it to be used directly by generated code.
657 WriteField<int32_t>(kParameterSizeOffset,
658 (number_of_parameters << kSystemPointerSizeLog2));
659 }
660
incoming_new_target_or_generator_register()661 interpreter::Register BytecodeArray::incoming_new_target_or_generator_register()
662 const {
663 int32_t register_operand =
664 ReadField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset);
665 if (register_operand == 0) {
666 return interpreter::Register::invalid_value();
667 } else {
668 return interpreter::Register::FromOperand(register_operand);
669 }
670 }
671
set_incoming_new_target_or_generator_register(interpreter::Register incoming_new_target_or_generator_register)672 void BytecodeArray::set_incoming_new_target_or_generator_register(
673 interpreter::Register incoming_new_target_or_generator_register) {
674 if (!incoming_new_target_or_generator_register.is_valid()) {
675 WriteField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset, 0);
676 } else {
677 DCHECK(incoming_new_target_or_generator_register.index() <
678 register_count());
679 DCHECK_NE(0, incoming_new_target_or_generator_register.ToOperand());
680 WriteField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset,
681 incoming_new_target_or_generator_register.ToOperand());
682 }
683 }
684
osr_loop_nesting_level()685 int BytecodeArray::osr_loop_nesting_level() const {
686 return ReadField<int8_t>(kOsrNestingLevelOffset);
687 }
688
set_osr_loop_nesting_level(int depth)689 void BytecodeArray::set_osr_loop_nesting_level(int depth) {
690 DCHECK(0 <= depth && depth <= AbstractCode::kMaxLoopNestingMarker);
691 STATIC_ASSERT(AbstractCode::kMaxLoopNestingMarker < kMaxInt8);
692 WriteField<int8_t>(kOsrNestingLevelOffset, depth);
693 }
694
bytecode_age()695 BytecodeArray::Age BytecodeArray::bytecode_age() const {
696 // Bytecode is aged by the concurrent marker.
697 return static_cast<Age>(RELAXED_READ_INT8_FIELD(*this, kBytecodeAgeOffset));
698 }
699
set_bytecode_age(BytecodeArray::Age age)700 void BytecodeArray::set_bytecode_age(BytecodeArray::Age age) {
701 DCHECK_GE(age, kFirstBytecodeAge);
702 DCHECK_LE(age, kLastBytecodeAge);
703 STATIC_ASSERT(kLastBytecodeAge <= kMaxInt8);
704 // Bytecode is aged by the concurrent marker.
705 RELAXED_WRITE_INT8_FIELD(*this, kBytecodeAgeOffset, static_cast<int8_t>(age));
706 }
707
parameter_count()708 int32_t BytecodeArray::parameter_count() const {
709 // Parameter count is stored as the size on stack of the parameters to allow
710 // it to be used directly by generated code.
711 return ReadField<int32_t>(kParameterSizeOffset) >> kSystemPointerSizeLog2;
712 }
713
ACCESSORS(BytecodeArray,constant_pool,FixedArray,kConstantPoolOffset)714 ACCESSORS(BytecodeArray, constant_pool, FixedArray, kConstantPoolOffset)
715 ACCESSORS(BytecodeArray, handler_table, ByteArray, kHandlerTableOffset)
716 RELEASE_ACQUIRE_ACCESSORS(BytecodeArray, source_position_table, Object,
717 kSourcePositionTableOffset)
718
719 void BytecodeArray::clear_padding() {
720 int data_size = kHeaderSize + length();
721 memset(reinterpret_cast<void*>(address() + data_size), 0,
722 SizeFor(length()) - data_size);
723 }
724
GetFirstBytecodeAddress()725 Address BytecodeArray::GetFirstBytecodeAddress() {
726 return ptr() - kHeapObjectTag + kHeaderSize;
727 }
728
HasSourcePositionTable()729 bool BytecodeArray::HasSourcePositionTable() const {
730 Object maybe_table = source_position_table(kAcquireLoad);
731 return !(maybe_table.IsUndefined() || DidSourcePositionGenerationFail());
732 }
733
DidSourcePositionGenerationFail()734 bool BytecodeArray::DidSourcePositionGenerationFail() const {
735 return source_position_table(kAcquireLoad).IsException();
736 }
737
SetSourcePositionsFailedToCollect()738 void BytecodeArray::SetSourcePositionsFailedToCollect() {
739 set_source_position_table(GetReadOnlyRoots().exception(), kReleaseStore);
740 }
741
SourcePositionTable()742 ByteArray BytecodeArray::SourcePositionTable() const {
743 // WARNING: This function may be called from a background thread, hence
744 // changes to how it accesses the heap can easily lead to bugs.
745 Object maybe_table = source_position_table(kAcquireLoad);
746 if (maybe_table.IsByteArray()) return ByteArray::cast(maybe_table);
747 ReadOnlyRoots roots = GetReadOnlyRoots();
748 DCHECK(maybe_table.IsUndefined(roots) || maybe_table.IsException(roots));
749 return roots.empty_byte_array();
750 }
751
BytecodeArraySize()752 int BytecodeArray::BytecodeArraySize() { return SizeFor(this->length()); }
753
SizeIncludingMetadata()754 int BytecodeArray::SizeIncludingMetadata() {
755 int size = BytecodeArraySize();
756 size += constant_pool().Size();
757 size += handler_table().Size();
758 ByteArray table = SourcePositionTable();
759 if (table.length() != 0) {
760 size += table.Size();
761 }
762 return size;
763 }
764
DEFINE_DEOPT_ELEMENT_ACCESSORS(TranslationByteArray,ByteArray)765 DEFINE_DEOPT_ELEMENT_ACCESSORS(TranslationByteArray, ByteArray)
766 DEFINE_DEOPT_ELEMENT_ACCESSORS(InlinedFunctionCount, Smi)
767 DEFINE_DEOPT_ELEMENT_ACCESSORS(LiteralArray, FixedArray)
768 DEFINE_DEOPT_ELEMENT_ACCESSORS(OsrBytecodeOffset, Smi)
769 DEFINE_DEOPT_ELEMENT_ACCESSORS(OsrPcOffset, Smi)
770 DEFINE_DEOPT_ELEMENT_ACCESSORS(OptimizationId, Smi)
771 DEFINE_DEOPT_ELEMENT_ACCESSORS(InliningPositions, PodArray<InliningPosition>)
772 DEFINE_DEOPT_ELEMENT_ACCESSORS(DeoptExitStart, Smi)
773 DEFINE_DEOPT_ELEMENT_ACCESSORS(NonLazyDeoptCount, Smi)
774
775 DEFINE_DEOPT_ENTRY_ACCESSORS(BytecodeOffsetRaw, Smi)
776 DEFINE_DEOPT_ENTRY_ACCESSORS(TranslationIndex, Smi)
777 DEFINE_DEOPT_ENTRY_ACCESSORS(Pc, Smi)
778
779 BailoutId DeoptimizationData::BytecodeOffset(int i) {
780 return BailoutId(BytecodeOffsetRaw(i).value());
781 }
782
SetBytecodeOffset(int i,BailoutId value)783 void DeoptimizationData::SetBytecodeOffset(int i, BailoutId value) {
784 SetBytecodeOffsetRaw(i, Smi::FromInt(value.ToInt()));
785 }
786
DeoptCount()787 int DeoptimizationData::DeoptCount() {
788 return (length() - kFirstDeoptEntryIndex) / kDeoptEntrySize;
789 }
790
791 } // namespace internal
792 } // namespace v8
793
794 #include "src/objects/object-macros-undef.h"
795
796 #endif // V8_OBJECTS_CODE_INL_H_
797