Commit 3113535e authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[interpreter/runtime] Simplify how global declarations are processed

This makes the code a little more specific to what's happening: There is only 1
global scope, and if there is one, we know its declarations are
info->scope()->declarations(). That means we don't need multiple
GlobalDeclarationsBuilders, and we don't need to cache partially serialized
versions of the declarations. One builder is enough, and we can simply walk
those declarations if there are any.

Additionally this CL drops unnecessary information passed into DeclareGlobals:
- Global functions always have the name on the shared function info, so we can
  drop the name.
- Due to lazy feedback vectors there's no point in trying to preinitialize
  global loads. Also this was only preinitializing global loads at the script
  level, not sub functions; without even checking whether the global load was
  used. It may actually have caused us to do more work and allocate more global
  load feedback slots than neccessary.

Change-Id: Ibbdd029abe5a39ba27f7fc9be84670c5d444d98d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1997123
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65725}
parent 69fda08a
This diff is collapsed.
......@@ -50,6 +50,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
#undef DECLARE_VISIT
// Visiting function for declarations list and statements are overridden.
void VisitGlobalDeclarations(Declaration::List* declarations);
void VisitDeclarations(Declaration::List* declarations);
void VisitStatements(const ZonePtrList<Statement>* statments);
......@@ -495,7 +496,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
GlobalDeclarationsBuilder* globals_builder_;
BlockCoverageBuilder* block_coverage_builder_;
ZoneVector<GlobalDeclarationsBuilder*> global_declarations_;
ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_;
ZoneVector<std::pair<NativeFunctionLiteral*, size_t>>
native_function_literals_;
......
......@@ -48,9 +48,8 @@ Object ThrowRedeclarationError(Isolate* isolate, Handle<String> name,
Object DeclareGlobal(
Isolate* isolate, Handle<JSGlobalObject> global, Handle<String> name,
Handle<Object> value, PropertyAttributes attr, bool is_var,
bool is_function_declaration, RedeclarationType redeclaration_type,
Handle<FeedbackVector> feedback_vector = Handle<FeedbackVector>(),
FeedbackSlot slot = FeedbackSlot::Invalid()) {
RedeclarationType redeclaration_type,
Handle<FeedbackVector> feedback_vector = Handle<FeedbackVector>()) {
Handle<ScriptContextTable> script_contexts(
global->native_context().script_context_table(), isolate);
ScriptContextTable::LookupResult lookup;
......@@ -66,7 +65,7 @@ Object DeclareGlobal(
// Do the lookup own properties only, see ES5 erratum.
LookupIterator::Configuration lookup_config(
LookupIterator::Configuration::OWN_SKIP_INTERCEPTOR);
if (is_function_declaration) {
if (!is_var) {
// For function declarations, use the interceptor on the declaration. For
// non-functions, use it only on initialization.
lookup_config = LookupIterator::Configuration::OWN;
......@@ -82,7 +81,6 @@ Object DeclareGlobal(
// Skip var re-declarations.
if (is_var) return ReadOnlyRoots(isolate).undefined_value();
DCHECK(is_function_declaration);
if ((old_attributes & DONT_DELETE) != 0) {
// Only allow reconfiguring globals to functions in user code (no
// natives, which are marked as read-only).
......@@ -111,25 +109,12 @@ Object DeclareGlobal(
if (it.state() == LookupIterator::ACCESSOR) it.Delete();
}
if (is_function_declaration) {
it.Restart();
}
if (!is_var) it.Restart();
// Define or redefine own property.
RETURN_FAILURE_ON_EXCEPTION(
isolate, JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attr));
if (!feedback_vector.is_null() &&
it.state() != LookupIterator::State::INTERCEPTOR) {
DCHECK_EQ(*global, *it.GetHolder<Object>());
// Preinitialize the feedback slot if the global object does not have
// named interceptor or the interceptor is not masking.
if (!global->HasNamedInterceptor() ||
global->GetNamedInterceptor().non_masking()) {
FeedbackNexus nexus(feedback_vector, slot);
nexus.ConfigurePropertyCellMode(it.GetPropertyCell());
}
}
return ReadOnlyRoots(isolate).undefined_value();
}
......@@ -154,32 +139,23 @@ Object DeclareGlobals(Isolate* isolate, Handle<FixedArray> declarations,
// Traverse the name/value pairs and set the properties.
int length = declarations->length();
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i += 4, {
Handle<String> name(String::cast(declarations->get(i)), isolate);
FeedbackSlot slot(Smi::ToInt(declarations->get(i + 1)));
Handle<Object> possibly_feedback_cell_slot(declarations->get(i + 2),
isolate);
Handle<Object> initial_value(declarations->get(i + 3), isolate);
bool is_var = initial_value->IsUndefined(isolate);
bool is_function = initial_value->IsSharedFunctionInfo();
DCHECK_NE(is_var, is_function);
FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
Handle<Object> decl(declarations->get(i), isolate);
Handle<String> name;
Handle<Object> value;
if (is_function) {
DCHECK(possibly_feedback_cell_slot->IsSmi());
Handle<FeedbackCell> feedback_cell =
closure_feedback_cell_array->GetFeedbackCell(
Smi::ToInt(*possibly_feedback_cell_slot));
// Copy the function and update its context. Use it as value.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(initial_value);
Handle<JSFunction> function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared, context, feedback_cell, AllocationType::kOld);
value = function;
} else {
bool is_var = decl->IsString();
if (is_var) {
name = Handle<String>::cast(decl);
value = isolate->factory()->undefined_value();
} else {
Handle<SharedFunctionInfo> sfi = Handle<SharedFunctionInfo>::cast(decl);
name = handle(sfi->Name(), isolate);
int index = Smi::ToInt(declarations->get(++i));
Handle<FeedbackCell> feedback_cell =
closure_feedback_cell_array->GetFeedbackCell(index);
value = isolate->factory()->NewFunctionFromSharedFunctionInfo(
sfi, context, feedback_cell, AllocationType::kOld);
}
// Compute the property attributes. According to ECMA-262,
......@@ -190,10 +166,9 @@ Object DeclareGlobals(Isolate* isolate, Handle<FixedArray> declarations,
// ES#sec-globaldeclarationinstantiation 5.d:
// If hasRestrictedGlobal is true, throw a SyntaxError exception.
Object result = DeclareGlobal(isolate, global, name, value,
static_cast<PropertyAttributes>(attr), is_var,
is_function, RedeclarationType::kSyntaxError,
feedback_vector, slot);
Object result = DeclareGlobal(
isolate, global, name, value, static_cast<PropertyAttributes>(attr),
is_var, RedeclarationType::kSyntaxError, feedback_vector);
if (isolate->has_pending_exception()) return result;
});
......@@ -228,9 +203,8 @@ Object DeclareEvalHelper(Isolate* isolate, Handle<String> name,
(context->IsBlockContext() &&
context->scope_info().is_declaration_scope()));
bool is_function = value->IsJSFunction();
bool is_var = !is_function;
DCHECK(!is_var || value->IsUndefined(isolate));
bool is_var = value->IsUndefined(isolate);
DCHECK_IMPLIES(!is_var, value->IsJSFunction());
int index;
PropertyAttributes attributes;
......@@ -249,20 +223,19 @@ Object DeclareEvalHelper(Isolate* isolate, Handle<String> name,
// ES#sec-evaldeclarationinstantiation 8.a.iv.1.b:
// If fnDefinable is false, throw a TypeError exception.
return DeclareGlobal(isolate, Handle<JSGlobalObject>::cast(holder), name,
value, NONE, is_var, is_function,
RedeclarationType::kTypeError);
value, NONE, is_var, RedeclarationType::kTypeError);
}
if (context->has_extension() && context->extension().IsJSGlobalObject()) {
Handle<JSGlobalObject> global(JSGlobalObject::cast(context->extension()),
isolate);
return DeclareGlobal(isolate, global, name, value, NONE, is_var,
is_function, RedeclarationType::kTypeError);
RedeclarationType::kTypeError);
} else if (context->IsScriptContext()) {
DCHECK(context->global_object().IsJSGlobalObject());
Handle<JSGlobalObject> global(
JSGlobalObject::cast(context->global_object()), isolate);
return DeclareGlobal(isolate, global, name, value, NONE, is_var,
is_function, RedeclarationType::kTypeError);
RedeclarationType::kTypeError);
}
if (attributes != ABSENT) {
......@@ -271,7 +244,6 @@ Object DeclareEvalHelper(Isolate* isolate, Handle<String> name,
// Skip var re-declarations.
if (is_var) return ReadOnlyRoots(isolate).undefined_value();
DCHECK(is_function);
if (index != Context::kNotFound) {
DCHECK(holder.is_identical_to(context));
context->set(index, *value);
......
......@@ -22,7 +22,7 @@ bytecodes: [
B(Mov), R(closure), R(3),
B(CallRuntime), U16(Runtime::kDeclareGlobals), R(1), U8(3),
/* 8 S> */ B(LdaSmi), I8(1),
/* 8 E> */ B(StaGlobal), U8(1), U8(2),
/* 8 E> */ B(StaGlobal), U8(1), U8(0),
B(LdaUndefined),
/* 11 S> */ B(Return),
]
......@@ -74,9 +74,9 @@ bytecodes: [
B(Mov), R(closure), R(3),
B(CallRuntime), U16(Runtime::kDeclareGlobals), R(1), U8(3),
/* 8 S> */ B(LdaSmi), I8(1),
/* 8 E> */ B(StaGlobal), U8(1), U8(2),
/* 8 E> */ B(StaGlobal), U8(1), U8(0),
/* 11 S> */ B(LdaSmi), I8(2),
/* 12 E> */ B(StaGlobal), U8(1), U8(2),
/* 12 E> */ B(StaGlobal), U8(1), U8(0),
B(Star), R(0),
/* 16 S> */ B(Return),
]
......
......@@ -21,12 +21,12 @@ bytecodes: [
B(Star), R(2),
B(Mov), R(closure), R(3),
B(CallRuntime), U16(Runtime::kDeclareGlobals), R(1), U8(3),
/* 8 S> */ B(CreateObjectLiteral), U8(1), U8(2), U8(41),
/* 8 S> */ B(CreateObjectLiteral), U8(1), U8(0), U8(41),
B(Star), R(1),
/* 16 E> */ B(CreateClosure), U8(2), U8(0), U8(0),
B(StaNamedOwnProperty), R(1), U8(3), U8(3),
B(StaNamedOwnProperty), R(1), U8(3), U8(1),
B(Ldar), R(1),
/* 8 E> */ B(StaGlobal), U8(4), U8(5),
/* 8 E> */ B(StaGlobal), U8(4), U8(3),
B(LdaUndefined),
/* 34 S> */ B(Return),
]
......
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