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_SHARED_FUNCTION_INFO_INL_H_ |
6 | #define V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_ |
7 | |
8 | #include "src/objects/shared-function-info.h" |
9 | |
10 | #include "src/feedback-vector-inl.h" |
11 | #include "src/handles-inl.h" |
12 | #include "src/heap/heap-write-barrier-inl.h" |
13 | #include "src/objects/debug-objects-inl.h" |
14 | #include "src/objects/scope-info.h" |
15 | #include "src/objects/templates.h" |
16 | #include "src/wasm/wasm-objects-inl.h" |
17 | |
18 | // Has to be the last include (doesn't have include guards): |
19 | #include "src/objects/object-macros.h" |
20 | |
21 | namespace v8 { |
22 | namespace internal { |
23 | |
24 | OBJECT_CONSTRUCTORS_IMPL(PreparseData, HeapObject) |
25 | |
26 | CAST_ACCESSOR(PreparseData) |
27 | INT_ACCESSORS(PreparseData, data_length, kDataLengthOffset) |
28 | INT_ACCESSORS(PreparseData, children_length, kInnerLengthOffset) |
29 | |
30 | int PreparseData::inner_start_offset() const { |
31 | return InnerOffset(data_length()); |
32 | } |
33 | |
34 | ObjectSlot PreparseData::inner_data_start() const { |
35 | return RawField(inner_start_offset()); |
36 | } |
37 | |
38 | void PreparseData::clear_padding() { |
39 | int data_end_offset = kDataStartOffset + data_length(); |
40 | int padding_size = inner_start_offset() - data_end_offset; |
41 | DCHECK_LE(0, padding_size); |
42 | if (padding_size == 0) return; |
43 | memset(reinterpret_cast<void*>(address() + data_end_offset), 0, padding_size); |
44 | } |
45 | |
46 | byte PreparseData::get(int index) const { |
47 | DCHECK_LE(0, index); |
48 | DCHECK_LT(index, data_length()); |
49 | int offset = kDataStartOffset + index * kByteSize; |
50 | return READ_BYTE_FIELD(*this, offset); |
51 | } |
52 | |
53 | void PreparseData::set(int index, byte value) { |
54 | DCHECK_LE(0, index); |
55 | DCHECK_LT(index, data_length()); |
56 | int offset = kDataStartOffset + index * kByteSize; |
57 | WRITE_BYTE_FIELD(*this, offset, value); |
58 | } |
59 | |
60 | void PreparseData::copy_in(int index, const byte* buffer, int length) { |
61 | DCHECK(index >= 0 && length >= 0 && length <= kMaxInt - index && |
62 | index + length <= this->data_length()); |
63 | Address dst_addr = FIELD_ADDR(*this, kDataStartOffset + index * kByteSize); |
64 | memcpy(reinterpret_cast<void*>(dst_addr), buffer, length); |
65 | } |
66 | |
67 | PreparseData PreparseData::get_child(int index) const { |
68 | return PreparseData::cast(get_child_raw(index)); |
69 | } |
70 | |
71 | Object PreparseData::get_child_raw(int index) const { |
72 | DCHECK_LE(0, index); |
73 | DCHECK_LT(index, this->children_length()); |
74 | int offset = inner_start_offset() + index * kTaggedSize; |
75 | return RELAXED_READ_FIELD(*this, offset); |
76 | } |
77 | |
78 | void PreparseData::set_child(int index, PreparseData value, |
79 | WriteBarrierMode mode) { |
80 | DCHECK_LE(0, index); |
81 | DCHECK_LT(index, this->children_length()); |
82 | int offset = inner_start_offset() + index * kTaggedSize; |
83 | RELAXED_WRITE_FIELD(*this, offset, value); |
84 | CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); |
85 | } |
86 | |
87 | OBJECT_CONSTRUCTORS_IMPL(UncompiledData, HeapObject) |
88 | OBJECT_CONSTRUCTORS_IMPL(UncompiledDataWithoutPreparseData, UncompiledData) |
89 | OBJECT_CONSTRUCTORS_IMPL(UncompiledDataWithPreparseData, UncompiledData) |
90 | CAST_ACCESSOR(UncompiledData) |
91 | ACCESSORS(UncompiledData, inferred_name, String, kInferredNameOffset) |
92 | INT32_ACCESSORS(UncompiledData, start_position, kStartPositionOffset) |
93 | INT32_ACCESSORS(UncompiledData, end_position, kEndPositionOffset) |
94 | INT32_ACCESSORS(UncompiledData, function_literal_id, kFunctionLiteralIdOffset) |
95 | |
96 | void UncompiledData::clear_padding() { |
97 | if (FIELD_SIZE(kOptionalPaddingOffset) == 0) return; |
98 | DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset)); |
99 | memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0, |
100 | FIELD_SIZE(kOptionalPaddingOffset)); |
101 | } |
102 | |
103 | CAST_ACCESSOR(UncompiledDataWithoutPreparseData) |
104 | |
105 | CAST_ACCESSOR(UncompiledDataWithPreparseData) |
106 | ACCESSORS(UncompiledDataWithPreparseData, preparse_data, PreparseData, |
107 | kPreparseDataOffset) |
108 | |
109 | bool HeapObject::IsUncompiledData() const { |
110 | return IsUncompiledDataWithoutPreparseData() || |
111 | IsUncompiledDataWithPreparseData(); |
112 | } |
113 | |
114 | OBJECT_CONSTRUCTORS_IMPL(InterpreterData, Struct) |
115 | |
116 | CAST_ACCESSOR(InterpreterData) |
117 | ACCESSORS(InterpreterData, bytecode_array, BytecodeArray, kBytecodeArrayOffset) |
118 | ACCESSORS(InterpreterData, interpreter_trampoline, Code, |
119 | kInterpreterTrampolineOffset) |
120 | |
121 | OBJECT_CONSTRUCTORS_IMPL(SharedFunctionInfo, HeapObject) |
122 | NEVER_READ_ONLY_SPACE_IMPL(SharedFunctionInfo) |
123 | CAST_ACCESSOR(SharedFunctionInfo) |
124 | DEFINE_DEOPT_ELEMENT_ACCESSORS(SharedFunctionInfo, Object) |
125 | |
126 | ACCESSORS(SharedFunctionInfo, name_or_scope_info, Object, |
127 | kNameOrScopeInfoOffset) |
128 | ACCESSORS(SharedFunctionInfo, script_or_debug_info, Object, |
129 | kScriptOrDebugInfoOffset) |
130 | |
131 | UINT16_ACCESSORS(SharedFunctionInfo, length, kLengthOffset) |
132 | UINT16_ACCESSORS(SharedFunctionInfo, internal_formal_parameter_count, |
133 | kFormalParameterCountOffset) |
134 | UINT16_ACCESSORS(SharedFunctionInfo, expected_nof_properties, |
135 | kExpectedNofPropertiesOffset) |
136 | UINT16_ACCESSORS(SharedFunctionInfo, raw_function_token_offset, |
137 | kFunctionTokenOffsetOffset) |
138 | RELAXED_INT32_ACCESSORS(SharedFunctionInfo, flags, kFlagsOffset) |
139 | |
140 | bool SharedFunctionInfo::HasSharedName() const { |
141 | Object value = name_or_scope_info(); |
142 | if (value->IsScopeInfo()) { |
143 | return ScopeInfo::cast(value)->HasSharedFunctionName(); |
144 | } |
145 | return value != kNoSharedNameSentinel; |
146 | } |
147 | |
148 | String SharedFunctionInfo::Name() const { |
149 | if (!HasSharedName()) return GetReadOnlyRoots().empty_string(); |
150 | Object value = name_or_scope_info(); |
151 | if (value->IsScopeInfo()) { |
152 | if (ScopeInfo::cast(value)->HasFunctionName()) { |
153 | return String::cast(ScopeInfo::cast(value)->FunctionName()); |
154 | } |
155 | return GetReadOnlyRoots().empty_string(); |
156 | } |
157 | return String::cast(value); |
158 | } |
159 | |
160 | void SharedFunctionInfo::SetName(String name) { |
161 | Object maybe_scope_info = name_or_scope_info(); |
162 | if (maybe_scope_info->IsScopeInfo()) { |
163 | ScopeInfo::cast(maybe_scope_info)->SetFunctionName(name); |
164 | } else { |
165 | DCHECK(maybe_scope_info->IsString() || |
166 | maybe_scope_info == kNoSharedNameSentinel); |
167 | set_name_or_scope_info(name); |
168 | } |
169 | UpdateFunctionMapIndex(); |
170 | } |
171 | |
172 | AbstractCode SharedFunctionInfo::abstract_code() { |
173 | if (HasBytecodeArray()) { |
174 | return AbstractCode::cast(GetBytecodeArray()); |
175 | } else { |
176 | return AbstractCode::cast(GetCode()); |
177 | } |
178 | } |
179 | |
180 | Object SharedFunctionInfo::function_data() const { |
181 | return ACQUIRE_READ_FIELD(*this, kFunctionDataOffset); |
182 | } |
183 | |
184 | void SharedFunctionInfo::set_function_data(Object data, WriteBarrierMode mode) { |
185 | RELEASE_WRITE_FIELD(*this, kFunctionDataOffset, data); |
186 | CONDITIONAL_WRITE_BARRIER(*this, kFunctionDataOffset, data, mode); |
187 | } |
188 | |
189 | int SharedFunctionInfo::function_token_position() const { |
190 | int offset = raw_function_token_offset(); |
191 | if (offset == kFunctionTokenOutOfRange) { |
192 | return kNoSourcePosition; |
193 | } else { |
194 | return StartPosition() - offset; |
195 | } |
196 | } |
197 | |
198 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_wrapped, |
199 | SharedFunctionInfo::IsWrappedBit) |
200 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, allows_lazy_compilation, |
201 | SharedFunctionInfo::AllowLazyCompilationBit) |
202 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, has_duplicate_parameters, |
203 | SharedFunctionInfo::HasDuplicateParametersBit) |
204 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_declaration, |
205 | SharedFunctionInfo::IsDeclarationBit) |
206 | |
207 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, native, |
208 | SharedFunctionInfo::IsNativeBit) |
209 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_asm_wasm_broken, |
210 | SharedFunctionInfo::IsAsmWasmBrokenBit) |
211 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, |
212 | requires_instance_members_initializer, |
213 | SharedFunctionInfo::RequiresInstanceMembersInitializer) |
214 | |
215 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, name_should_print_as_anonymous, |
216 | SharedFunctionInfo::NameShouldPrintAsAnonymousBit) |
217 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_anonymous_expression, |
218 | SharedFunctionInfo::IsAnonymousExpressionBit) |
219 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, has_reported_binary_coverage, |
220 | SharedFunctionInfo::HasReportedBinaryCoverageBit) |
221 | |
222 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_named_expression, |
223 | SharedFunctionInfo::IsNamedExpressionBit) |
224 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_toplevel, |
225 | SharedFunctionInfo::IsTopLevelBit) |
226 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_oneshot_iife, |
227 | SharedFunctionInfo::IsOneshotIIFEBit) |
228 | BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, |
229 | is_safe_to_skip_arguments_adaptor, |
230 | SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit) |
231 | |
232 | bool SharedFunctionInfo::optimization_disabled() const { |
233 | return disable_optimization_reason() != BailoutReason::kNoReason; |
234 | } |
235 | |
236 | BailoutReason SharedFunctionInfo::disable_optimization_reason() const { |
237 | return DisabledOptimizationReasonBits::decode(flags()); |
238 | } |
239 | |
240 | LanguageMode SharedFunctionInfo::language_mode() const { |
241 | STATIC_ASSERT(LanguageModeSize == 2); |
242 | return construct_language_mode(IsStrictBit::decode(flags())); |
243 | } |
244 | |
245 | void SharedFunctionInfo::set_language_mode(LanguageMode language_mode) { |
246 | STATIC_ASSERT(LanguageModeSize == 2); |
247 | // We only allow language mode transitions that set the same language mode |
248 | // again or go up in the chain: |
249 | DCHECK(is_sloppy(this->language_mode()) || is_strict(language_mode)); |
250 | int hints = flags(); |
251 | hints = IsStrictBit::update(hints, is_strict(language_mode)); |
252 | set_flags(hints); |
253 | UpdateFunctionMapIndex(); |
254 | } |
255 | |
256 | FunctionKind SharedFunctionInfo::kind() const { |
257 | return FunctionKindBits::decode(flags()); |
258 | } |
259 | |
260 | void SharedFunctionInfo::set_kind(FunctionKind kind) { |
261 | int hints = flags(); |
262 | hints = FunctionKindBits::update(hints, kind); |
263 | hints = IsClassConstructorBit::update(hints, IsClassConstructor(kind)); |
264 | set_flags(hints); |
265 | UpdateFunctionMapIndex(); |
266 | } |
267 | |
268 | bool SharedFunctionInfo::needs_home_object() const { |
269 | return NeedsHomeObjectBit::decode(flags()); |
270 | } |
271 | |
272 | void SharedFunctionInfo::set_needs_home_object(bool value) { |
273 | int hints = flags(); |
274 | hints = NeedsHomeObjectBit::update(hints, value); |
275 | set_flags(hints); |
276 | UpdateFunctionMapIndex(); |
277 | } |
278 | |
279 | bool SharedFunctionInfo::construct_as_builtin() const { |
280 | return ConstructAsBuiltinBit::decode(flags()); |
281 | } |
282 | |
283 | void SharedFunctionInfo::CalculateConstructAsBuiltin() { |
284 | bool uses_builtins_construct_stub = false; |
285 | if (HasBuiltinId()) { |
286 | int id = builtin_id(); |
287 | if (id != Builtins::kCompileLazy && id != Builtins::kEmptyFunction) { |
288 | uses_builtins_construct_stub = true; |
289 | } |
290 | } else if (IsApiFunction()) { |
291 | uses_builtins_construct_stub = true; |
292 | } |
293 | |
294 | int f = flags(); |
295 | f = ConstructAsBuiltinBit::update(f, uses_builtins_construct_stub); |
296 | set_flags(f); |
297 | } |
298 | |
299 | int SharedFunctionInfo::function_map_index() const { |
300 | // Note: Must be kept in sync with the FastNewClosure builtin. |
301 | int index = |
302 | Context::FIRST_FUNCTION_MAP_INDEX + FunctionMapIndexBits::decode(flags()); |
303 | DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); |
304 | return index; |
305 | } |
306 | |
307 | void SharedFunctionInfo::set_function_map_index(int index) { |
308 | STATIC_ASSERT(Context::LAST_FUNCTION_MAP_INDEX <= |
309 | Context::FIRST_FUNCTION_MAP_INDEX + FunctionMapIndexBits::kMax); |
310 | DCHECK_LE(Context::FIRST_FUNCTION_MAP_INDEX, index); |
311 | DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); |
312 | index -= Context::FIRST_FUNCTION_MAP_INDEX; |
313 | set_flags(FunctionMapIndexBits::update(flags(), index)); |
314 | } |
315 | |
316 | void SharedFunctionInfo::clear_padding() { |
317 | memset(reinterpret_cast<void*>(this->address() + kSize), 0, |
318 | kAlignedSize - kSize); |
319 | } |
320 | |
321 | void SharedFunctionInfo::UpdateFunctionMapIndex() { |
322 | int map_index = Context::FunctionMapIndex( |
323 | language_mode(), kind(), HasSharedName(), needs_home_object()); |
324 | set_function_map_index(map_index); |
325 | } |
326 | |
327 | void SharedFunctionInfo::DontAdaptArguments() { |
328 | // TODO(leszeks): Revise this DCHECK now that the code field is gone. |
329 | DCHECK(!HasWasmExportedFunctionData()); |
330 | set_internal_formal_parameter_count(kDontAdaptArgumentsSentinel); |
331 | } |
332 | |
333 | bool SharedFunctionInfo::IsInterpreted() const { return HasBytecodeArray(); } |
334 | |
335 | ScopeInfo SharedFunctionInfo::scope_info() const { |
336 | Object maybe_scope_info = name_or_scope_info(); |
337 | if (maybe_scope_info->IsScopeInfo()) { |
338 | return ScopeInfo::cast(maybe_scope_info); |
339 | } |
340 | return ScopeInfo::Empty(GetIsolate()); |
341 | } |
342 | |
343 | void SharedFunctionInfo::set_scope_info(ScopeInfo scope_info, |
344 | WriteBarrierMode mode) { |
345 | // Move the existing name onto the ScopeInfo. |
346 | Object name = name_or_scope_info(); |
347 | if (name->IsScopeInfo()) { |
348 | name = ScopeInfo::cast(name)->FunctionName(); |
349 | } |
350 | DCHECK(name->IsString() || name == kNoSharedNameSentinel); |
351 | // Only set the function name for function scopes. |
352 | scope_info->SetFunctionName(name); |
353 | if (HasInferredName() && inferred_name()->length() != 0) { |
354 | scope_info->SetInferredFunctionName(inferred_name()); |
355 | } |
356 | WRITE_FIELD(*this, kNameOrScopeInfoOffset, scope_info); |
357 | CONDITIONAL_WRITE_BARRIER(*this, kNameOrScopeInfoOffset, scope_info, mode); |
358 | } |
359 | |
360 | ACCESSORS(SharedFunctionInfo, raw_outer_scope_info_or_feedback_metadata, |
361 | HeapObject, kOuterScopeInfoOrFeedbackMetadataOffset) |
362 | |
363 | HeapObject SharedFunctionInfo::outer_scope_info() const { |
364 | DCHECK(!is_compiled()); |
365 | DCHECK(!HasFeedbackMetadata()); |
366 | return raw_outer_scope_info_or_feedback_metadata(); |
367 | } |
368 | |
369 | bool SharedFunctionInfo::HasOuterScopeInfo() const { |
370 | ScopeInfo outer_info; |
371 | if (!is_compiled()) { |
372 | if (!outer_scope_info()->IsScopeInfo()) return false; |
373 | outer_info = ScopeInfo::cast(outer_scope_info()); |
374 | } else { |
375 | if (!scope_info()->HasOuterScopeInfo()) return false; |
376 | outer_info = scope_info()->OuterScopeInfo(); |
377 | } |
378 | return outer_info->length() > 0; |
379 | } |
380 | |
381 | ScopeInfo SharedFunctionInfo::GetOuterScopeInfo() const { |
382 | DCHECK(HasOuterScopeInfo()); |
383 | if (!is_compiled()) return ScopeInfo::cast(outer_scope_info()); |
384 | return scope_info()->OuterScopeInfo(); |
385 | } |
386 | |
387 | void SharedFunctionInfo::set_outer_scope_info(HeapObject value, |
388 | WriteBarrierMode mode) { |
389 | DCHECK(!is_compiled()); |
390 | DCHECK(raw_outer_scope_info_or_feedback_metadata()->IsTheHole()); |
391 | DCHECK(value->IsScopeInfo() || value->IsTheHole()); |
392 | set_raw_outer_scope_info_or_feedback_metadata(value, mode); |
393 | } |
394 | |
395 | bool SharedFunctionInfo::HasFeedbackMetadata() const { |
396 | return raw_outer_scope_info_or_feedback_metadata()->IsFeedbackMetadata(); |
397 | } |
398 | |
399 | FeedbackMetadata SharedFunctionInfo::feedback_metadata() const { |
400 | DCHECK(HasFeedbackMetadata()); |
401 | return FeedbackMetadata::cast(raw_outer_scope_info_or_feedback_metadata()); |
402 | } |
403 | |
404 | void SharedFunctionInfo::set_feedback_metadata(FeedbackMetadata value, |
405 | WriteBarrierMode mode) { |
406 | DCHECK(!HasFeedbackMetadata()); |
407 | DCHECK(value->IsFeedbackMetadata()); |
408 | set_raw_outer_scope_info_or_feedback_metadata(value, mode); |
409 | } |
410 | |
411 | bool SharedFunctionInfo::is_compiled() const { |
412 | Object data = function_data(); |
413 | return data != Smi::FromEnum(Builtins::kCompileLazy) && |
414 | !data->IsUncompiledData(); |
415 | } |
416 | |
417 | IsCompiledScope SharedFunctionInfo::is_compiled_scope() const { |
418 | return IsCompiledScope(*this, GetIsolate()); |
419 | } |
420 | |
421 | IsCompiledScope::IsCompiledScope(const SharedFunctionInfo shared, |
422 | Isolate* isolate) |
423 | : retain_bytecode_(shared->HasBytecodeArray() |
424 | ? handle(shared->GetBytecodeArray(), isolate) |
425 | : MaybeHandle<BytecodeArray>()), |
426 | is_compiled_(shared->is_compiled()) { |
427 | DCHECK_IMPLIES(!retain_bytecode_.is_null(), is_compiled()); |
428 | } |
429 | |
430 | bool SharedFunctionInfo::has_simple_parameters() { |
431 | return scope_info()->HasSimpleParameters(); |
432 | } |
433 | |
434 | bool SharedFunctionInfo::IsApiFunction() const { |
435 | return function_data()->IsFunctionTemplateInfo(); |
436 | } |
437 | |
438 | FunctionTemplateInfo SharedFunctionInfo::get_api_func_data() { |
439 | DCHECK(IsApiFunction()); |
440 | return FunctionTemplateInfo::cast(function_data()); |
441 | } |
442 | |
443 | bool SharedFunctionInfo::HasBytecodeArray() const { |
444 | return function_data()->IsBytecodeArray() || |
445 | function_data()->IsInterpreterData(); |
446 | } |
447 | |
448 | BytecodeArray SharedFunctionInfo::GetBytecodeArray() const { |
449 | DCHECK(HasBytecodeArray()); |
450 | if (HasDebugInfo() && GetDebugInfo()->HasInstrumentedBytecodeArray()) { |
451 | return GetDebugInfo()->OriginalBytecodeArray(); |
452 | } else if (function_data()->IsBytecodeArray()) { |
453 | return BytecodeArray::cast(function_data()); |
454 | } else { |
455 | DCHECK(function_data()->IsInterpreterData()); |
456 | return InterpreterData::cast(function_data())->bytecode_array(); |
457 | } |
458 | } |
459 | |
460 | BytecodeArray SharedFunctionInfo::GetDebugBytecodeArray() const { |
461 | DCHECK(HasBytecodeArray()); |
462 | DCHECK(HasDebugInfo() && GetDebugInfo()->HasInstrumentedBytecodeArray()); |
463 | if (function_data()->IsBytecodeArray()) { |
464 | return BytecodeArray::cast(function_data()); |
465 | } else { |
466 | DCHECK(function_data()->IsInterpreterData()); |
467 | return InterpreterData::cast(function_data())->bytecode_array(); |
468 | } |
469 | } |
470 | |
471 | void SharedFunctionInfo::SetDebugBytecodeArray(BytecodeArray bytecode) { |
472 | DCHECK(HasBytecodeArray()); |
473 | if (function_data()->IsBytecodeArray()) { |
474 | set_function_data(bytecode); |
475 | } else { |
476 | DCHECK(function_data()->IsInterpreterData()); |
477 | interpreter_data()->set_bytecode_array(bytecode); |
478 | } |
479 | } |
480 | |
481 | void SharedFunctionInfo::set_bytecode_array(BytecodeArray bytecode) { |
482 | DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy) || |
483 | HasUncompiledData()); |
484 | set_function_data(bytecode); |
485 | } |
486 | |
487 | bool SharedFunctionInfo::ShouldFlushBytecode(BytecodeFlushMode mode) { |
488 | if (mode == BytecodeFlushMode::kDoNotFlushBytecode) return false; |
489 | |
490 | // TODO(rmcilroy): Enable bytecode flushing for resumable functions. |
491 | if (IsResumableFunction(kind()) || !allows_lazy_compilation()) { |
492 | return false; |
493 | } |
494 | |
495 | // Get a snapshot of the function data field, and if it is a bytecode array, |
496 | // check if it is old. Note, this is done this way since this function can be |
497 | // called by the concurrent marker. |
498 | Object data = function_data(); |
499 | if (!data->IsBytecodeArray()) return false; |
500 | |
501 | if (mode == BytecodeFlushMode::kStressFlushBytecode) return true; |
502 | |
503 | BytecodeArray bytecode = BytecodeArray::cast(data); |
504 | |
505 | return bytecode->IsOld(); |
506 | } |
507 | |
508 | Code SharedFunctionInfo::InterpreterTrampoline() const { |
509 | DCHECK(HasInterpreterData()); |
510 | return interpreter_data()->interpreter_trampoline(); |
511 | } |
512 | |
513 | bool SharedFunctionInfo::HasInterpreterData() const { |
514 | return function_data()->IsInterpreterData(); |
515 | } |
516 | |
517 | InterpreterData SharedFunctionInfo::interpreter_data() const { |
518 | DCHECK(HasInterpreterData()); |
519 | return InterpreterData::cast(function_data()); |
520 | } |
521 | |
522 | void SharedFunctionInfo::set_interpreter_data( |
523 | InterpreterData interpreter_data) { |
524 | DCHECK(FLAG_interpreted_frames_native_stack); |
525 | set_function_data(interpreter_data); |
526 | } |
527 | |
528 | bool SharedFunctionInfo::HasAsmWasmData() const { |
529 | return function_data()->IsAsmWasmData(); |
530 | } |
531 | |
532 | AsmWasmData SharedFunctionInfo::asm_wasm_data() const { |
533 | DCHECK(HasAsmWasmData()); |
534 | return AsmWasmData::cast(function_data()); |
535 | } |
536 | |
537 | void SharedFunctionInfo::set_asm_wasm_data(AsmWasmData data) { |
538 | DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy) || |
539 | HasUncompiledData() || HasAsmWasmData()); |
540 | set_function_data(data); |
541 | } |
542 | |
543 | bool SharedFunctionInfo::HasBuiltinId() const { |
544 | return function_data()->IsSmi(); |
545 | } |
546 | |
547 | int SharedFunctionInfo::builtin_id() const { |
548 | DCHECK(HasBuiltinId()); |
549 | int id = Smi::ToInt(function_data()); |
550 | DCHECK(Builtins::IsBuiltinId(id)); |
551 | return id; |
552 | } |
553 | |
554 | void SharedFunctionInfo::set_builtin_id(int builtin_id) { |
555 | DCHECK(Builtins::IsBuiltinId(builtin_id)); |
556 | set_function_data(Smi::FromInt(builtin_id), SKIP_WRITE_BARRIER); |
557 | } |
558 | |
559 | bool SharedFunctionInfo::HasUncompiledData() const { |
560 | return function_data()->IsUncompiledData(); |
561 | } |
562 | |
563 | UncompiledData SharedFunctionInfo::uncompiled_data() const { |
564 | DCHECK(HasUncompiledData()); |
565 | return UncompiledData::cast(function_data()); |
566 | } |
567 | |
568 | void SharedFunctionInfo::set_uncompiled_data(UncompiledData uncompiled_data) { |
569 | DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy)); |
570 | DCHECK(uncompiled_data->IsUncompiledData()); |
571 | set_function_data(uncompiled_data); |
572 | } |
573 | |
574 | bool SharedFunctionInfo::HasUncompiledDataWithPreparseData() const { |
575 | return function_data()->IsUncompiledDataWithPreparseData(); |
576 | } |
577 | |
578 | UncompiledDataWithPreparseData |
579 | SharedFunctionInfo::uncompiled_data_with_preparse_data() const { |
580 | DCHECK(HasUncompiledDataWithPreparseData()); |
581 | return UncompiledDataWithPreparseData::cast(function_data()); |
582 | } |
583 | |
584 | void SharedFunctionInfo::set_uncompiled_data_with_preparse_data( |
585 | UncompiledDataWithPreparseData uncompiled_data_with_preparse_data) { |
586 | DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy)); |
587 | DCHECK( |
588 | uncompiled_data_with_preparse_data->IsUncompiledDataWithPreparseData()); |
589 | set_function_data(uncompiled_data_with_preparse_data); |
590 | } |
591 | |
592 | bool SharedFunctionInfo::HasUncompiledDataWithoutPreparseData() const { |
593 | return function_data()->IsUncompiledDataWithoutPreparseData(); |
594 | } |
595 | |
596 | void SharedFunctionInfo::ClearPreparseData() { |
597 | DCHECK(HasUncompiledDataWithPreparseData()); |
598 | UncompiledDataWithPreparseData data = uncompiled_data_with_preparse_data(); |
599 | |
600 | // Trim off the pre-parsed scope data from the uncompiled data by swapping the |
601 | // map, leaving only an uncompiled data without pre-parsed scope. |
602 | DisallowHeapAllocation no_gc; |
603 | Heap* heap = GetHeapFromWritableObject(data); |
604 | |
605 | // Swap the map. |
606 | heap->NotifyObjectLayoutChange(data, UncompiledDataWithPreparseData::kSize, |
607 | no_gc); |
608 | STATIC_ASSERT(UncompiledDataWithoutPreparseData::kSize < |
609 | UncompiledDataWithPreparseData::kSize); |
610 | STATIC_ASSERT(UncompiledDataWithoutPreparseData::kSize == |
611 | UncompiledData::kSize); |
612 | data->synchronized_set_map( |
613 | GetReadOnlyRoots().uncompiled_data_without_preparse_data_map()); |
614 | |
615 | // Fill the remaining space with filler. |
616 | heap->CreateFillerObjectAt( |
617 | data->address() + UncompiledDataWithoutPreparseData::kSize, |
618 | UncompiledDataWithPreparseData::kSize - |
619 | UncompiledDataWithoutPreparseData::kSize, |
620 | ClearRecordedSlots::kNo); |
621 | |
622 | // Ensure that the clear was successful. |
623 | DCHECK(HasUncompiledDataWithoutPreparseData()); |
624 | } |
625 | |
626 | OBJECT_CONSTRUCTORS_IMPL(SharedFunctionInfoWithID, SharedFunctionInfo) |
627 | CAST_ACCESSOR(SharedFunctionInfoWithID) |
628 | INT_ACCESSORS(SharedFunctionInfoWithID, unique_id, kUniqueIdOffset) |
629 | |
630 | // static |
631 | void UncompiledData::Initialize( |
632 | UncompiledData data, String inferred_name, int start_position, |
633 | int end_position, int function_literal_id, |
634 | std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)> |
635 | gc_notify_updated_slot) { |
636 | data->set_inferred_name(inferred_name); |
637 | gc_notify_updated_slot( |
638 | data, data->RawField(UncompiledData::kInferredNameOffset), inferred_name); |
639 | data->set_start_position(start_position); |
640 | data->set_end_position(end_position); |
641 | data->set_function_literal_id(function_literal_id); |
642 | data->clear_padding(); |
643 | } |
644 | |
645 | void UncompiledDataWithPreparseData::Initialize( |
646 | UncompiledDataWithPreparseData data, String inferred_name, |
647 | int start_position, int end_position, int function_literal_id, |
648 | PreparseData scope_data, |
649 | std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)> |
650 | gc_notify_updated_slot) { |
651 | UncompiledData::Initialize(data, inferred_name, start_position, end_position, |
652 | function_literal_id, gc_notify_updated_slot); |
653 | data->set_preparse_data(scope_data); |
654 | gc_notify_updated_slot( |
655 | data, data->RawField(UncompiledDataWithPreparseData::kPreparseDataOffset), |
656 | scope_data); |
657 | } |
658 | |
659 | bool UncompiledData::has_function_literal_id() { |
660 | return function_literal_id() != kFunctionLiteralIdInvalid; |
661 | } |
662 | |
663 | bool SharedFunctionInfo::HasWasmExportedFunctionData() const { |
664 | return function_data()->IsWasmExportedFunctionData(); |
665 | } |
666 | |
667 | Object SharedFunctionInfo::script() const { |
668 | Object maybe_script = script_or_debug_info(); |
669 | if (maybe_script->IsDebugInfo()) { |
670 | return DebugInfo::cast(maybe_script)->script(); |
671 | } |
672 | return maybe_script; |
673 | } |
674 | |
675 | void SharedFunctionInfo::set_script(Object script) { |
676 | Object maybe_debug_info = script_or_debug_info(); |
677 | if (maybe_debug_info->IsDebugInfo()) { |
678 | DebugInfo::cast(maybe_debug_info)->set_script(script); |
679 | } else { |
680 | set_script_or_debug_info(script); |
681 | } |
682 | } |
683 | |
684 | bool SharedFunctionInfo::HasDebugInfo() const { |
685 | return script_or_debug_info()->IsDebugInfo(); |
686 | } |
687 | |
688 | DebugInfo SharedFunctionInfo::GetDebugInfo() const { |
689 | DCHECK(HasDebugInfo()); |
690 | return DebugInfo::cast(script_or_debug_info()); |
691 | } |
692 | |
693 | void SharedFunctionInfo::SetDebugInfo(DebugInfo debug_info) { |
694 | DCHECK(!HasDebugInfo()); |
695 | DCHECK_EQ(debug_info->script(), script_or_debug_info()); |
696 | set_script_or_debug_info(debug_info); |
697 | } |
698 | |
699 | bool SharedFunctionInfo::HasInferredName() { |
700 | Object scope_info = name_or_scope_info(); |
701 | if (scope_info->IsScopeInfo()) { |
702 | return ScopeInfo::cast(scope_info)->HasInferredFunctionName(); |
703 | } |
704 | return HasUncompiledData(); |
705 | } |
706 | |
707 | String SharedFunctionInfo::inferred_name() { |
708 | Object maybe_scope_info = name_or_scope_info(); |
709 | if (maybe_scope_info->IsScopeInfo()) { |
710 | ScopeInfo scope_info = ScopeInfo::cast(maybe_scope_info); |
711 | if (scope_info->HasInferredFunctionName()) { |
712 | Object name = ScopeInfo::cast(maybe_scope_info)->InferredFunctionName(); |
713 | if (name->IsString()) return String::cast(name); |
714 | } |
715 | } else if (HasUncompiledData()) { |
716 | return uncompiled_data()->inferred_name(); |
717 | } |
718 | return GetReadOnlyRoots().empty_string(); |
719 | } |
720 | |
721 | bool SharedFunctionInfo::IsUserJavaScript() { |
722 | Object script_obj = script(); |
723 | if (script_obj->IsUndefined()) return false; |
724 | Script script = Script::cast(script_obj); |
725 | return script->IsUserJavaScript(); |
726 | } |
727 | |
728 | bool SharedFunctionInfo::IsSubjectToDebugging() { |
729 | return IsUserJavaScript() && !HasAsmWasmData(); |
730 | } |
731 | |
732 | bool SharedFunctionInfo::CanDiscardCompiled() const { |
733 | bool can_decompile = (HasBytecodeArray() || HasAsmWasmData() || |
734 | HasUncompiledDataWithPreparseData()); |
735 | return can_decompile; |
736 | } |
737 | |
738 | } // namespace internal |
739 | } // namespace v8 |
740 | |
741 | #include "src/objects/object-macros-undef.h" |
742 | |
743 | #endif // V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_ |
744 | |