Remove Scope::scope_contains_with_ bit

This part of Scope has existed since V8's initial check in, but from what
I can tell it's not required to implement "with". The only tests that
depend upon it are tests of the debugger and the Scope mirrors, but the
resulting test behavior after removing the bit still seems perfectly
reasonable to me. In fact, with the included fix for scope name collection,
the scope mirror is actually improved with this change.

As a bi-product, this fixes the attached bug, about the contains_with
bit having inconsistent values in some arrow function compilation
scenarios.

BUG=chromium:592353
LOG=n
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1804783002

Cr-Commit-Position: refs/heads/master@{#34802}
This commit is contained in:
adamk 2016-03-15 15:41:13 -07:00 committed by Commit bot
parent 80b1b2a45b
commit 108efd7f54
9 changed files with 42 additions and 62 deletions

View File

@ -171,7 +171,6 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
this_function_ = nullptr; this_function_ = nullptr;
illegal_redecl_ = nullptr; illegal_redecl_ = nullptr;
scope_inside_with_ = false; scope_inside_with_ = false;
scope_contains_with_ = false;
scope_calls_eval_ = false; scope_calls_eval_ = false;
scope_uses_arguments_ = false; scope_uses_arguments_ = false;
scope_uses_super_property_ = false; scope_uses_super_property_ = false;
@ -210,7 +209,6 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
// Reconstruct the outer scope chain from a closure's context chain. // Reconstruct the outer scope chain from a closure's context chain.
Scope* current_scope = NULL; Scope* current_scope = NULL;
Scope* innermost_scope = NULL; Scope* innermost_scope = NULL;
bool contains_with = false;
while (!context->IsNativeContext()) { while (!context->IsNativeContext()) {
if (context->IsWithContext()) { if (context->IsWithContext()) {
Scope* with_scope = new (zone) Scope* with_scope = new (zone)
@ -218,7 +216,6 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
script_scope->ast_value_factory_); script_scope->ast_value_factory_);
current_scope = with_scope; current_scope = with_scope;
// All the inner scopes are inside a with. // All the inner scopes are inside a with.
contains_with = true;
for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) { for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
s->scope_inside_with_ = true; s->scope_inside_with_ = true;
} }
@ -252,13 +249,7 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
script_scope->ast_value_factory_->GetString(Handle<String>(name)), script_scope->ast_value_factory_->GetString(Handle<String>(name)),
script_scope->ast_value_factory_); script_scope->ast_value_factory_);
} }
if (contains_with) current_scope->RecordWithStatement();
if (innermost_scope == NULL) innermost_scope = current_scope; if (innermost_scope == NULL) innermost_scope = current_scope;
// Forget about a with when we move to a context for a different function.
if (context->previous()->closure() != context->closure()) {
contains_with = false;
}
context = context->previous(); context = context->previous();
} }
@ -392,7 +383,6 @@ void Scope::PropagateUsageFlagsToScope(Scope* other) {
if (uses_arguments()) other->RecordArgumentsUsage(); if (uses_arguments()) other->RecordArgumentsUsage();
if (uses_super_property()) other->RecordSuperPropertyUsage(); if (uses_super_property()) other->RecordSuperPropertyUsage();
if (calls_eval()) other->RecordEvalCall(); if (calls_eval()) other->RecordEvalCall();
if (scope_contains_with_) other->RecordWithStatement();
} }
@ -982,7 +972,6 @@ void Scope::Print(int n) {
Indent(n1, "// strict mode scope\n"); Indent(n1, "// strict mode scope\n");
} }
if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n"); if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n"); if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n"); if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
if (scope_uses_super_property_) if (scope_uses_super_property_)
@ -1254,8 +1243,8 @@ bool Scope::MustAllocate(Variable* var) {
// visible name. // visible name.
if ((var->is_this() || !var->raw_name()->IsEmpty()) && if ((var->is_this() || !var->raw_name()->IsEmpty()) &&
(var->has_forced_context_allocation() || scope_calls_eval_ || (var->has_forced_context_allocation() || scope_calls_eval_ ||
inner_scope_calls_eval_ || scope_contains_with_ || is_catch_scope() || inner_scope_calls_eval_ || is_catch_scope() || is_block_scope() ||
is_block_scope() || is_module_scope() || is_script_scope())) { is_module_scope() || is_script_scope())) {
var->set_is_used(); var->set_is_used();
if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned(); if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned();
} }
@ -1278,10 +1267,8 @@ bool Scope::MustAllocateInContext(Variable* var) {
if (var->mode() == TEMPORARY) return false; if (var->mode() == TEMPORARY) return false;
if (is_catch_scope() || is_module_scope()) return true; if (is_catch_scope() || is_module_scope()) return true;
if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true; if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true;
return var->has_forced_context_allocation() || return var->has_forced_context_allocation() || scope_calls_eval_ ||
scope_calls_eval_ || inner_scope_calls_eval_;
inner_scope_calls_eval_ ||
scope_contains_with_;
} }

View File

@ -245,9 +245,6 @@ class Scope: public ZoneObject {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Scope-specific info. // Scope-specific info.
// Inform the scope that the corresponding code contains a with statement.
void RecordWithStatement() { scope_contains_with_ = true; }
// Inform the scope that the corresponding code contains an eval call. // Inform the scope that the corresponding code contains an eval call.
void RecordEvalCall() { scope_calls_eval_ = true; } void RecordEvalCall() { scope_calls_eval_ = true; }
@ -646,8 +643,6 @@ class Scope: public ZoneObject {
// //
// This scope is inside a 'with' of some outer scope. // This scope is inside a 'with' of some outer scope.
bool scope_inside_with_; bool scope_inside_with_;
// This scope contains a 'with' statement.
bool scope_contains_with_;
// This scope or a nested catch scope or with scope contain an 'eval' call. At // This scope or a nested catch scope or with scope contain an 'eval' call. At
// the 'eval' call site this scope is the declaration scope. // the 'eval' call site this scope is the declaration scope.
bool scope_calls_eval_; bool scope_calls_eval_;

View File

@ -135,11 +135,6 @@ MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
Handle<JSFunction> js_function = HasContext() Handle<JSFunction> js_function = HasContext()
? handle(CurrentContext()->closure()) ? handle(CurrentContext()->closure())
: Handle<JSFunction>::null(); : Handle<JSFunction>::null();
if (!js_function.is_null()) {
Handle<String> closure_name = JSFunction::GetDebugName(js_function);
if (!closure_name.is_null() && (closure_name->length() != 0))
details->set(kScopeDetailsNameIndex, *closure_name);
}
if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) { if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
return isolate_->factory()->NewJSArrayWithElements(details); return isolate_->factory()->NewJSArrayWithElements(details);
} }
@ -156,6 +151,10 @@ MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
} }
if (!js_function.is_null()) { if (!js_function.is_null()) {
Handle<String> closure_name = JSFunction::GetDebugName(js_function);
if (!closure_name.is_null() && closure_name->length() != 0) {
details->set(kScopeDetailsNameIndex, *closure_name);
}
details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position)); details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position));
details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position)); details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position));
details->set(kScopeDetailsFunctionIndex, *js_function); details->set(kScopeDetailsFunctionIndex, *js_function);

View File

@ -2711,7 +2711,6 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
Expression* expr = ParseExpression(true, CHECK_OK); Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
scope_->DeclarationScope()->RecordWithStatement();
Scope* with_scope = NewScope(scope_, WITH_SCOPE); Scope* with_scope = NewScope(scope_, WITH_SCOPE);
Statement* body; Statement* body;
{ BlockState block_state(&scope_, with_scope); { BlockState block_state(&scope_, with_scope);

View File

@ -11,27 +11,19 @@ wrap: yes
snippet: " snippet: "
with ({x:42}) { return x; } with ({x:42}) { return x; }
" "
frame size: 5 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 45 bytecode array length: 24
bytecodes: [ bytecodes: [
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), U8(1),
B(PushContext), R(0),
B(Ldar), R(this),
B(StaContextSlot), R(context), U8(4),
B(CreateMappedArguments),
B(StaContextSlot), R(context), U8(5),
B(Ldar), R(new_target),
B(StaContextSlot), R(context), U8(6),
B(StackCheck), B(StackCheck),
B(CreateObjectLiteral), U8(0), U8(0), U8(5), B(CreateObjectLiteral), U8(0), U8(0), U8(5),
B(Star), R(2), B(Star), R(1),
B(ToObject), B(ToObject),
B(Star), R(3), B(Star), R(2),
B(Ldar), R(closure), B(Ldar), R(closure),
B(Star), R(4), B(Star), R(3),
B(CallRuntime), U16(Runtime::kPushWithContext), R(3), U8(2), B(CallRuntime), U16(Runtime::kPushWithContext), R(2), U8(2),
B(PushContext), R(1), B(PushContext), R(0),
B(LdaLookupSlot), U8(1), B(LdaLookupSlot), U8(1),
B(Return), B(Return),
] ]

View File

@ -89,18 +89,17 @@ function f() {
} }
function checkFrame2(frame) { function checkFrame2(frame) {
// Frame 2 (f) has normal variables a and b (and arguments). // Frame 2 (f) has normal variables a and b.
var count = frame.localCount(); var count = frame.localCount();
assertEquals(3, count); assertEquals(2, count);
for (var i = 0; i < count; ++i) { for (var i = 0; i < count; ++i) {
var name = frame.localName(i); var name = frame.localName(i);
var value = frame.localValue(i).value(); var value = frame.localValue(i).value();
if (name == 'a') { if (name == 'a') {
assertEquals(5, value); assertEquals(5, value);
} else if (name == 'b') {
assertEquals(0, value);
} else { } else {
assertEquals('arguments', name); assertEquals('b', name);
assertEquals(0, value);
} }
} }
} }

View File

@ -73,7 +73,7 @@ assertEquals(6, mirror.scopeCount());
CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure); CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
CheckScope(mirror.scope(1), { w: 5, v: "Capybara" }, ScopeType.With); CheckScope(mirror.scope(1), { w: 5, v: "Capybara" }, ScopeType.With);
CheckScope(mirror.scope(2), { y: 17, z: 22 }, ScopeType.Closure); CheckScope(mirror.scope(2), { z: 22 }, ScopeType.Closure);
CheckScope(mirror.scope(3), { x: 5 }, ScopeType.Closure); CheckScope(mirror.scope(3), { x: 5 }, ScopeType.Closure);
CheckScope(mirror.scope(4), {}, ScopeType.Script); CheckScope(mirror.scope(4), {}, ScopeType.Script);
CheckScope(mirror.scope(5), {}, ScopeType.Global); CheckScope(mirror.scope(5), {}, ScopeType.Global);

View File

@ -152,7 +152,7 @@ function CheckScopeChainNames(names, exec_state) {
for (var i = 0; i < names.length; i++) { for (var i = 0; i < names.length; i++) {
var scope = exec_state.frame().scope(i); var scope = exec_state.frame().scope(i);
assertTrue(scope.isScope()); assertTrue(scope.isScope());
assertEquals(scope.details().name(), names[i]) assertEquals(names[i], scope.details().name())
} }
} }
@ -544,7 +544,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({a:1}, 1, exec_state); CheckScopeContent({a:1}, 1, exec_state);
CheckScopeChainNames([undefined, "closure_1", undefined, undefined], exec_state) CheckScopeChainNames(["f", "closure_1", undefined, undefined], exec_state)
}; };
closure_1(1)(); closure_1(1)();
EndTest(); EndTest();
@ -571,7 +571,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({a:1,x:3}, 1, exec_state); CheckScopeContent({a:1,x:3}, 1, exec_state);
CheckScopeChainNames([undefined, "closure_2", undefined, undefined], exec_state) CheckScopeChainNames(["f", "closure_2", undefined, undefined], exec_state)
}; };
closure_2(1, 2)(); closure_2(1, 2)();
EndTest(); EndTest();
@ -599,7 +599,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({a:1,b:2,x:3,y:4}, 1, exec_state); CheckScopeContent({a:1,b:2,x:3,y:4}, 1, exec_state);
CheckScopeChainNames([undefined, "closure_3", undefined, undefined], exec_state) CheckScopeChainNames(["f", "closure_3", undefined, undefined], exec_state)
}; };
closure_3(1, 2)(); closure_3(1, 2)();
EndTest(); EndTest();
@ -630,7 +630,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({a:1,b:2,x:3,y:4,f:function(){}}, 1, exec_state); CheckScopeContent({a:1,b:2,x:3,y:4,f:function(){}}, 1, exec_state);
CheckScopeChainNames([undefined, "closure_4", undefined, undefined], exec_state) CheckScopeChainNames(["f", "closure_4", undefined, undefined], exec_state)
}; };
closure_4(1, 2)(); closure_4(1, 2)();
EndTest(); EndTest();
@ -748,7 +748,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({x: 2}, 0, exec_state); CheckScopeContent({x: 2}, 0, exec_state);
CheckScopeChainNames([undefined, undefined, undefined], exec_state) CheckScopeChainNames(["inner", undefined, undefined], exec_state)
}; };
closure_8(); closure_8();
EndTest(); EndTest();
@ -770,7 +770,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Closure, debug.ScopeType.Closure,
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeChainNames([undefined, "closure_9", undefined, undefined], exec_state) CheckScopeChainNames(["inner", "closure_9", undefined, undefined], exec_state)
}; };
closure_9(); closure_9();
EndTest(); EndTest();
@ -837,10 +837,10 @@ function closure_in_with_1() {
listener_delegate = function(exec_state) { listener_delegate = function(exec_state) {
CheckScopeChain([debug.ScopeType.Local, CheckScopeChain([debug.ScopeType.Local,
debug.ScopeType.With, debug.ScopeType.With,
debug.ScopeType.Closure,
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({x: 2}, 0, exec_state); CheckScopeContent({x: 2}, 0, exec_state);
CheckScopeContent({x: 1}, 1, exec_state);
}; };
closure_in_with_1(); closure_in_with_1();
EndTest(); EndTest();
@ -861,13 +861,12 @@ listener_delegate = function(exec_state) {
CheckScopeChain([debug.ScopeType.With, CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.Local, debug.ScopeType.Local,
debug.ScopeType.With, debug.ScopeType.With,
debug.ScopeType.Closure,
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({x: 3}, 0, exec_state); CheckScopeContent({x: 3}, 0, exec_state);
CheckScopeContent({x: 2}, 1, exec_state); CheckScopeContent({x: 2}, 1, exec_state);
CheckScopeContent({x: 1}, 2, exec_state); CheckScopeContent({x: 1}, 2, exec_state);
CheckScopeChainNames(["inner", "inner", "closure_in_with_2", "closure_in_with_2", undefined, undefined], exec_state) CheckScopeChainNames(["inner", "inner", "closure_in_with_2", undefined, undefined], exec_state)
}; };
closure_in_with_2(); closure_in_with_2();
EndTest(); EndTest();
@ -949,7 +948,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({e:'Exception'}, 0, exec_state); CheckScopeContent({e:'Exception'}, 0, exec_state);
CheckScopeChainNames(["catch_block_1", undefined, undefined, undefined], exec_state) CheckScopeChainNames(["catch_block_1", "catch_block_1", undefined, undefined], exec_state)
}; };
catch_block_1(); catch_block_1();
EndTest(); EndTest();
@ -1095,7 +1094,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({e:'Exception'}, 0, exec_state); CheckScopeContent({e:'Exception'}, 0, exec_state);
CheckScopeChainNames(["catch_block_7", undefined, undefined, undefined], exec_state) CheckScopeChainNames(["catch_block_7", "catch_block_7", undefined, undefined], exec_state)
}; };
catch_block_7(); catch_block_7();
EndTest(); EndTest();
@ -1109,7 +1108,7 @@ listener_delegate = function(exec_state) {
debug.ScopeType.Script, debug.ScopeType.Script,
debug.ScopeType.Global], exec_state); debug.ScopeType.Global], exec_state);
CheckScopeContent({}, 1, exec_state); CheckScopeContent({}, 1, exec_state);
CheckScopeChainNames([undefined, undefined, undefined], exec_state) CheckScopeChainNames(["m", undefined, undefined], exec_state)
}; };
(function() { (function() {

View File

@ -0,0 +1,10 @@
// Copyright 2016 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.
//
// Flags: --allow-natives-syntax --no-lazy
with ({}) {}
f = ({x}) => { };
%OptimizeFunctionOnNextCall(f);
f({});