Commit 3121449b authored by jgruber's avatar jgruber Committed by Commit Bot

[builtins] Add the builtin_id to SharedFunctionInfo

Lazy deserialization needs to determine the underlying builtin by looking at
the SharedFunctionInfo.

This packs the builtin_id into the SFI::function_data field, and adds
convenience functions to Code as a drive-by addition.

Bug: v8:6624
Change-Id: I59093815aa6937342302153ebc95dd60edb0064e
Reviewed-on: https://chromium-review.googlesource.com/641490
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47712}
parent 71ea6b8f
......@@ -209,7 +209,7 @@ Callable Builtins::CallableFor(Isolate* isolate, Name name) {
// static
const char* Builtins::name(int index) {
DCHECK(0 <= index && index < builtin_count);
DCHECK(IsBuiltinId(index));
return builtin_metadata[index].name;
}
......@@ -219,9 +219,37 @@ Address Builtins::CppEntryOf(int index) {
return builtin_metadata[index].kind_specific_data.cpp_entry;
}
// static
bool Builtins::IsLazy(int index) {
DCHECK(IsBuiltinId(index));
// There are a couple of reasons that builtins can require eager-loading,
// i.e. deserialization at isolate creation instead of on-demand. For
// instance:
// * DeserializeLazy implements lazy loading.
// * Immovability requirement. This can only conveniently be guaranteed at
// isolate creation (at runtime, we'd have to allocate in LO space).
// * To avoid conflicts in SharedFunctionInfo::function_data (Illegal,
// HandleApiCall, interpreter entry trampolines).
// * Frequent use makes lazy loading unnecessary (CompileLazy).
switch (index) {
case kCheckOptimizationMarker:
case kCompileLazy:
case kHandleApiCall:
case kIllegal:
case kInterpreterEnterBytecodeAdvance:
case kInterpreterEnterBytecodeDispatch:
case kInterpreterEntryTrampoline:
return false;
default:
// TODO(6624): Extend to other kinds.
return KindOf(index) == TFJ;
}
UNREACHABLE();
}
// static
Builtins::Kind Builtins::KindOf(int index) {
DCHECK(0 <= index && index < builtin_count);
DCHECK(IsBuiltinId(index));
return builtin_metadata[index].kind;
}
......
......@@ -48,6 +48,10 @@ class Builtins {
builtin_count
};
static bool IsBuiltinId(int maybe_id) {
return 0 <= maybe_id && maybe_id < builtin_count;
}
// The different builtin kinds are documented in builtins-definitions.h.
enum Kind { CPP, API, TFJ, TFC, TFS, TFH, ASM };
......@@ -95,6 +99,11 @@ class Builtins {
static bool IsCpp(int index);
static bool HasCppImplementation(int index);
// Returns true iff the given builtin can be lazy-loaded from the snapshot.
// This is true in general for most builtins with the exception of a few
// special cases such as CompileLazy and DeserializeLazy.
static bool IsLazy(int index);
bool is_initialized() const { return initialized_; }
// Used by SetupIsolateDelegate and Deserializer.
......
......@@ -2522,11 +2522,15 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_raw_name(has_shared_name
? *shared_name
: SharedFunctionInfo::kNoSharedNameSentinel);
share->set_function_data(*undefined_value(), SKIP_WRITE_BARRIER);
Handle<Code> code;
if (!maybe_code.ToHandle(&code)) {
code = BUILTIN_CODE(isolate(), Illegal);
}
Object* function_data =
(code->is_builtin() && Builtins::IsLazy(code->builtin_index()))
? Smi::FromInt(code->builtin_index())
: Object::cast(*undefined_value());
share->set_function_data(function_data, SKIP_WRITE_BARRIER);
share->set_code(*code);
share->set_scope_info(ScopeInfo::Empty(isolate()));
share->set_outer_scope_info(*the_hole_value());
......
......@@ -732,7 +732,8 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() {
Isolate* isolate = GetIsolate();
CHECK(function_data()->IsUndefined(isolate) || IsApiFunction() ||
HasBytecodeArray() || HasAsmWasmData());
HasBytecodeArray() || HasAsmWasmData() ||
HasLazyDeserializationBuiltinId());
CHECK(function_identifier()->IsUndefined(isolate) || HasBuiltinFunctionId() ||
HasInferredName());
......
......@@ -3697,17 +3697,22 @@ void Code::set_raw_kind_specific_flags2(int value) {
inline bool Code::is_interpreter_trampoline_builtin() const {
Builtins* builtins = GetIsolate()->builtins();
return this == builtins->builtin(Builtins::kInterpreterEntryTrampoline) ||
this ==
builtins->builtin(Builtins::kInterpreterEnterBytecodeAdvance) ||
this == builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch);
bool is_interpreter_trampoline =
(this == builtins->builtin(Builtins::kInterpreterEntryTrampoline) ||
this == builtins->builtin(Builtins::kInterpreterEnterBytecodeAdvance) ||
this == builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch));
DCHECK_IMPLIES(is_interpreter_trampoline, !Builtins::IsLazy(builtin_index()));
return is_interpreter_trampoline;
}
inline bool Code::checks_optimization_marker() const {
Builtins* builtins = GetIsolate()->builtins();
return this == builtins->builtin(Builtins::kCompileLazy) ||
this == builtins->builtin(Builtins::kInterpreterEntryTrampoline) ||
this == builtins->builtin(Builtins::kCheckOptimizationMarker);
bool checks_marker =
(this == builtins->builtin(Builtins::kCompileLazy) ||
this == builtins->builtin(Builtins::kInterpreterEntryTrampoline) ||
this == builtins->builtin(Builtins::kCheckOptimizationMarker));
DCHECK_IMPLIES(checks_marker, !Builtins::IsLazy(builtin_index()));
return checks_marker;
}
inline bool Code::has_unwinding_info() const {
......@@ -3832,13 +3837,18 @@ void Code::set_allow_osr_at_loop_nesting_level(int level) {
}
int Code::builtin_index() const {
return READ_INT_FIELD(this, kBuiltinIndexOffset);
int index = READ_INT_FIELD(this, kBuiltinIndexOffset);
DCHECK(index == -1 || Builtins::IsBuiltinId(index));
return index;
}
void Code::set_builtin_index(int index) {
DCHECK(index == -1 || Builtins::IsBuiltinId(index));
WRITE_INT_FIELD(this, kBuiltinIndexOffset, index);
}
bool Code::is_builtin() const { return builtin_index() != -1; }
unsigned Code::stack_slots() const {
DCHECK(is_turbofanned());
return StackSlotsField::decode(
......
......@@ -3815,6 +3815,7 @@ class Code: public HeapObject {
// builtin index is a non-negative integer for builtins, and -1 otherwise.
inline int builtin_index() const;
inline void set_builtin_index(int id);
inline bool is_builtin() const;
// [stack_slots]: For kind OPTIMIZED_FUNCTION, the number of stack slots
// reserved in the code prologue.
......
......@@ -325,6 +325,17 @@ void SharedFunctionInfo::ClearAsmWasmData() {
set_function_data(GetHeap()->undefined_value());
}
bool SharedFunctionInfo::HasLazyDeserializationBuiltinId() const {
return function_data()->IsSmi();
}
int SharedFunctionInfo::lazy_deserialization_builtin_id() const {
DCHECK(HasLazyDeserializationBuiltinId());
int id = Smi::ToInt(function_data());
DCHECK(Builtins::IsBuiltinId(id));
return id;
}
bool SharedFunctionInfo::HasBuiltinFunctionId() {
return function_identifier()->IsSmi();
}
......
......@@ -146,6 +146,7 @@ class SharedFunctionInfo : public HeapObject {
// - a FunctionTemplateInfo to make benefit the API [IsApiFunction()].
// - a BytecodeArray for the interpreter [HasBytecodeArray()].
// - a FixedArray with Asm->Wasm conversion [HasAsmWasmData()].
// - a Smi containing the builtin id [HasLazyDeserializationBuiltinId()]
DECL_ACCESSORS(function_data, Object)
inline bool IsApiFunction();
......@@ -159,6 +160,13 @@ class SharedFunctionInfo : public HeapObject {
inline FixedArray* asm_wasm_data() const;
inline void set_asm_wasm_data(FixedArray* data);
inline void ClearAsmWasmData();
// A brief note to clear up possible confusion:
// lazy_deserialization_builtin_id corresponds to the auto-generated
// Builtins::Name id, while builtin_function_id corresponds to
// BuiltinFunctionId (a manually maintained list of 'interesting' functions
// mainly used during optimization).
inline bool HasLazyDeserializationBuiltinId() const;
inline int lazy_deserialization_builtin_id() const;
// [function identifier]: This field holds an additional identifier for the
// function.
......
......@@ -2743,3 +2743,24 @@ TEST(SerializationMemoryStats) {
v8::StartupData blob = v8::V8::CreateSnapshotDataBlob();
delete[] blob.data;
}
TEST(BuiltinsHaveBuiltinIdForLazyDeserialization) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
CHECK(Builtins::IsLazy(Builtins::kRegExpPrototypeExec));
CHECK_EQ(Builtins::kRegExpPrototypeExec,
isolate->regexp_exec_function()
->shared()
->lazy_deserialization_builtin_id());
CHECK(Builtins::IsLazy(Builtins::kAsyncIteratorValueUnwrap));
CHECK_EQ(Builtins::kAsyncIteratorValueUnwrap,
isolate->async_iterator_value_unwrap_shared_fun()
->lazy_deserialization_builtin_id());
CHECK(!Builtins::IsLazy(Builtins::kIllegal));
CHECK(!isolate->intl_date_time_format_function()
->shared()
->HasLazyDeserializationBuiltinId());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment