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