Chromium Code Reviews| Index: src/runtime/runtime-debug.cc |
| diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc |
| index 28657ee72bcbd3677cdf79e5947e121a5543f0c0..36720111c4057d554791809d8f938a318e3626a1 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); |
| @@ -986,6 +1009,24 @@ static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> 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( |
| @@ -1068,6 +1109,7 @@ class ScopeIterator { |
| public: |
| enum ScopeType { |
| ScopeTypeGlobal = 0, |
| + ScopeTypeScript, |
| ScopeTypeLocal, |
| ScopeTypeWith, |
| ScopeTypeClosure, |
| @@ -1084,6 +1126,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()); |
| @@ -1175,6 +1218,7 @@ class ScopeIterator { |
| inlined_jsframe_index_(0), |
| function_(function), |
| context_(function->context()), |
| + seen_script_scope_(false), |
| failed_(false) { |
| if (function->IsBuiltin()) { |
| context_ = Handle<Context>(); |
| @@ -1200,8 +1244,17 @@ class ScopeIterator { |
| return; |
| } |
| if (nested_scope_chain_.is_empty()) { |
| - context_ = Handle<Context>(context_->previous(), isolate_); |
| + if (scope_type == ScopeTypeScript) { |
| + seen_script_scope_ = true; // Our current context was script context. |
| + if (context_->IsScriptContext()) { |
| + context_ = Handle<Context>(context_->previous(), isolate_); |
| + } |
| + CHECK(context_->IsNativeContext()); |
| + } else { |
| + context_ = Handle<Context>(context_->previous(), isolate_); |
| + } |
| } else { |
| + seen_script_scope_ = scope_type == ScopeTypeScript; |
| if (nested_scope_chain_.last()->HasContext()) { |
| DCHECK(context_->previous() != NULL); |
| context_ = Handle<Context>(context_->previous(), isolate_); |
| @@ -1224,8 +1277,8 @@ class ScopeIterator { |
| DCHECK(context_->IsModuleContext()); |
| return ScopeTypeModule; |
| case SCRIPT_SCOPE: |
| - DCHECK(context_->IsNativeContext()); |
| - return ScopeTypeGlobal; |
| + DCHECK(context_->IsScriptContext() || context_->IsNativeContext()); |
|
yurys
2014/11/14 12:25:32
Why not return ScopeTypeScript only in case contex
|
| + return ScopeTypeScript; |
| case WITH_SCOPE: |
| DCHECK(context_->IsWithContext()); |
| return ScopeTypeWith; |
| @@ -1241,7 +1294,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, |
|
yurys
2014/11/14 12:25:32
Can you educate me on how this works, I thought th
Dmitry Lomov (no reviews)
2014/11/14 13:56:51
No. I tried to explain this in CL description but
yurys
2014/11/14 15:02:02
Gotcha, thanks for explaining!
|
| + // fake it. |
| + return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript; |
| } |
| if (context_->IsFunctionContext()) { |
| return ScopeTypeClosure; |
| @@ -1255,6 +1310,9 @@ class ScopeIterator { |
| if (context_->IsModuleContext()) { |
| return ScopeTypeModule; |
| } |
| + if (context_->IsScriptContext()) { |
| + return ScopeTypeScript; |
| + } |
| DCHECK(context_->IsWithContext()); |
| return ScopeTypeWith; |
| } |
| @@ -1265,6 +1323,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); |
| @@ -1303,6 +1364,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: |
| // TODO(2399): should we implement it? |
| break; |
| @@ -1329,7 +1393,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_; |
| @@ -1386,6 +1451,15 @@ class ScopeIterator { |
| } |
| break; |
| + case ScopeIterator::ScopeTypeScript: |
| + os << "Script:\n"; |
| + CurrentContext() |
| + ->global_object() |
| + ->native_context() |
| + ->script_context_table() |
| + ->Print(os); |
| + break; |
| + |
| default: |
| UNREACHABLE(); |
| } |
| @@ -1400,6 +1474,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, |
| @@ -2164,6 +2239,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); |