Index: src/runtime/runtime-debug.cc |
diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc |
index d576dc73a9f41a0f5adcd93874ad2ed5edfa6c5d..68d2f9e4777d0ef30b9e558345ef37039eca26cc 100644 |
--- a/src/runtime/runtime-debug.cc |
+++ b/src/runtime/runtime-debug.cc |
@@ -801,6 +801,29 @@ MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( |
} |
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScriptScope( |
+ Handle<GlobalObject> global) { |
+ Isolate* isolate = global->GetIsolate(); |
+ Handle<ScriptContextTable> script_contexts( |
+ global->native_context()->script_context_table()); |
+ |
+ Handle<JSObject> script_scope = |
+ isolate->factory()->NewJSObject(isolate->object_function()); |
+ |
+ for (int context_index = 0; context_index < script_contexts->used(); |
+ context_index++) { |
+ Handle<Context> context = |
+ ScriptContextTable::GetContext(script_contexts, context_index); |
+ Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); |
+ if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, |
+ script_scope)) { |
+ return MaybeHandle<JSObject>(); |
+ } |
+ } |
+ return script_scope; |
+} |
+ |
+ |
MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope( |
Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) { |
FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); |
@@ -997,6 +1020,24 @@ static bool SetBlockContextVariableValue(Handle<Context> block_context, |
} |
+static bool SetScriptVariableValue(Handle<Context> context, |
+ Handle<String> variable_name, |
+ Handle<Object> new_value) { |
+ Handle<ScriptContextTable> script_contexts( |
+ context->global_object()->native_context()->script_context_table()); |
+ ScriptContextTable::LookupResult lookup_result; |
+ if (ScriptContextTable::Lookup(script_contexts, variable_name, |
+ &lookup_result)) { |
+ Handle<Context> script_context = ScriptContextTable::GetContext( |
+ script_contexts, lookup_result.context_index); |
+ script_context->set(lookup_result.slot_index, *new_value); |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+ |
// Create a plain JSObject which materializes the scope for the specified |
// catch context. |
MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope( |
@@ -1084,6 +1125,7 @@ class ScopeIterator { |
ScopeTypeClosure, |
ScopeTypeCatch, |
ScopeTypeBlock, |
+ ScopeTypeScript, |
ScopeTypeModule |
}; |
@@ -1095,6 +1137,7 @@ class ScopeIterator { |
function_(frame->function()), |
context_(Context::cast(frame->context())), |
nested_scope_chain_(4), |
+ seen_script_scope_(false), |
failed_(false) { |
// Catch the case when the debugger stops in an internal function. |
Handle<SharedFunctionInfo> shared_info(function_->shared()); |
@@ -1186,6 +1229,7 @@ class ScopeIterator { |
inlined_jsframe_index_(0), |
function_(function), |
context_(function->context()), |
+ seen_script_scope_(false), |
failed_(false) { |
if (function->IsBuiltin()) { |
context_ = Handle<Context>(); |
@@ -1210,8 +1254,16 @@ class ScopeIterator { |
context_ = Handle<Context>(); |
return; |
} |
+ if (scope_type == ScopeTypeScript) seen_script_scope_ = true; |
if (nested_scope_chain_.is_empty()) { |
- context_ = Handle<Context>(context_->previous(), isolate_); |
+ if (scope_type == ScopeTypeScript) { |
+ if (context_->IsScriptContext()) { |
+ context_ = Handle<Context>(context_->previous(), isolate_); |
+ } |
+ CHECK(context_->IsNativeContext()); |
+ } else { |
+ context_ = Handle<Context>(context_->previous(), isolate_); |
+ } |
} else { |
if (nested_scope_chain_.last()->HasContext()) { |
DCHECK(context_->previous() != NULL); |
@@ -1235,8 +1287,8 @@ class ScopeIterator { |
DCHECK(context_->IsModuleContext()); |
return ScopeTypeModule; |
case SCRIPT_SCOPE: |
- DCHECK(context_->IsNativeContext()); |
- return ScopeTypeGlobal; |
+ DCHECK(context_->IsScriptContext() || context_->IsNativeContext()); |
+ return ScopeTypeScript; |
case WITH_SCOPE: |
DCHECK(context_->IsWithContext()); |
return ScopeTypeWith; |
@@ -1252,7 +1304,9 @@ class ScopeIterator { |
} |
if (context_->IsNativeContext()) { |
DCHECK(context_->global_object()->IsGlobalObject()); |
- return ScopeTypeGlobal; |
+ // If we are at the native context and have not yet seen script scope, |
+ // fake it. |
+ return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript; |
} |
if (context_->IsFunctionContext()) { |
return ScopeTypeClosure; |
@@ -1266,6 +1320,9 @@ class ScopeIterator { |
if (context_->IsModuleContext()) { |
return ScopeTypeModule; |
} |
+ if (context_->IsScriptContext()) { |
+ return ScopeTypeScript; |
+ } |
DCHECK(context_->IsWithContext()); |
return ScopeTypeWith; |
} |
@@ -1276,6 +1333,9 @@ class ScopeIterator { |
switch (Type()) { |
case ScopeIterator::ScopeTypeGlobal: |
return Handle<JSObject>(CurrentContext()->global_object()); |
+ case ScopeIterator::ScopeTypeScript: |
+ return MaterializeScriptScope( |
+ Handle<GlobalObject>(CurrentContext()->global_object())); |
case ScopeIterator::ScopeTypeLocal: |
// Materialize the content of the local scope into a JSObject. |
DCHECK(nested_scope_chain_.length() == 1); |
@@ -1314,6 +1374,9 @@ class ScopeIterator { |
case ScopeIterator::ScopeTypeClosure: |
return SetClosureVariableValue(isolate_, CurrentContext(), |
variable_name, new_value); |
+ case ScopeIterator::ScopeTypeScript: |
+ return SetScriptVariableValue(CurrentContext(), variable_name, |
+ new_value); |
case ScopeIterator::ScopeTypeBlock: |
return SetBlockContextVariableValue(CurrentContext(), variable_name, |
new_value); |
@@ -1340,7 +1403,8 @@ class ScopeIterator { |
// be an actual context. |
Handle<Context> CurrentContext() { |
DCHECK(!failed_); |
- if (Type() == ScopeTypeGlobal || nested_scope_chain_.is_empty()) { |
+ if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript || |
+ nested_scope_chain_.is_empty()) { |
return context_; |
} else if (nested_scope_chain_.last()->HasContext()) { |
return context_; |
@@ -1397,6 +1461,15 @@ class ScopeIterator { |
} |
break; |
+ case ScopeIterator::ScopeTypeScript: |
+ os << "Script:\n"; |
+ CurrentContext() |
+ ->global_object() |
+ ->native_context() |
+ ->script_context_table() |
+ ->Print(os); |
+ break; |
+ |
default: |
UNREACHABLE(); |
} |
@@ -1411,6 +1484,7 @@ class ScopeIterator { |
Handle<JSFunction> function_; |
Handle<Context> context_; |
List<Handle<ScopeInfo> > nested_scope_chain_; |
+ bool seen_script_scope_; |
bool failed_; |
void RetrieveScopeChain(Scope* scope, |
@@ -2175,6 +2249,7 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) { |
// We iterate to find the function's context. If the function has no |
// context-allocated variables, we iterate until we hit the outer context. |
while (!function_context->IsFunctionContext() && |
+ !function_context->IsScriptContext() && |
!function_context.is_identical_to(outer_context)) { |
inner_context = function_context; |
function_context = Handle<Context>(function_context->previous(), isolate); |