| Index: src/runtime/runtime-debug.cc
|
| diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc
|
| index d1e857add81241d44434d1e55b2b701458a3aac2..736d33dadce30cdfcc9571eb4b50dc13d6ad3c73 100644
|
| --- a/src/runtime/runtime-debug.cc
|
| +++ b/src/runtime/runtime-debug.cc
|
| @@ -2253,27 +2253,38 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
|
| // [inner context] -> [function stack]+[function context] -> [outer context]
|
| // The function stack is not an actual context, it complements the function
|
| // context. In order to have the same lookup chain when debug-evaluating,
|
| - // we materialize the stack and insert it into the context chain as a
|
| - // with-context before the function context.
|
| - // [inner context] -> [with context] -> [function context] -> [outer context]
|
| + // we:
|
| + // - clone inner context
|
| + // - materialize the stack and insert it into the context chain as a
|
| + // with-context before the function context.
|
| + // [inner context clone] -> [with context] -> [function context] ->
|
| + // [outer context]
|
| // Ordering the with-context before the function context forces a dynamic
|
| // lookup instead of a static lookup that could fail as the scope info is
|
| // outdated and may expect variables to still be stack-allocated.
|
| - // Afterwards, we write changes to the with-context back to the stack
|
| - // and remove it from the context chain.
|
| - // This could cause lookup failures if debug-evaluate creates a closure that
|
| - // uses this temporary context chain.
|
| + // Afterwards, we write changes to the with-context back to the stack, and
|
| + // write changes in cloned contexts back to original contexts.
|
|
|
| DCHECK(!eval_context.is_null());
|
| Handle<Context> function_context = eval_context;
|
| Handle<Context> outer_context(function->context(), isolate);
|
| Handle<Context> inner_context;
|
| - // We iterate to find the function's context. If the function has no
|
| - // context-allocated variables, we iterate until we hit the outer context.
|
| + Handle<Context> innermost_context;
|
| +
|
| + // We iterate to find the function's context, cloning until we hit it.
|
| + // 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;
|
| + Handle<Context> clone = Handle<Context>::cast(
|
| + FixedArray::CopySize(function_context, function_context->length()));
|
| + if (!inner_context.is_null()) {
|
| + inner_context->set_previous(*clone);
|
| + } else {
|
| + innermost_context = clone;
|
| + }
|
| + inner_context = clone;
|
| function_context = Handle<Context>(function_context->previous(), isolate);
|
| }
|
|
|
| @@ -2282,17 +2293,15 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
|
|
|
| if (inner_context.is_null()) {
|
| // No inner context. The with-context is now inner-most.
|
| - eval_context = materialized_context;
|
| + innermost_context = materialized_context;
|
| } else {
|
| inner_context->set_previous(*materialized_context);
|
| }
|
|
|
| Handle<Object> receiver(frame->receiver(), isolate);
|
| - MaybeHandle<Object> maybe_result = DebugEvaluate(
|
| - isolate, outer_info, eval_context, context_extension, receiver, source);
|
| -
|
| - // Remove with-context if it was inserted in between.
|
| - if (!inner_context.is_null()) inner_context->set_previous(*function_context);
|
| + MaybeHandle<Object> maybe_result =
|
| + DebugEvaluate(isolate, outer_info, innermost_context, context_extension,
|
| + receiver, source);
|
|
|
| Handle<Object> result;
|
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
|
| @@ -2301,6 +2310,15 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
|
| UpdateStackLocalsFromMaterializedObject(isolate, materialized, function,
|
| frame, inlined_jsframe_index);
|
|
|
| + while (!innermost_context.is_identical_to(materialized_context)) {
|
| + DCHECK(eval_context->map() == innermost_context->map());
|
| + innermost_context->CopyTo(
|
| + Context::MIN_CONTEXT_SLOTS, *eval_context, Context::MIN_CONTEXT_SLOTS,
|
| + innermost_context->length() - Context::MIN_CONTEXT_SLOTS);
|
| + innermost_context = handle(innermost_context->previous(), isolate);
|
| + eval_context = handle(eval_context->previous(), isolate);
|
| + }
|
| +
|
| return *result;
|
| }
|
|
|
|
|