Commit ae8b5619 authored by jgruber's avatar jgruber Committed by Commit Bot

[builtins] Add DeserializeLazy builtin and feature flags

This adds an initial implementation of the DeserializeLazy builtin and
runtime function, as well as --lazy-deserialization and
--trace-lazy-deserialization feature flags.

Since lazy deserialization itself isn't implemented yet, DeserializeLazy
simply replaces itself with the appropriate builtin. The builtin_id is
loaded from the SFI, and the builtin itself is loaded from the Builtins
table.

Bug: v8:6624
Change-Id: I4ef8c3030a8cda19a086b8e569a24d97213b5ed8
Reviewed-on: https://chromium-review.googlesource.com/643289Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47757}
parent 7d60f78a
......@@ -123,6 +123,7 @@ namespace internal {
/* Code life-cycle */ \
ASM(CompileLazy) \
ASM(CheckOptimizationMarker) \
TFJ(DeserializeLazy, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
ASM(InstantiateAsmJs) \
ASM(NotifyDeoptimized) \
ASM(NotifySoftDeoptimized) \
......
......@@ -11,6 +11,82 @@
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// Lazy deserialization.
// DeserializeLazy is very similar to CompileLazy: it is called with the
// arguments intended for the target function. We load the function from the
// frame, make sure its code object is deserialized, then tail-call into it,
// passing along all arguments unmodified.
TF_BUILTIN(DeserializeLazy, CodeStubAssembler) {
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* function = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
CSA_ASSERT(this, IsJSFunction(function));
Node* shared =
LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset);
CSA_ASSERT(this, IsSharedFunctionInfo(shared));
Node* shared_code = LoadObjectField(shared, SharedFunctionInfo::kCodeOffset);
CSA_ASSERT(this, IsCodeMap(LoadMap(shared_code)));
Node* shared_code_builtin_id = LoadObjectField(
shared_code, Code::kBuiltinIndexOffset, MachineType::Int32());
// TODO(6624): Once lazy deserialization has been implemented, add a path
// here that checks whether the appropriate builtin has already been
// deserialized into the builtin table. If so, copy it into the function &
// shared function info here instead of going through runtime.
// It could be that the shared function info already has a deserialized copy
// of the builtin. In that case, simply copy the code over to the function and
// tail-call into it. Otherwise, we need to call into runtime to deserialize.
Label copy_from_shared(this), deserialize_in_runtime(this), out(this);
Branch(Word32Equal(shared_code_builtin_id,
Int32Constant(Builtins::kDeserializeLazy)),
&deserialize_in_runtime, &copy_from_shared);
BIND(&copy_from_shared);
{
CSA_ASSERT(this, Int32GreaterThanOrEqual(shared_code_builtin_id,
Int32Constant(0)));
CSA_ASSERT(this, Int32LessThan(shared_code_builtin_id,
Int32Constant(Builtins::builtin_count)));
StoreObjectField(function, JSFunction::kCodeOffset, shared_code);
Goto(&out);
}
BIND(&deserialize_in_runtime);
{
CallRuntime(Runtime::kDeserializeLazy, context, function);
#ifdef DEBUG
Node* function_code = LoadObjectField(function, JSFunction::kCodeOffset);
CSA_ASSERT(this, IsCodeMap(LoadMap(function_code)));
Node* function_code_builtin_id = LoadObjectField(
function_code, Code::kBuiltinIndexOffset, MachineType::Int32());
Node* function_builtin_id =
LoadObjectField(shared, SharedFunctionInfo::kFunctionDataOffset);
CSA_ASSERT(this, TaggedIsSmi(function_builtin_id));
CSA_ASSERT(this, Word32Equal(function_code_builtin_id,
SmiToWord32(function_builtin_id)));
#endif
Goto(&out);
}
BIND(&out);
TailCallStub(CodeFactory::Call(isolate()), context, function, argc);
}
// -----------------------------------------------------------------------------
// Interrupt and stack checks.
......
......@@ -929,6 +929,9 @@ DEFINE_INT(runtime_stats, 0,
DEFINE_VALUE_IMPLICATION(runtime_call_stats, runtime_stats, 1)
// snapshot-common.cc
DEFINE_BOOL(lazy_deserialization, false,
"Deserialize code lazily from the snapshot.")
DEFINE_BOOL(trace_lazy_deserialization, false, "Trace lazy deserialization.")
DEFINE_BOOL(profile_deserialization, false,
"Print the time it takes to deserialize the snapshot.")
DEFINE_BOOL(serialization_statistics, false,
......
......@@ -503,6 +503,37 @@ RUNTIME_FUNCTION(Runtime_CreateListFromArrayLike) {
isolate, object, ElementTypes::kAll));
}
RUNTIME_FUNCTION(Runtime_DeserializeLazy) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
DCHECK(FLAG_lazy_deserialization);
// TODO(6624): Lazy-deserialize instead of simply loading from the builtins
// list. In fact, this should never be called if the builtin has already
// been deserialized.
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
int builtin_id = shared->lazy_deserialization_builtin_id();
// The DeserializeLazy builtin tail-calls the deserialized builtin. This only
// works with JS-linkage.
DCHECK_EQ(Builtins::TFJ, Builtins::KindOf(builtin_id));
if (FLAG_trace_lazy_deserialization) {
PrintF("Lazy-deserializing %s\n", Builtins::name(builtin_id));
}
Code* code =
isolate->builtins()->builtin(static_cast<Builtins::Name>(builtin_id));
DCHECK_EQ(builtin_id, code->builtin_index());
shared->set_code(code);
function->set_code(code);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_IncrementUseCounter) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -285,6 +285,7 @@ namespace internal {
F(CheckIsBootstrapping, 0, 1) \
F(CreateAsyncFromSyncIterator, 1, 1) \
F(CreateListFromArrayLike, 1, 1) \
F(DeserializeLazy, 1, 1) \
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(ExportFromRuntime, 1, 1) \
F(IncrementUseCounter, 1, 1) \
......
......@@ -180,6 +180,7 @@ void Deserializer::VisitRootPointers(Root root, Object** start, Object** end) {
void Deserializer::Synchronize(VisitorSynchronization::SyncTag tag) {
static const byte expected = kSynchronize;
CHECK_EQ(expected, source_.Get());
deserializing_builtins_ = (tag == VisitorSynchronization::kHandleScope);
}
void Deserializer::DeserializeDeferredObjects() {
......@@ -353,6 +354,14 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
return obj;
}
int Deserializer::MaybeReplaceWithDeserializeLazy(int builtin_id) {
DCHECK(Builtins::IsBuiltinId(builtin_id));
return (FLAG_lazy_deserialization && Builtins::IsLazy(builtin_id) &&
!deserializing_builtins_)
? Builtins::kDeserializeLazy
: builtin_id;
}
HeapObject* Deserializer::GetBackReferencedObject(int space) {
HeapObject* obj;
SerializerReference back_reference =
......@@ -827,9 +836,8 @@ Object** Deserializer::ReadDataCase(Isolate* isolate, Object** current,
emit_write_barrier = isolate->heap()->InNewSpace(new_object);
} else {
DCHECK(where == kBuiltin);
int builtin_id = source_.GetInt();
DCHECK_LE(0, builtin_id);
DCHECK_LT(builtin_id, Builtins::builtin_count);
int builtin_id = MaybeReplaceWithDeserializeLazy(source_.GetInt());
DCHECK(Builtins::IsBuiltinId(builtin_id));
Builtins::Name name = static_cast<Builtins::Name>(builtin_id);
new_object = isolate->builtins()->builtin(name);
// Record the builtin reference for post-processing after builtin
......
......@@ -160,6 +160,10 @@ class Deserializer : public SerializerDeserializer {
// Special handling for serialized code like hooking up internalized strings.
HeapObject* PostProcessNewObject(HeapObject* obj, int space);
// May replace the given builtin_id with the DeserializeLazy builtin for lazy
// deserialization.
int MaybeReplaceWithDeserializeLazy(int builtin_id);
// Cached current isolate.
Isolate* isolate_;
......@@ -192,6 +196,10 @@ class Deserializer : public SerializerDeserializer {
const bool deserializing_user_code_;
// TODO(jgruber): This workaround will no longer be necessary once builtin
// reference patching has been removed (through advance allocation).
bool deserializing_builtins_ = false;
AllocationAlignment next_alignment_;
// TODO(6593): generalize rehashing, and remove this flag.
......
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