| // Copyright 2017 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_ | |
| #define V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_ | |
| #include "src/objects/shared-function-info.h" | |
| #include "src/handles-inl.h" | |
| #include "src/heap/heap-inl.h" | |
| #include "src/objects/debug-objects-inl.h" | |
| #include "src/objects/scope-info.h" | |
| #include "src/objects/templates.h" | |
| // Has to be the last include (doesn't have include guards): | |
| #include "src/objects/object-macros.h" | |
| namespace v8 { | |
| namespace internal { | |
| CAST_ACCESSOR(PreParsedScopeData) | |
| ACCESSORS(PreParsedScopeData, scope_data, PodArray<uint8_t>, kScopeDataOffset) | |
| INT_ACCESSORS(PreParsedScopeData, length, kLengthOffset) | |
| Object* PreParsedScopeData::child_data(int index) const { | |
| DCHECK_GE(index, 0); | |
| DCHECK_LT(index, this->length()); | |
| int offset = kChildDataStartOffset + index * kPointerSize; | |
| return RELAXED_READ_FIELD(this, offset); | |
| } | |
| void PreParsedScopeData::set_child_data(int index, Object* value, | |
| WriteBarrierMode mode) { | |
| DCHECK_GE(index, 0); | |
| DCHECK_LT(index, this->length()); | |
| int offset = kChildDataStartOffset + index * kPointerSize; | |
| RELAXED_WRITE_FIELD(this, offset, value); | |
| CONDITIONAL_WRITE_BARRIER(this, offset, value, mode); | |
| } | |
| Object** PreParsedScopeData::child_data_start() const { | |
| return HeapObject::RawField(this, kChildDataStartOffset); | |
| } | |
| void PreParsedScopeData::clear_padding() { | |
| // For archs where kIntSize < kPointerSize, there will be padding between the | |
| // length field and the start of the child data. | |
| if (kUnalignedChildDataStartOffset < kChildDataStartOffset) { | |
| memset(reinterpret_cast<void*>(address() + kUnalignedChildDataStartOffset), | |
| 0, kChildDataStartOffset - kUnalignedChildDataStartOffset); | |
| } | |
| } | |
| CAST_ACCESSOR(UncompiledData) | |
| ACCESSORS(UncompiledData, inferred_name, String, kInferredNameOffset) | |
| INT32_ACCESSORS(UncompiledData, start_position, kStartPositionOffset) | |
| INT32_ACCESSORS(UncompiledData, end_position, kEndPositionOffset) | |
| INT32_ACCESSORS(UncompiledData, function_literal_id, kFunctionLiteralIdOffset) | |
| void UncompiledData::clear_padding() { | |
| // For archs where kIntSize < kPointerSize, there will be padding at the end | |
| // of the data. | |
| if (kUnalignedSize < kSize) { | |
| memset(reinterpret_cast<void*>(address() + kUnalignedSize), 0, | |
| kSize - kUnalignedSize); | |
| } | |
| } | |
| CAST_ACCESSOR(UncompiledDataWithoutPreParsedScope) | |
| CAST_ACCESSOR(UncompiledDataWithPreParsedScope) | |
| ACCESSORS(UncompiledDataWithPreParsedScope, pre_parsed_scope_data, | |
| PreParsedScopeData, kPreParsedScopeDataOffset) | |
| CAST_ACCESSOR(InterpreterData) | |
| ACCESSORS(InterpreterData, bytecode_array, BytecodeArray, kBytecodeArrayOffset) | |
| ACCESSORS(InterpreterData, interpreter_trampoline, Code, | |
| kInterpreterTrampolineOffset) | |
| CAST_ACCESSOR(SharedFunctionInfo) | |
| DEFINE_DEOPT_ELEMENT_ACCESSORS(SharedFunctionInfo, Object) | |
| ACCESSORS(SharedFunctionInfo, name_or_scope_info, Object, | |
| kNameOrScopeInfoOffset) | |
| ACCESSORS(SharedFunctionInfo, function_data, Object, kFunctionDataOffset) | |
| ACCESSORS(SharedFunctionInfo, script_or_debug_info, Object, | |
| kScriptOrDebugInfoOffset) | |
| #if V8_SFI_HAS_UNIQUE_ID | |
| INT_ACCESSORS(SharedFunctionInfo, unique_id, kUniqueIdOffset) | |
| #endif | |
| UINT16_ACCESSORS(SharedFunctionInfo, length, kLengthOffset) | |
| UINT16_ACCESSORS(SharedFunctionInfo, internal_formal_parameter_count, | |
| kFormalParameterCountOffset) | |
| UINT8_ACCESSORS(SharedFunctionInfo, expected_nof_properties, | |
| kExpectedNofPropertiesOffset) | |
| UINT8_ACCESSORS(SharedFunctionInfo, raw_builtin_function_id, kBuiltinFunctionId) | |
| UINT16_ACCESSORS(SharedFunctionInfo, raw_function_token_offset, | |
| kFunctionTokenOffsetOffset) | |
| INT_ACCESSORS(SharedFunctionInfo, flags, kFlagsOffset) | |
| bool SharedFunctionInfo::HasSharedName() const { | |
| Object* value = name_or_scope_info(); | |
| if (value->IsScopeInfo()) { | |
| return ScopeInfo::cast(value)->HasSharedFunctionName(); | |
| } | |
| return value != kNoSharedNameSentinel; | |
| } | |
| String* SharedFunctionInfo::Name() const { | |
| if (!HasSharedName()) return GetReadOnlyRoots().empty_string(); | |
| Object* value = name_or_scope_info(); | |
| if (value->IsScopeInfo()) { | |
| if (ScopeInfo::cast(value)->HasFunctionName()) { | |
| return String::cast(ScopeInfo::cast(value)->FunctionName()); | |
| } | |
| return GetReadOnlyRoots().empty_string(); | |
| } | |
| return String::cast(value); | |
| } | |
| void SharedFunctionInfo::SetName(String* name) { | |
| Object* maybe_scope_info = name_or_scope_info(); | |
| if (maybe_scope_info->IsScopeInfo()) { | |
| ScopeInfo::cast(maybe_scope_info)->SetFunctionName(name); | |
| } else { | |
| DCHECK(maybe_scope_info->IsString() || | |
| maybe_scope_info == kNoSharedNameSentinel); | |
| set_name_or_scope_info(name); | |
| } | |
| UpdateFunctionMapIndex(); | |
| } | |
| AbstractCode* SharedFunctionInfo::abstract_code() { | |
| if (HasBytecodeArray()) { | |
| return AbstractCode::cast(GetBytecodeArray()); | |
| } else { | |
| return AbstractCode::cast(GetCode()); | |
| } | |
| } | |
| int SharedFunctionInfo::function_token_position() const { | |
| int offset = raw_function_token_offset(); | |
| if (offset == kFunctionTokenOutOfRange) { | |
| return kNoSourcePosition; | |
| } else { | |
| return StartPosition() - offset; | |
| } | |
| } | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_wrapped, | |
| SharedFunctionInfo::IsWrappedBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, allows_lazy_compilation, | |
| SharedFunctionInfo::AllowLazyCompilationBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, has_duplicate_parameters, | |
| SharedFunctionInfo::HasDuplicateParametersBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_declaration, | |
| SharedFunctionInfo::IsDeclarationBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, native, | |
| SharedFunctionInfo::IsNativeBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_asm_wasm_broken, | |
| SharedFunctionInfo::IsAsmWasmBrokenBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, | |
| requires_instance_fields_initializer, | |
| SharedFunctionInfo::RequiresInstanceFieldsInitializer) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, name_should_print_as_anonymous, | |
| SharedFunctionInfo::NameShouldPrintAsAnonymousBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_anonymous_expression, | |
| SharedFunctionInfo::IsAnonymousExpressionBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, deserialized, | |
| SharedFunctionInfo::IsDeserializedBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, has_reported_binary_coverage, | |
| SharedFunctionInfo::HasReportedBinaryCoverageBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_named_expression, | |
| SharedFunctionInfo::IsNamedExpressionBit) | |
| BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_toplevel, | |
| SharedFunctionInfo::IsTopLevelBit) | |
| bool SharedFunctionInfo::optimization_disabled() const { | |
| return disable_optimization_reason() != BailoutReason::kNoReason; | |
| } | |
| BailoutReason SharedFunctionInfo::disable_optimization_reason() const { | |
| return DisabledOptimizationReasonBits::decode(flags()); | |
| } | |
| LanguageMode SharedFunctionInfo::language_mode() const { | |
| STATIC_ASSERT(LanguageModeSize == 2); | |
| return construct_language_mode(IsStrictBit::decode(flags())); | |
| } | |
| void SharedFunctionInfo::set_language_mode(LanguageMode language_mode) { | |
| STATIC_ASSERT(LanguageModeSize == 2); | |
| // We only allow language mode transitions that set the same language mode | |
| // again or go up in the chain: | |
| DCHECK(is_sloppy(this->language_mode()) || is_strict(language_mode)); | |
| int hints = flags(); | |
| hints = IsStrictBit::update(hints, is_strict(language_mode)); | |
| set_flags(hints); | |
| UpdateFunctionMapIndex(); | |
| } | |
| FunctionKind SharedFunctionInfo::kind() const { | |
| return FunctionKindBits::decode(flags()); | |
| } | |
| void SharedFunctionInfo::set_kind(FunctionKind kind) { | |
| int hints = flags(); | |
| hints = FunctionKindBits::update(hints, kind); | |
| hints = IsClassConstructorBit::update(hints, IsClassConstructor(kind)); | |
| hints = IsDerivedConstructorBit::update(hints, IsDerivedConstructor(kind)); | |
| set_flags(hints); | |
| UpdateFunctionMapIndex(); | |
| } | |
| bool SharedFunctionInfo::needs_home_object() const { | |
| return NeedsHomeObjectBit::decode(flags()); | |
| } | |
| void SharedFunctionInfo::set_needs_home_object(bool value) { | |
| int hints = flags(); | |
| hints = NeedsHomeObjectBit::update(hints, value); | |
| set_flags(hints); | |
| UpdateFunctionMapIndex(); | |
| } | |
| bool SharedFunctionInfo::construct_as_builtin() const { | |
| return ConstructAsBuiltinBit::decode(flags()); | |
| } | |
| void SharedFunctionInfo::CalculateConstructAsBuiltin() { | |
| bool uses_builtins_construct_stub = false; | |
| if (HasBuiltinId()) { | |
| int id = builtin_id(); | |
| if (id != Builtins::kCompileLazy && id != Builtins::kEmptyFunction) { | |
| uses_builtins_construct_stub = true; | |
| } | |
| } else if (IsApiFunction()) { | |
| uses_builtins_construct_stub = true; | |
| } | |
| int f = flags(); | |
| f = ConstructAsBuiltinBit::update(f, uses_builtins_construct_stub); | |
| set_flags(f); | |
| } | |
| int SharedFunctionInfo::function_map_index() const { | |
| // Note: Must be kept in sync with the FastNewClosure builtin. | |
| int index = | |
| Context::FIRST_FUNCTION_MAP_INDEX + FunctionMapIndexBits::decode(flags()); | |
| DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); | |
| return index; | |
| } | |
| void SharedFunctionInfo::set_function_map_index(int index) { | |
| STATIC_ASSERT(Context::LAST_FUNCTION_MAP_INDEX <= | |
| Context::FIRST_FUNCTION_MAP_INDEX + FunctionMapIndexBits::kMax); | |
| DCHECK_LE(Context::FIRST_FUNCTION_MAP_INDEX, index); | |
| DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); | |
| index -= Context::FIRST_FUNCTION_MAP_INDEX; | |
| set_flags(FunctionMapIndexBits::update(flags(), index)); | |
| } | |
| void SharedFunctionInfo::clear_padding() { | |
| memset(reinterpret_cast<void*>(this->address() + kSize), 0, | |
| kAlignedSize - kSize); | |
| } | |
| void SharedFunctionInfo::UpdateFunctionMapIndex() { | |
| int map_index = Context::FunctionMapIndex( | |
| language_mode(), kind(), true, HasSharedName(), needs_home_object()); | |
| set_function_map_index(map_index); | |
| } | |
| void SharedFunctionInfo::DontAdaptArguments() { | |
| // TODO(leszeks): Revise this DCHECK now that the code field is gone. | |
| DCHECK(!HasWasmExportedFunctionData()); | |
| set_internal_formal_parameter_count(kDontAdaptArgumentsSentinel); | |
| } | |
| int SharedFunctionInfo::StartPosition() const { | |
| Object* maybe_scope_info = name_or_scope_info(); | |
| if (maybe_scope_info->IsScopeInfo()) { | |
| ScopeInfo* info = ScopeInfo::cast(maybe_scope_info); | |
| if (info->HasPositionInfo()) { | |
| return info->StartPosition(); | |
| } | |
| } else if (HasUncompiledData()) { | |
| // Works with or without scope. | |
| return uncompiled_data()->start_position(); | |
| } else if (IsApiFunction() || HasBuiltinId()) { | |
| DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy); | |
| return 0; | |
| } | |
| return kNoSourcePosition; | |
| } | |
| int SharedFunctionInfo::EndPosition() const { | |
| Object* maybe_scope_info = name_or_scope_info(); | |
| if (maybe_scope_info->IsScopeInfo()) { | |
| ScopeInfo* info = ScopeInfo::cast(maybe_scope_info); | |
| if (info->HasPositionInfo()) { | |
| return info->EndPosition(); | |
| } | |
| } else if (HasUncompiledData()) { | |
| // Works with or without scope. | |
| return uncompiled_data()->end_position(); | |
| } else if (IsApiFunction() || HasBuiltinId()) { | |
| DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy); | |
| return 0; | |
| } | |
| return kNoSourcePosition; | |
| } | |
| void SharedFunctionInfo::SetPosition(int start_position, int end_position) { | |
| Object* maybe_scope_info = name_or_scope_info(); | |
| if (maybe_scope_info->IsScopeInfo()) { | |
| ScopeInfo* info = ScopeInfo::cast(maybe_scope_info); | |
| if (info->HasPositionInfo()) { | |
| info->SetPositionInfo(start_position, end_position); | |
| } | |
| } else if (HasUncompiledData()) { | |
| if (HasUncompiledDataWithPreParsedScope()) { | |
| // Clear out preparsed scope data, since the position setter invalidates | |
| // any scope data. | |
| ClearPreParsedScopeData(); | |
| } | |
| uncompiled_data()->set_start_position(start_position); | |
| uncompiled_data()->set_end_position(end_position); | |
| } else { | |
| UNREACHABLE(); | |
| } | |
| } | |
| bool SharedFunctionInfo::IsInterpreted() const { return HasBytecodeArray(); } | |
| ScopeInfo* SharedFunctionInfo::scope_info() const { | |
| Object* maybe_scope_info = name_or_scope_info(); | |
| if (maybe_scope_info->IsScopeInfo()) { | |
| return ScopeInfo::cast(maybe_scope_info); | |
| } | |
| return ScopeInfo::Empty(GetIsolate()); | |
| } | |
| void SharedFunctionInfo::set_scope_info(ScopeInfo* scope_info, | |
| WriteBarrierMode mode) { | |
| // Move the existing name onto the ScopeInfo. | |
| Object* name = name_or_scope_info(); | |
| if (name->IsScopeInfo()) { | |
| name = ScopeInfo::cast(name)->FunctionName(); | |
| } | |
| DCHECK(name->IsString() || name == kNoSharedNameSentinel); | |
| // Only set the function name for function scopes. | |
| scope_info->SetFunctionName(name); | |
| if (HasInferredName() && inferred_name()->length() != 0) { | |
| scope_info->SetInferredFunctionName(inferred_name()); | |
| } | |
| WRITE_FIELD(this, kNameOrScopeInfoOffset, | |
| reinterpret_cast<Object*>(scope_info)); | |
| CONDITIONAL_WRITE_BARRIER(this, kNameOrScopeInfoOffset, | |
| reinterpret_cast<Object*>(scope_info), mode); | |
| } | |
| ACCESSORS(SharedFunctionInfo, raw_outer_scope_info_or_feedback_metadata, | |
| HeapObject, kOuterScopeInfoOrFeedbackMetadataOffset) | |
| HeapObject* SharedFunctionInfo::outer_scope_info() const { | |
| DCHECK(!is_compiled()); | |
| DCHECK(!HasFeedbackMetadata()); | |
| return raw_outer_scope_info_or_feedback_metadata(); | |
| } | |
| bool SharedFunctionInfo::HasOuterScopeInfo() const { | |
| ScopeInfo* outer_info = nullptr; | |
| if (!is_compiled()) { | |
| if (!outer_scope_info()->IsScopeInfo()) return false; | |
| outer_info = ScopeInfo::cast(outer_scope_info()); | |
| } else { | |
| if (!scope_info()->HasOuterScopeInfo()) return false; | |
| outer_info = scope_info()->OuterScopeInfo(); | |
| } | |
| return outer_info->length() > 0; | |
| } | |
| ScopeInfo* SharedFunctionInfo::GetOuterScopeInfo() const { | |
| DCHECK(HasOuterScopeInfo()); | |
| if (!is_compiled()) return ScopeInfo::cast(outer_scope_info()); | |
| return scope_info()->OuterScopeInfo(); | |
| } | |
| void SharedFunctionInfo::set_outer_scope_info(HeapObject* value, | |
| WriteBarrierMode mode) { | |
| DCHECK(!is_compiled()); | |
| DCHECK(raw_outer_scope_info_or_feedback_metadata()->IsTheHole()); | |
| DCHECK(value->IsScopeInfo() || value->IsTheHole()); | |
| return set_raw_outer_scope_info_or_feedback_metadata(value, mode); | |
| } | |
| bool SharedFunctionInfo::HasFeedbackMetadata() const { | |
| return raw_outer_scope_info_or_feedback_metadata()->IsFeedbackMetadata(); | |
| } | |
| FeedbackMetadata* SharedFunctionInfo::feedback_metadata() const { | |
| DCHECK(HasFeedbackMetadata()); | |
| return FeedbackMetadata::cast(raw_outer_scope_info_or_feedback_metadata()); | |
| } | |
| void SharedFunctionInfo::set_feedback_metadata(FeedbackMetadata* value, | |
| WriteBarrierMode mode) { | |
| DCHECK(!HasFeedbackMetadata()); | |
| DCHECK(value->IsFeedbackMetadata()); | |
| return set_raw_outer_scope_info_or_feedback_metadata(value, mode); | |
| } | |
| bool SharedFunctionInfo::is_compiled() const { | |
| Object* data = function_data(); | |
| return data != Smi::FromEnum(Builtins::kCompileLazy) && | |
| !data->IsUncompiledData(); | |
| } | |
| uint16_t SharedFunctionInfo::GetLength() const { | |
| DCHECK(is_compiled()); | |
| DCHECK(HasLength()); | |
| return length(); | |
| } | |
| bool SharedFunctionInfo::HasLength() const { | |
| return length() != kInvalidLength; | |
| } | |
| bool SharedFunctionInfo::has_simple_parameters() { | |
| return scope_info()->HasSimpleParameters(); | |
| } | |
| bool SharedFunctionInfo::IsApiFunction() const { | |
| return function_data()->IsFunctionTemplateInfo(); | |
| } | |
| FunctionTemplateInfo* SharedFunctionInfo::get_api_func_data() { | |
| DCHECK(IsApiFunction()); | |
| return FunctionTemplateInfo::cast(function_data()); | |
| } | |
| bool SharedFunctionInfo::HasBytecodeArray() const { | |
| return function_data()->IsBytecodeArray() || | |
| function_data()->IsInterpreterData(); | |
| } | |
| BytecodeArray* SharedFunctionInfo::GetBytecodeArray() const { | |
| DCHECK(HasBytecodeArray()); | |
| if (HasDebugInfo() && GetDebugInfo()->HasInstrumentedBytecodeArray()) { | |
| return GetDebugInfo()->OriginalBytecodeArray(); | |
| } else if (function_data()->IsBytecodeArray()) { | |
| return BytecodeArray::cast(function_data()); | |
| } else { | |
| DCHECK(function_data()->IsInterpreterData()); | |
| return InterpreterData::cast(function_data())->bytecode_array(); | |
| } | |
| } | |
| BytecodeArray* SharedFunctionInfo::GetDebugBytecodeArray() const { | |
| DCHECK(HasBytecodeArray()); | |
| DCHECK(HasDebugInfo() && GetDebugInfo()->HasInstrumentedBytecodeArray()); | |
| if (function_data()->IsBytecodeArray()) { | |
| return BytecodeArray::cast(function_data()); | |
| } else { | |
| DCHECK(function_data()->IsInterpreterData()); | |
| return InterpreterData::cast(function_data())->bytecode_array(); | |
| } | |
| } | |
| void SharedFunctionInfo::SetDebugBytecodeArray(BytecodeArray* bytecode) { | |
| DCHECK(HasBytecodeArray()); | |
| if (function_data()->IsBytecodeArray()) { | |
| set_function_data(bytecode); | |
| } else { | |
| DCHECK(function_data()->IsInterpreterData()); | |
| interpreter_data()->set_bytecode_array(bytecode); | |
| } | |
| } | |
| void SharedFunctionInfo::set_bytecode_array(BytecodeArray* bytecode) { | |
| DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy) || | |
| HasUncompiledData()); | |
| set_function_data(bytecode); | |
| } | |
| Code* SharedFunctionInfo::InterpreterTrampoline() const { | |
| DCHECK(HasInterpreterData()); | |
| return interpreter_data()->interpreter_trampoline(); | |
| } | |
| bool SharedFunctionInfo::HasInterpreterData() const { | |
| return function_data()->IsInterpreterData(); | |
| } | |
| InterpreterData* SharedFunctionInfo::interpreter_data() const { | |
| DCHECK(HasInterpreterData()); | |
| return InterpreterData::cast(function_data()); | |
| } | |
| void SharedFunctionInfo::set_interpreter_data( | |
| InterpreterData* interpreter_data) { | |
| DCHECK(FLAG_interpreted_frames_native_stack); | |
| set_function_data(interpreter_data); | |
| } | |
| bool SharedFunctionInfo::HasAsmWasmData() const { | |
| return function_data()->IsFixedArray(); | |
| } | |
| FixedArray* SharedFunctionInfo::asm_wasm_data() const { | |
| DCHECK(HasAsmWasmData()); | |
| return FixedArray::cast(function_data()); | |
| } | |
| void SharedFunctionInfo::set_asm_wasm_data(FixedArray* data) { | |
| DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy) || | |
| HasUncompiledData() || HasAsmWasmData()); | |
| set_function_data(data); | |
| } | |
| bool SharedFunctionInfo::HasBuiltinId() const { | |
| return function_data()->IsSmi(); | |
| } | |
| int SharedFunctionInfo::builtin_id() const { | |
| DCHECK(HasBuiltinId()); | |
| int id = Smi::ToInt(function_data()); | |
| DCHECK(Builtins::IsBuiltinId(id)); | |
| return id; | |
| } | |
| void SharedFunctionInfo::set_builtin_id(int builtin_id) { | |
| DCHECK(Builtins::IsBuiltinId(builtin_id)); | |
| DCHECK_NE(builtin_id, Builtins::kDeserializeLazy); | |
| set_function_data(Smi::FromInt(builtin_id), SKIP_WRITE_BARRIER); | |
| } | |
| bool SharedFunctionInfo::HasUncompiledData() const { | |
| return function_data()->IsUncompiledData(); | |
| } | |
| UncompiledData* SharedFunctionInfo::uncompiled_data() const { | |
| DCHECK(HasUncompiledData()); | |
| return UncompiledData::cast(function_data()); | |
| } | |
| void SharedFunctionInfo::set_uncompiled_data(UncompiledData* uncompiled_data) { | |
| DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy)); | |
| DCHECK(uncompiled_data->IsUncompiledData()); | |
| set_function_data(uncompiled_data); | |
| } | |
| bool SharedFunctionInfo::HasUncompiledDataWithPreParsedScope() const { | |
| return function_data()->IsUncompiledDataWithPreParsedScope(); | |
| } | |
| UncompiledDataWithPreParsedScope* | |
| SharedFunctionInfo::uncompiled_data_with_pre_parsed_scope() const { | |
| DCHECK(HasUncompiledDataWithPreParsedScope()); | |
| return UncompiledDataWithPreParsedScope::cast(function_data()); | |
| } | |
| void SharedFunctionInfo::set_uncompiled_data_with_pre_parsed_scope( | |
| UncompiledDataWithPreParsedScope* uncompiled_data_with_pre_parsed_scope) { | |
| DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy)); | |
| DCHECK(uncompiled_data_with_pre_parsed_scope | |
| ->IsUncompiledDataWithPreParsedScope()); | |
| set_function_data(uncompiled_data_with_pre_parsed_scope); | |
| } | |
| bool SharedFunctionInfo::HasUncompiledDataWithoutPreParsedScope() const { | |
| return function_data()->IsUncompiledDataWithoutPreParsedScope(); | |
| } | |
| void SharedFunctionInfo::ClearPreParsedScopeData() { | |
| DCHECK(HasUncompiledDataWithPreParsedScope()); | |
| UncompiledDataWithPreParsedScope* data = | |
| uncompiled_data_with_pre_parsed_scope(); | |
| // Trim off the pre-parsed scope data from the uncompiled data by swapping the | |
| // map, leaving only an uncompiled data without pre-parsed scope. | |
| DisallowHeapAllocation no_gc; | |
| Heap* heap = Heap::FromWritableHeapObject(data); | |
| // Swap the map. | |
| heap->NotifyObjectLayoutChange(data, UncompiledDataWithPreParsedScope::kSize, | |
| no_gc); | |
| STATIC_ASSERT(UncompiledDataWithoutPreParsedScope::kSize < | |
| UncompiledDataWithPreParsedScope::kSize); | |
| STATIC_ASSERT(UncompiledDataWithoutPreParsedScope::kSize == | |
| UncompiledData::kSize); | |
| data->synchronized_set_map( | |
| GetReadOnlyRoots().uncompiled_data_without_pre_parsed_scope_map()); | |
| // Fill the remaining space with filler. | |
| heap->CreateFillerObjectAt( | |
| data->address() + UncompiledDataWithoutPreParsedScope::kSize, | |
| UncompiledDataWithPreParsedScope::kSize - | |
| UncompiledDataWithoutPreParsedScope::kSize, | |
| ClearRecordedSlots::kNo); | |
| // Ensure that the clear was successful. | |
| DCHECK(HasUncompiledDataWithoutPreParsedScope()); | |
| } | |
| bool SharedFunctionInfo::HasWasmExportedFunctionData() const { | |
| return function_data()->IsWasmExportedFunctionData(); | |
| } | |
| int SharedFunctionInfo::FunctionLiteralId(Isolate* isolate) const { | |
| // Fast path for the common case when the SFI is uncompiled and so the | |
| // function literal id is already in the uncompiled data. | |
| if (HasUncompiledData()) { | |
| int id = uncompiled_data()->function_literal_id(); | |
| // Make sure the id is what we should have found with the slow path. | |
| DCHECK_EQ(id, FindIndexInScript(isolate)); | |
| return id; | |
| } | |
| // Otherwise, search for the function in the SFI's script's function list, | |
| // and return its index in that list.e | |
| return FindIndexInScript(isolate); | |
| } | |
| Object* SharedFunctionInfo::script() const { | |
| Object* maybe_script = script_or_debug_info(); | |
| if (maybe_script->IsDebugInfo()) { | |
| return DebugInfo::cast(maybe_script)->script(); | |
| } | |
| return maybe_script; | |
| } | |
| void SharedFunctionInfo::set_script(Object* script) { | |
| Object* maybe_debug_info = script_or_debug_info(); | |
| if (maybe_debug_info->IsDebugInfo()) { | |
| DebugInfo::cast(maybe_debug_info)->set_script(script); | |
| } else { | |
| set_script_or_debug_info(script); | |
| } | |
| } | |
| bool SharedFunctionInfo::HasDebugInfo() const { | |
| return script_or_debug_info()->IsDebugInfo(); | |
| } | |
| DebugInfo* SharedFunctionInfo::GetDebugInfo() const { | |
| DCHECK(HasDebugInfo()); | |
| return DebugInfo::cast(script_or_debug_info()); | |
| } | |
| void SharedFunctionInfo::SetDebugInfo(DebugInfo* debug_info) { | |
| DCHECK(!HasDebugInfo()); | |
| DCHECK_EQ(debug_info->script(), script_or_debug_info()); | |
| set_script_or_debug_info(debug_info); | |
| } | |
| bool SharedFunctionInfo::HasBuiltinFunctionId() { | |
| return builtin_function_id() != BuiltinFunctionId::kInvalidBuiltinFunctionId; | |
| } | |
| BuiltinFunctionId SharedFunctionInfo::builtin_function_id() { | |
| return static_cast<BuiltinFunctionId>(raw_builtin_function_id()); | |
| } | |
| void SharedFunctionInfo::set_builtin_function_id(BuiltinFunctionId id) { | |
| set_raw_builtin_function_id(static_cast<uint8_t>(id)); | |
| } | |
| bool SharedFunctionInfo::HasInferredName() { | |
| Object* scope_info = name_or_scope_info(); | |
| if (scope_info->IsScopeInfo()) { | |
| return ScopeInfo::cast(scope_info)->HasInferredFunctionName(); | |
| } | |
| return HasUncompiledData(); | |
| } | |
| String* SharedFunctionInfo::inferred_name() { | |
| Object* maybe_scope_info = name_or_scope_info(); | |
| if (maybe_scope_info->IsScopeInfo()) { | |
| ScopeInfo* scope_info = ScopeInfo::cast(maybe_scope_info); | |
| if (scope_info->HasInferredFunctionName()) { | |
| Object* name = ScopeInfo::cast(maybe_scope_info)->InferredFunctionName(); | |
| if (name->IsString()) return String::cast(name); | |
| } | |
| } else if (HasUncompiledData()) { | |
| return uncompiled_data()->inferred_name(); | |
| } | |
| return GetReadOnlyRoots().empty_string(); | |
| } | |
| bool SharedFunctionInfo::IsUserJavaScript() { | |
| Object* script_obj = script(); | |
| if (script_obj->IsUndefined()) return false; | |
| Script* script = Script::cast(script_obj); | |
| return script->IsUserJavaScript(); | |
| } | |
| bool SharedFunctionInfo::IsSubjectToDebugging() { | |
| return IsUserJavaScript() && !HasAsmWasmData(); | |
| } | |
| bool SharedFunctionInfo::CanDiscardCompiled() const { | |
| bool can_decompile = (HasBytecodeArray() || HasAsmWasmData() || | |
| HasUncompiledDataWithPreParsedScope()); | |
| return can_decompile; | |
| } | |
| // static | |
| void SharedFunctionInfo::DiscardCompiled( | |
| Isolate* isolate, Handle<SharedFunctionInfo> shared_info) { | |
| DCHECK(shared_info->CanDiscardCompiled()); | |
| int start_position = shared_info->StartPosition(); | |
| int end_position = shared_info->EndPosition(); | |
| int function_literal_id = shared_info->FunctionLiteralId(isolate); | |
| if (shared_info->is_compiled()) { | |
| DisallowHeapAllocation no_gc; | |
| HeapObject* outer_scope_info; | |
| if (shared_info->scope_info()->HasOuterScopeInfo()) { | |
| outer_scope_info = shared_info->scope_info()->OuterScopeInfo(); | |
| } else { | |
| outer_scope_info = ReadOnlyRoots(isolate).the_hole_value(); | |
| } | |
| // Raw setter to avoid validity checks, since we're performing the unusual | |
| // task of decompiling. | |
| shared_info->set_raw_outer_scope_info_or_feedback_metadata( | |
| outer_scope_info); | |
| } else { | |
| DCHECK(shared_info->outer_scope_info()->IsScopeInfo() || | |
| shared_info->outer_scope_info()->IsTheHole()); | |
| } | |
| if (shared_info->HasUncompiledDataWithPreParsedScope()) { | |
| // If this is uncompiled data with a pre-parsed scope data, we can just | |
| // clear out the scope data and keep the uncompiled data. | |
| shared_info->ClearPreParsedScopeData(); | |
| } else { | |
| // Create a new UncompiledData, without pre-parsed scope, and update the | |
| // function data to point to it. Use the raw function data setter to avoid | |
| // validity checks, since we're performing the unusual task of decompiling. | |
| Handle<UncompiledData> data = | |
| isolate->factory()->NewUncompiledDataWithoutPreParsedScope( | |
| handle(shared_info->inferred_name(), isolate), start_position, | |
| end_position, function_literal_id); | |
| shared_info->set_function_data(*data); | |
| } | |
| } | |
| } // namespace internal | |
| } // namespace v8 | |
| #include "src/objects/object-macros-undef.h" | |
| #endif // V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_ |