Commit d1e08e7a authored by yangguo's avatar yangguo Committed by Commit bot

[debugger] do not expose temporary variables introduced by the parser.

R=bmeurer@chromium.org, kozyatinskiy@chromium.org
BUG=chromium:582048
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#35805}
parent 101260d3
...@@ -438,16 +438,13 @@ MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) { ...@@ -438,16 +438,13 @@ MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
return ContextLocalMaybeAssignedFlag::decode(value); return ContextLocalMaybeAssignedFlag::decode(value);
} }
bool ScopeInfo::VariableIsSynthetic(String* name) {
bool ScopeInfo::LocalIsSynthetic(int var) {
DCHECK(0 <= var && var < LocalCount());
// There's currently no flag stored on the ScopeInfo to indicate that a // There's currently no flag stored on the ScopeInfo to indicate that a
// variable is a compiler-introduced temporary. However, to avoid conflict // variable is a compiler-introduced temporary. However, to avoid conflict
// with user declarations, the current temporaries like .generator_object and // with user declarations, the current temporaries like .generator_object and
// .result start with a dot, so we can use that as a flag. It's a hack! // .result start with a dot, so we can use that as a flag. It's a hack!
Handle<String> name(LocalName(var)); return name->length() == 0 || name->Get(0) == '.' ||
return (name->length() > 0 && name->Get(0) == '.') || name->Equals(name->GetHeap()->this_string());
name->Equals(*GetIsolate()->factory()->this_string());
} }
......
...@@ -116,6 +116,7 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target, ...@@ -116,6 +116,7 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
// TODO(yangguo): check whether this is necessary, now that we materialize // TODO(yangguo): check whether this is necessary, now that we materialize
// context locals as well. // context locals as well.
Handle<String> name(scope_info->ParameterName(i)); Handle<String> name(scope_info->ParameterName(i));
if (ScopeInfo::VariableIsSynthetic(*name)) continue;
if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
Handle<Object> value = Handle<Object> value =
...@@ -129,8 +130,8 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target, ...@@ -129,8 +130,8 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
// Second fill all stack locals. // Second fill all stack locals.
for (int i = 0; i < scope_info->StackLocalCount(); ++i) { for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
if (scope_info->LocalIsSynthetic(i)) continue;
Handle<String> name(scope_info->StackLocalName(i)); Handle<String> name(scope_info->StackLocalName(i));
if (ScopeInfo::VariableIsSynthetic(*name)) continue;
Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i)); Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i));
// TODO(yangguo): We convert optimized out values to {undefined} when they // TODO(yangguo): We convert optimized out values to {undefined} when they
// are passed to the debugger. Eventually we should handle them somehow. // are passed to the debugger. Eventually we should handle them somehow.
...@@ -162,6 +163,7 @@ void FrameInspector::UpdateStackLocalsFromMaterializedObject( ...@@ -162,6 +163,7 @@ void FrameInspector::UpdateStackLocalsFromMaterializedObject(
for (int i = 0; i < scope_info->ParameterCount(); ++i) { for (int i = 0; i < scope_info->ParameterCount(); ++i) {
// Shadowed parameters were not materialized. // Shadowed parameters were not materialized.
Handle<String> name(scope_info->ParameterName(i)); Handle<String> name(scope_info->ParameterName(i));
if (ScopeInfo::VariableIsSynthetic(*name)) continue;
if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
DCHECK(!frame_->GetParameter(i)->IsTheHole()); DCHECK(!frame_->GetParameter(i)->IsTheHole());
...@@ -172,13 +174,12 @@ void FrameInspector::UpdateStackLocalsFromMaterializedObject( ...@@ -172,13 +174,12 @@ void FrameInspector::UpdateStackLocalsFromMaterializedObject(
// Stack locals. // Stack locals.
for (int i = 0; i < scope_info->StackLocalCount(); ++i) { for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
if (scope_info->LocalIsSynthetic(i)) continue; Handle<String> name(scope_info->StackLocalName(i));
if (ScopeInfo::VariableIsSynthetic(*name)) continue;
int index = scope_info->StackLocalIndex(i); int index = scope_info->StackLocalIndex(i);
if (frame_->GetExpression(index)->IsTheHole()) continue; if (frame_->GetExpression(index)->IsTheHole()) continue;
Handle<Object> value = Handle<Object> value =
Object::GetPropertyOrElement( Object::GetPropertyOrElement(target, name).ToHandleChecked();
target, handle(scope_info->StackLocalName(i), isolate_))
.ToHandleChecked();
frame_->SetExpression(index, *value); frame_->SetExpression(index, *value);
} }
} }
......
...@@ -801,19 +801,16 @@ void ScopeIterator::CopyContextLocalsToScopeObject( ...@@ -801,19 +801,16 @@ void ScopeIterator::CopyContextLocalsToScopeObject(
int local_count = scope_info->ContextLocalCount(); int local_count = scope_info->ContextLocalCount();
if (local_count == 0) return; if (local_count == 0) return;
// Fill all context locals to the context extension. // Fill all context locals to the context extension.
int first_context_var = scope_info->StackLocalCount();
int start = scope_info->ContextLocalNameEntriesIndex();
for (int i = 0; i < local_count; ++i) { for (int i = 0; i < local_count; ++i) {
if (scope_info->LocalIsSynthetic(first_context_var + i)) continue; Handle<String> name(scope_info->ContextLocalName(i));
if (ScopeInfo::VariableIsSynthetic(*name)) continue;
int context_index = Context::MIN_CONTEXT_SLOTS + i; int context_index = Context::MIN_CONTEXT_SLOTS + i;
Handle<Object> value = Handle<Object>(context->get(context_index), isolate); Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
// Reflect variables under TDZ as undefined in scope object. // Reflect variables under TDZ as undefined in scope object.
if (value->IsTheHole()) continue; if (value->IsTheHole()) continue;
// This should always succeed. // This should always succeed.
// TODO(verwaest): Use AddDataProperty instead. // TODO(verwaest): Use AddDataProperty instead.
JSObject::SetOwnPropertyIgnoreAttributes( JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE)
scope_object, handle(String::cast(scope_info->get(i + start))), value,
NONE)
.Check(); .Check();
} }
} }
......
...@@ -4194,7 +4194,7 @@ class ScopeInfo : public FixedArray { ...@@ -4194,7 +4194,7 @@ class ScopeInfo : public FixedArray {
// Return true if this local was introduced by the compiler, and should not be // Return true if this local was introduced by the compiler, and should not be
// exposed to the user in a debugger. // exposed to the user in a debugger.
bool LocalIsSynthetic(int var); static bool VariableIsSynthetic(String* name);
// Lookup support for serialized scope info. Returns the // Lookup support for serialized scope info. Returns the
// the stack slot index for a given slot name if the slot is // the stack slot index for a given slot name if the slot is
......
...@@ -571,7 +571,9 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) { ...@@ -571,7 +571,9 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
for (int slot = 0; slot < scope_info->LocalCount(); ++slot) { for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
// Hide compiler-introduced temporary variables, whether on the stack or on // Hide compiler-introduced temporary variables, whether on the stack or on
// the context. // the context.
if (scope_info->LocalIsSynthetic(slot)) local_count--; if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(slot))) {
local_count--;
}
} }
Handle<FixedArray> locals = Handle<FixedArray> locals =
...@@ -582,7 +584,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) { ...@@ -582,7 +584,7 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
int i = 0; int i = 0;
for (; i < scope_info->StackLocalCount(); ++i) { for (; i < scope_info->StackLocalCount(); ++i) {
// Use the value from the stack. // Use the value from the stack.
if (scope_info->LocalIsSynthetic(i)) continue; if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(i))) continue;
locals->set(local * 2, scope_info->LocalName(i)); locals->set(local * 2, scope_info->LocalName(i));
Handle<Object> value = frame_inspector.GetExpression(i); Handle<Object> value = frame_inspector.GetExpression(i);
// TODO(yangguo): We convert optimized out values to {undefined} when they // TODO(yangguo): We convert optimized out values to {undefined} when they
...@@ -596,8 +598,8 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) { ...@@ -596,8 +598,8 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
Handle<Context> context( Handle<Context> context(
Handle<Context>::cast(frame_inspector.GetContext())->closure_context()); Handle<Context>::cast(frame_inspector.GetContext())->closure_context());
for (; i < scope_info->LocalCount(); ++i) { for (; i < scope_info->LocalCount(); ++i) {
if (scope_info->LocalIsSynthetic(i)) continue;
Handle<String> name(scope_info->LocalName(i)); Handle<String> name(scope_info->LocalName(i));
if (ScopeInfo::VariableIsSynthetic(*name)) continue;
VariableMode mode; VariableMode mode;
InitializationFlag init_flag; InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag; MaybeAssignedFlag maybe_assigned_flag;
......
...@@ -183,10 +183,8 @@ function CheckScopeContent(content, number, exec_state) { ...@@ -183,10 +183,8 @@ function CheckScopeContent(content, number, exec_state) {
if (!scope.scopeObject().property('this').isUndefined()) { if (!scope.scopeObject().property('this').isUndefined()) {
scope_size--; scope_size--;
} }
// Skip property with empty name. // Temporary variables introduced by the parser have not been materialized.
if (!scope.scopeObject().property('').isUndefined()) { assertTrue(scope.scopeObject().property('').isUndefined());
scope_size--;
}
if (count != scope_size) { if (count != scope_size) {
print('Names found in scope:'); print('Names found in scope:');
......
...@@ -148,10 +148,8 @@ function CheckScopeContent(content, number, exec_state) { ...@@ -148,10 +148,8 @@ function CheckScopeContent(content, number, exec_state) {
if (!scope.scopeObject().property('arguments').isUndefined()) { if (!scope.scopeObject().property('arguments').isUndefined()) {
scope_size--; scope_size--;
} }
// Skip property with empty name. // Temporary variables introduced by the parser have not been materialized.
if (!scope.scopeObject().property('').isUndefined()) { assertTrue(scope.scopeObject().property('').isUndefined());
scope_size--;
}
if (count != scope_size) { if (count != scope_size) {
print('Names found in scope:'); print('Names found in scope:');
......
// 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: --expose-debug-as debug
var Debug = debug.Debug;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
var frame_count = exec_state.frameCount();
for (var i = 0; i < frame_count; i++) {
var frame = exec_state.frame(i);
var scope_count = frame.scopeCount();
for (var j = 0; j < scope_count; j++) {
var scope = frame.scope(j);
assertTrue(scope.scopeObject().property('').isUndefined());
}
}
} catch (e) {
print(e, e.stack);
exception = e;
}
}
Debug.setListener(listener);
(function(a = 1) { debugger; })();
Debug.setListener(null);
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