blob: be6705e327d72d6a017f6056d2e4d7fe86167f2a [file] [log] [blame]
// 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.
#include <memory>
#include "src/base/bit-field.h"
#include "src/codegen/bailout-reason.h"
#include "src/objects/compressed-slots.h"
#include "src/objects/function-kind.h"
#include "src/objects/function-syntax-kind.h"
#include "src/objects/objects.h"
#include "src/objects/script.h"
#include "src/objects/slots.h"
#include "src/objects/smi.h"
#include "src/objects/struct.h"
#include "src/roots/roots.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "torque-generated/bit-fields.h"
#include "torque-generated/field-offsets.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class AsmWasmData;
class BytecodeArray;
class CoverageInfo;
class DebugInfo;
class IsCompiledScope;
class WasmCapiFunctionData;
class WasmExportedFunctionData;
class WasmJSFunctionData;
#include "torque-generated/src/objects/"
// Data collected by the pre-parser storing information about scopes and inner
// functions.
// PreparseData Layout:
// +-------------------------------+
// | data_length | children_length |
// +-------------------------------+
// | Scope Byte Data ... |
// | ... |
// +-------------------------------+
// | [Padding] |
// +-------------------------------+
// | Inner PreparseData 1 |
// +-------------------------------+
// | ... |
// +-------------------------------+
// | Inner PreparseData N |
// +-------------------------------+
class PreparseData
: public TorqueGeneratedPreparseData<PreparseData, HeapObject> {
inline int inner_start_offset() const;
inline ObjectSlot inner_data_start() const;
inline byte get(int index) const;
inline void set(int index, byte value);
inline void copy_in(int index, const byte* buffer, int length);
inline PreparseData get_child(int index) const;
inline void set_child(int index, PreparseData value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// Clear uninitialized padding space.
inline void clear_padding();
static const int kDataStartOffset = kSize;
class BodyDescriptor;
static int InnerOffset(int data_length) {
return RoundUp(kDataStartOffset + data_length * kByteSize, kTaggedSize);
static int SizeFor(int data_length, int children_length) {
return InnerOffset(data_length) + children_length * kTaggedSize;
inline Object get_child_raw(int index) const;
// Abstract class representing extra data for an uncompiled function, which is
// not stored in the SharedFunctionInfo.
class UncompiledData
: public TorqueGeneratedUncompiledData<UncompiledData, HeapObject> {
template <typename LocalIsolate>
inline void Init(LocalIsolate* isolate, String inferred_name,
int start_position, int end_position);
inline void InitAfterBytecodeFlush(
String inferred_name, int start_position, int end_position,
std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
using BodyDescriptor =
FixedBodyDescriptor<kStartOfStrongFieldsOffset, kEndOfStrongFieldsOffset,
// Class representing data for an uncompiled function that does not have any
// data from the pre-parser, either because it's a leaf function or because the
// pre-parser bailed out.
class UncompiledDataWithoutPreparseData
: public TorqueGeneratedUncompiledDataWithoutPreparseData<
UncompiledDataWithoutPreparseData, UncompiledData> {
// No extra fields compared to UncompiledData.
using BodyDescriptor = UncompiledData::BodyDescriptor;
// Class representing data for an uncompiled function that has pre-parsed scope
// data.
class UncompiledDataWithPreparseData
: public TorqueGeneratedUncompiledDataWithPreparseData<
UncompiledDataWithPreparseData, UncompiledData> {
template <typename LocalIsolate>
inline void Init(LocalIsolate* isolate, String inferred_name,
int start_position, int end_position,
PreparseData scope_data);
using BodyDescriptor = SubclassBodyDescriptor<
FixedBodyDescriptor<kStartOfStrongFieldsOffset, kEndOfStrongFieldsOffset,
class InterpreterData : public Struct {
DECL_ACCESSORS(bytecode_array, BytecodeArray)
DECL_ACCESSORS(interpreter_trampoline, Code)
OBJECT_CONSTRUCTORS(InterpreterData, Struct);
// SharedFunctionInfo describes the JSFunction information that can be
// shared by multiple instances of the function.
class SharedFunctionInfo : public HeapObject {
// This initializes the SharedFunctionInfo after allocation. It must
// initialize all fields, and leave the SharedFunctionInfo in a state where
// it is safe for the GC to visit it.
// Important: This function MUST not allocate.
void Init(ReadOnlyRoots roots, int unique_id);
V8_EXPORT_PRIVATE static constexpr Smi const kNoSharedNameSentinel =
// [name]: Returns shared name if it exists or an empty string otherwise.
inline String Name() const;
inline void SetName(String name);
// Get the code object which represents the execution of this function.
V8_EXPORT_PRIVATE Code GetCode() const;
// Get the abstract code associated with the function, which will either be
// a Code object or a BytecodeArray.
inline AbstractCode abstract_code();
// Tells whether or not this shared function info has an attached
// BytecodeArray.
inline bool IsInterpreted() const;
// Set up the link between shared function info and the script. The shared
// function info is added to the list on the script.
V8_EXPORT_PRIVATE void SetScript(ReadOnlyRoots roots,
HeapObject script_object,
int function_literal_id,
bool reset_preparsed_scope_data = true);
// Layout description of the optimized code map.
static const int kEntriesStart = 0;
static const int kContextOffset = 0;
static const int kCachedCodeOffset = 1;
static const int kEntryLength = 2;
static const int kInitialLength = kEntriesStart + kEntryLength;
static const int kNotFound = -1;
DECL_GETTER(scope_info, ScopeInfo)
// Set scope_info without moving the existing name onto the ScopeInfo.
inline void set_raw_scope_info(ScopeInfo scope_info,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline void SetScopeInfo(ScopeInfo scope_info,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline bool is_script() const;
inline bool needs_script_context() const;
// End position of this function in the script source.
V8_EXPORT_PRIVATE int EndPosition() const;
// Start position of this function in the script source.
V8_EXPORT_PRIVATE int StartPosition() const;
// Set the start and end position of this function in the script source.
// Updates the scope info if available.
V8_EXPORT_PRIVATE void SetPosition(int start_position, int end_position);
// [outer scope info | feedback metadata] Shared storage for outer scope info
// (on uncompiled functions) and feedback metadata (on compiled functions).
DECL_ACCESSORS(raw_outer_scope_info_or_feedback_metadata, HeapObject)
// Get the outer scope info whether this function is compiled or not.
inline bool HasOuterScopeInfo() const;
inline ScopeInfo GetOuterScopeInfo() const;
// [feedback metadata] Metadata template for feedback vectors of instances of
// this function.
inline bool HasFeedbackMetadata() const;
DECL_ACCESSORS(feedback_metadata, FeedbackMetadata)
// Returns if this function has been compiled yet. Note: with bytecode
// flushing, any GC after this call is made could cause the function
// to become uncompiled. If you need to ensure the function remains compiled
// for some period of time, use IsCompiledScope instead.
inline bool is_compiled() const;
// Returns an IsCompiledScope which reports whether the function is compiled,
// and if compiled, will avoid the function becoming uncompiled while it is
// held.
template <typename LocalIsolate>
inline IsCompiledScope is_compiled_scope(LocalIsolate* isolate) const;
// [length]: The function length - usually the number of declared parameters.
// Use up to 2^16-2 parameters (16 bits of values, where one is reserved for
// kDontAdaptArgumentsSentinel). The value is only reliable when the function
// has been compiled.
inline uint16_t length() const;
inline void set_length(int value);
// [internal formal parameter count]: The declared number of parameters.
// For subclass constructors, also includes
// The size of function's frame is internal_formal_parameter_count + 1.
// Set the formal parameter count so the function code will be
// called without using argument adaptor frames.
inline void DontAdaptArguments();
// [expected_nof_properties]: Expected number of properties for the
// function. The value is only reliable when the function has been compiled.
// [function_literal_id] - uniquely identifies the FunctionLiteral this
// SharedFunctionInfo represents within its script, or -1 if this
// SharedFunctionInfo object doesn't correspond to a parsed FunctionLiteral.
// [unique_id] - For --trace-maps purposes, an identifier that's persistent
// even if the GC moves this SharedFunctionInfo.
// [function data]: This field holds some additional data for function.
// Currently it has one of:
// - a FunctionTemplateInfo to make benefit the API [IsApiFunction()].
// - a BytecodeArray for the interpreter [HasBytecodeArray()].
// - a InterpreterData with the BytecodeArray and a copy of the
// interpreter trampoline [HasInterpreterData()]
// - an AsmWasmData with Asm->Wasm conversion [HasAsmWasmData()].
// - a Smi containing the builtin id [HasBuiltinId()]
// - a UncompiledDataWithoutPreparseData for lazy compilation
// [HasUncompiledDataWithoutPreparseData()]
// - a UncompiledDataWithPreparseData for lazy compilation
// [HasUncompiledDataWithPreparseData()]
// - a WasmExportedFunctionData for Wasm [HasWasmExportedFunctionData()]
inline bool IsApiFunction() const;
inline bool is_class_constructor() const;
inline FunctionTemplateInfo get_api_func_data() const;
inline void set_api_func_data(FunctionTemplateInfo data);
inline bool HasBytecodeArray() const;
inline BytecodeArray GetBytecodeArray() const;
inline void set_bytecode_array(BytecodeArray bytecode);
inline Code InterpreterTrampoline() const;
inline bool HasInterpreterData() const;
inline InterpreterData interpreter_data() const;
inline void set_interpreter_data(InterpreterData interpreter_data);
inline BytecodeArray GetDebugBytecodeArray() const;
inline void SetDebugBytecodeArray(BytecodeArray bytecode);
inline bool HasAsmWasmData() const;
inline AsmWasmData asm_wasm_data() const;
inline void set_asm_wasm_data(AsmWasmData data);
// builtin_id corresponds to the auto-generated Builtins::Name id.
inline bool HasBuiltinId() const;
inline int builtin_id() const;
inline void set_builtin_id(int builtin_id);
inline bool HasUncompiledData() const;
inline UncompiledData uncompiled_data() const;
inline void set_uncompiled_data(UncompiledData data);
inline bool HasUncompiledDataWithPreparseData() const;
inline UncompiledDataWithPreparseData uncompiled_data_with_preparse_data()
inline void set_uncompiled_data_with_preparse_data(
UncompiledDataWithPreparseData data);
inline bool HasUncompiledDataWithoutPreparseData() const;
inline bool HasWasmExportedFunctionData() const;
V8_EXPORT_PRIVATE WasmExportedFunctionData
wasm_exported_function_data() const;
inline bool HasWasmJSFunctionData() const;
WasmJSFunctionData wasm_js_function_data() const;
inline bool HasWasmCapiFunctionData() const;
WasmCapiFunctionData wasm_capi_function_data() const;
// Clear out pre-parsed scope data from UncompiledDataWithPreparseData,
// turning it into UncompiledDataWithoutPreparseData.
inline void ClearPreparseData();
// The inferred_name is inferred from variable or property assignment of this
// function. It is used to facilitate debugging and profiling of JavaScript
// code written in OO style, where almost all functions are anonymous but are
// assigned to object properties.
inline bool HasInferredName();
inline String inferred_name();
// Break infos are contained in DebugInfo, this is a convenience method
// to simplify access.
V8_EXPORT_PRIVATE bool HasBreakInfo() const;
bool BreakAtEntry() const;
// Coverage infos are contained in DebugInfo, this is a convenience method
// to simplify access.
bool HasCoverageInfo() const;
CoverageInfo GetCoverageInfo() const;
// The function's name if it is non-empty, otherwise the inferred name.
String DebugName();
// Used for flags such as --turbo-filter.
bool PassesFilter(const char* raw_filter);
// [script_or_debug_info]: One of:
// - Script from which the function originates.
// - a DebugInfo which holds the actual script [HasDebugInfo()].
DECL_RELEASE_ACQUIRE_ACCESSORS(script_or_debug_info, HeapObject)
inline HeapObject script() const;
inline void set_script(HeapObject script);
// True if the underlying script was parsed and compiled in REPL mode.
inline bool is_repl_mode() const;
// The function is subject to debugging if a debug info is attached.
inline bool HasDebugInfo() const;
inline DebugInfo GetDebugInfo() const;
inline void SetDebugInfo(DebugInfo debug_info);
// The offset of the 'function' token in the script source relative to the
// start position. Can return kFunctionTokenOutOfRange if offset doesn't
// fit in 16 bits.
// The position of the 'function' token in the script source. Can return
// kNoSourcePosition if raw_function_token_offset() returns
// kFunctionTokenOutOfRange.
inline int function_token_position() const;
// Returns true if the function has shared name.
inline bool HasSharedName() const;
// [flags] Bit field containing various flags about the function.
// True if the outer class scope contains a private brand for
// private instance methdos.
// True if this SFI has been (non-OSR) optimized in the past. This is used to
// guide native-context-independent codegen.
// True if a Code object associated with this SFI has been inserted into the
// compilation cache. Note that the cache entry may be removed by aging,
// hence the 'may'.
// Returns the cached Code object for this SFI if it exists, an empty handle
// otherwise.
MaybeHandle<Code> TryGetCachedCode(Isolate* isolate);
// Is this function a top-level function (scripts, evals).
// Indicates if this function can be lazy compiled.
// Indicates the language mode.
inline LanguageMode language_mode() const;
inline void set_language_mode(LanguageMode language_mode);
// How the function appears in source text.
DECL_PRIMITIVE_ACCESSORS(syntax_kind, FunctionSyntaxKind)
// Indicates whether the source is implicitly wrapped in a function.
inline bool is_wrapped() const;
// True if the function has any duplicated parameter names.
// Indicates whether the function is a native function.
// These needs special treatment in .call and .apply since
// null passed as the receiver should not be translated to the
// global object.
// Indicates that asm->wasm conversion failed and should not be re-attempted.
// Indicates that the function was created by the Function function.
// Though it's anonymous, toString should treat it as if it had the name
// "anonymous". We don't set the name itself so that the system does not
// see a binding for it.
// Indicates that the function represented by the shared function info was
// classed as an immediately invoked function execution (IIFE) function and
// is only executed once.
// Whether or not the number of expected properties may change.
// Indicates that the function has been reported for binary code coverage.
// Indicates that the private name lookups inside the function skips the
// closest outer class scope.
inline FunctionKind kind() const;
// Defines the index in a native context of closure's map instantiated using
// this shared function info.
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic.
inline void clear_padding();
// Recalculates the |map_index| value after modifications of this shared info.
inline void UpdateFunctionMapIndex();
// Indicates whether optimizations have been disabled for this shared function
// info. If we cannot optimize the function we disable optimization to avoid
// spending time attempting to optimize it again.
inline bool optimization_disabled() const;
// The reason why optimization was disabled.
inline BailoutReason disable_optimization_reason() const;
// Disable (further) attempted optimization of all functions sharing this
// shared function info.
void DisableOptimization(BailoutReason reason);
// This class constructor needs to call out to an instance fields
// initializer. This flag is set when creating the
// SharedFunctionInfo as a reminder to emit the initializer call
// when generating code later.
// [source code]: Source code for the function.
bool HasSourceCode() const;
static Handle<Object> GetSourceCode(Handle<SharedFunctionInfo> shared);
static Handle<Object> GetSourceCodeHarmony(Handle<SharedFunctionInfo> shared);
// Tells whether this function should be subject to debugging, e.g. for
// - scope inspection
// - internal break points
// - coverage and type profile
// - error stack trace
inline bool IsSubjectToDebugging() const;
// Whether this function is defined in user-provided JavaScript code.
inline bool IsUserJavaScript() const;
// True if one can flush compiled code from this function, in such a way that
// it can later be re-compiled.
inline bool CanDiscardCompiled() const;
// Flush compiled data from this function, setting it back to CompileLazy and
// clearing any compiled metadata.
V8_EXPORT_PRIVATE static void DiscardCompiled(
Isolate* isolate, Handle<SharedFunctionInfo> shared_info);
// Discard the compiled metadata. If called during GC then
// |gc_notify_updated_slot| should be used to record any slot updates.
void DiscardCompiledMetadata(
Isolate* isolate,
std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
gc_notify_updated_slot =
[](HeapObject object, ObjectSlot slot, HeapObject target) {});
// Returns true if the function has old bytecode that could be flushed. This
// function shouldn't access any flags as it is used by concurrent marker.
// Hence it takes the mode as an argument.
inline bool ShouldFlushBytecode(BytecodeFlushMode mode);
enum Inlineability {
// Different reasons for not being inlineable:
Inlineability GetInlineability() const;
// Source size of this function.
int SourceSize();
// Returns `false` if formal parameters include rest parameters, optional
// parameters, or destructuring parameters.
// TODO(caitp): make this a flag set during parsing
inline bool has_simple_parameters();
// Initialize a SharedFunctionInfo from a parsed function literal.
template <typename LocalIsolate>
static void InitFromFunctionLiteral(LocalIsolate* isolate,
Handle<SharedFunctionInfo> shared_info,
FunctionLiteral* lit, bool is_toplevel);
// Updates the expected number of properties based on estimate from parser.
void UpdateExpectedNofPropertiesFromEstimate(FunctionLiteral* literal);
void UpdateAndFinalizeExpectedNofPropertiesFromEstimate(
FunctionLiteral* literal);
// Sets the FunctionTokenOffset field based on the given token position and
// start position.
void SetFunctionTokenPosition(int function_token_position,
int start_position);
static void EnsureSourcePositionsAvailable(
Isolate* isolate, Handle<SharedFunctionInfo> shared_info);
V8_EXPORT_PRIVATE bool AreSourcePositionsAvailable() const;
// Hash based on function literal id and script id.
V8_EXPORT_PRIVATE uint32_t Hash();
inline bool construct_as_builtin() const;
// Determines and sets the ConstructAsBuiltinBit in |flags|, based on the
// |function_data|. Must be called when creating the SFI after other fields
// are initialized. The ConstructAsBuiltinBit determines whether
// JSBuiltinsConstructStub or JSConstructStubGeneric should be called to
// construct this function.
inline void CalculateConstructAsBuiltin();
// Dispatched behavior.
void SharedFunctionInfoVerify(LocalIsolate* isolate);
void PrintSourceCode(std::ostream& os);
// Iterate over all shared function infos in a given script.
class ScriptIterator {
V8_EXPORT_PRIVATE ScriptIterator(Isolate* isolate, Script script);
explicit ScriptIterator(Handle<WeakFixedArray> shared_function_infos);
ScriptIterator(const ScriptIterator&) = delete;
ScriptIterator& operator=(const ScriptIterator&) = delete;
V8_EXPORT_PRIVATE SharedFunctionInfo Next();
int CurrentIndex() const { return index_ - 1; }
// Reset the iterator to run on |script|.
void Reset(Isolate* isolate, Script script);
Handle<WeakFixedArray> shared_function_infos_;
int index_;
// Constants.
static const int kMaximumFunctionTokenOffset = kMaxUInt16 - 1;
static const uint16_t kFunctionTokenOutOfRange = static_cast<uint16_t>(-1);
STATIC_ASSERT(kMaximumFunctionTokenOffset + 1 == kFunctionTokenOutOfRange);
static const int kAlignedSize = POINTER_SIZE_ALIGN(kSize);
class BodyDescriptor;
// Bailout reasons must fit in the DisabledOptimizationReason bitfield.
STATIC_ASSERT(BailoutReason::kLastErrorMessage <=
STATIC_ASSERT(kLastFunctionKind <= FunctionKindBits::kMax);
STATIC_ASSERT(FunctionSyntaxKind::kLastFunctionSyntaxKind <=
// Indicates that this function uses a super property (or an eval that may
// use a super property).
// This is needed to set up the [[HomeObject]] on the function instance.
inline bool needs_home_object() const;
void SharedFunctionInfoVerify(ReadOnlyRoots roots);
// [name_or_scope_info]: Function name string, kNoSharedNameSentinel or
// ScopeInfo.
DECL_RELEASE_ACQUIRE_ACCESSORS(name_or_scope_info, Object)
// [outer scope info] The outer scope info, needed to lazily parse this
// function.
DECL_ACCESSORS(outer_scope_info, HeapObject)
// [is_oneshot_iife_or_properties_are_final]: This bit is used to track
// two mutually exclusive cases. Either this SharedFunctionInfo is
// a oneshot_iife or we have finished parsing its properties. These cases
// are mutually exclusive because the properties final bit is only used by
// class constructors to handle lazily parsed properties and class
// constructors can never be oneshot iifes.
inline void set_kind(FunctionKind kind);
inline void set_needs_home_object(bool value);
inline uint16_t get_property_estimate_from_literal(FunctionLiteral* literal);
template <typename Impl>
friend class FactoryBase;
friend class V8HeapExplorer;
FRIEND_TEST(PreParserTest, LazyFunctionLength);
OBJECT_CONSTRUCTORS(SharedFunctionInfo, HeapObject);
// Printing support.
struct SourceCodeOf {
explicit SourceCodeOf(SharedFunctionInfo v, int max = -1)
: value(v), max_length(max) {}
const SharedFunctionInfo value;
int max_length;
// IsCompiledScope enables a caller to check if a function is compiled, and
// ensure it remains compiled (i.e., doesn't have it's bytecode flushed) while
// the scope is retained.
class IsCompiledScope {
inline IsCompiledScope(const SharedFunctionInfo shared, Isolate* isolate);
inline IsCompiledScope(const SharedFunctionInfo shared,
LocalIsolate* isolate);
inline IsCompiledScope() : retain_bytecode_(), is_compiled_(false) {}
inline bool is_compiled() const { return is_compiled_; }
MaybeHandle<BytecodeArray> retain_bytecode_;
bool is_compiled_;
std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v);
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"