debug-scopes.cc 31 KB
Newer Older
1 2 3 4 5 6
// Copyright 2015 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.

#include "src/debug/debug-scopes.h"

7 8
#include <memory>

9
#include "src/ast/ast.h"
10
#include "src/ast/scopes.h"
11
#include "src/debug/debug.h"
12
#include "src/frames-inl.h"
13
#include "src/globals.h"
14
#include "src/isolate-inl.h"
15
#include "src/parsing/parse-info.h"
16
#include "src/parsing/parsing.h"
verwaest's avatar
verwaest committed
17
#include "src/parsing/rewriter.h"
18 19 20 21 22

namespace v8 {
namespace internal {

ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
23
                             ScopeIterator::Option option)
24 25 26
    : isolate_(isolate),
      frame_inspector_(frame_inspector),
      nested_scope_chain_(4),
27
      seen_script_scope_(false) {
28
  if (!frame_inspector->GetContext()->IsContext()) {
29 30 31 32
    // Optimized frame, context or function cannot be materialized. Give up.
    return;
  }

33
  context_ = Handle<Context>::cast(frame_inspector->GetContext());
34

35 36 37
  // We should not instantiate a ScopeIterator for wasm frames.
  DCHECK(frame_inspector->GetScript()->type() != Script::TYPE_WASM);

38 39 40 41
  // Catch the case when the debugger stops in an internal function.
  Handle<JSFunction> function = GetFunction();
  Handle<SharedFunctionInfo> shared_info(function->shared());
  Handle<ScopeInfo> scope_info(shared_info->scope_info());
42
  if (shared_info->script()->IsUndefined(isolate)) {
43 44 45 46 47 48 49 50 51 52 53 54
    while (context_->closure() == *function) {
      context_ = Handle<Context>(context_->previous(), isolate_);
    }
    return;
  }

  // Currently it takes too much time to find nested scopes due to script
  // parsing. Sometimes we want to run the ScopeIterator as fast as possible
  // (for example, while collecting async call stacks on every
  // addEventListener call), even if we drop some nested scopes.
  // Later we may optimize getting the nested scopes (cache the result?)
  // and include nested scopes into the "fast" iteration case as well.
55 56
  bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES);
  bool collect_non_locals = (option == COLLECT_NON_LOCALS);
57 58 59 60 61 62 63
  if (!ignore_nested_scopes && shared_info->HasDebugInfo()) {
    // The source position at return is always the end of the function,
    // which is not consistent with the current scope chain. Therefore all
    // nested with, catch and block contexts are skipped, and we can only
    // inspect the function scope.
    // This can only happen if we set a break point inside right before the
    // return, which requires a debug info to be available.
64
    Handle<DebugInfo> debug_info(shared_info->GetDebugInfo());
65 66

    // Find the break point where execution has stopped.
67
    BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
68 69 70 71 72 73 74 75 76 77 78 79

    ignore_nested_scopes = location.IsReturn();
  }

  if (ignore_nested_scopes) {
    if (scope_info->HasContext()) {
      context_ = Handle<Context>(context_->declaration_context(), isolate_);
    } else {
      while (context_->closure() == *function) {
        context_ = Handle<Context>(context_->previous(), isolate_);
      }
    }
80
    if (scope_info->scope_type() == FUNCTION_SCOPE) {
81 82 83
      nested_scope_chain_.Add(ExtendedScopeInfo(scope_info,
                                                shared_info->start_position(),
                                                shared_info->end_position()));
84
    }
85 86 87 88 89
    if (!collect_non_locals) return;
  }

  // Reparse the code and analyze the scopes.
  // Check whether we are in global, eval or function code.
90
  Zone zone(isolate->allocator(), ZONE_NAME);
91
  std::unique_ptr<ParseInfo> info;
92 93
  if (scope_info->scope_type() != FUNCTION_SCOPE) {
    // Global or eval code.
94
    Handle<Script> script(Script::cast(shared_info->script()));
95
    info.reset(new ParseInfo(&zone, script));
96
    if (scope_info->scope_type() == EVAL_SCOPE) {
97
      info->set_eval();
98 99 100
      if (!function->context()->IsNativeContext()) {
        info->set_outer_scope_info(handle(function->context()->scope_info()));
      }
101 102 103
      // Language mode may be inherited from the eval caller.
      // Retrieve it from shared function info.
      info->set_language_mode(shared_info->language_mode());
104 105
    } else if (scope_info->scope_type() == MODULE_SCOPE) {
      info->set_module();
106 107
    } else {
      DCHECK(scope_info->scope_type() == SCRIPT_SCOPE);
108 109
    }
  } else {
110
    // Inner function.
111
    info.reset(new ParseInfo(&zone, shared_info));
112
  }
113
  if (parsing::ParseAny(info.get()) && Rewriter::Rewrite(info.get())) {
verwaest's avatar
verwaest committed
114 115 116 117 118
    DeclarationScope* scope = info->literal()->scope();
    if (!ignore_nested_scopes || collect_non_locals) {
      CollectNonLocals(info.get(), scope);
    }
    if (!ignore_nested_scopes) {
119
      DeclarationScope::Analyze(info.get(), AnalyzeMode::kDebugger);
verwaest's avatar
verwaest committed
120 121
      RetrieveScopeChain(scope);
    }
122
  } else {
verwaest's avatar
verwaest committed
123 124 125 126 127 128
    // A failed reparse indicates that the preparser has diverged from the
    // parser or that the preparse data given to the initial parse has been
    // faulty. We fail in debug mode but in release mode we only provide the
    // information we get from the context chain but nothing about
    // completely stack allocated scopes or stack allocated locals.
    // Or it could be due to stack overflow.
129 130 131 132
    // Silently fail by presenting an empty context chain.
    CHECK(isolate_->has_pending_exception());
    isolate_->clear_pending_exception();
    context_ = Handle<Context>();
verwaest's avatar
verwaest committed
133
  }
134
  UnwrapEvaluationContext();
135 136 137 138 139 140
}

ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
    : isolate_(isolate),
      frame_inspector_(NULL),
      context_(function->context()),
141
      seen_script_scope_(false) {
142
  if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>();
143 144 145
  UnwrapEvaluationContext();
}

146 147 148 149 150
ScopeIterator::ScopeIterator(Isolate* isolate,
                             Handle<JSGeneratorObject> generator)
    : isolate_(isolate),
      frame_inspector_(NULL),
      context_(generator->context()),
151
      seen_script_scope_(false) {
152 153 154 155 156 157
  if (!generator->function()->shared()->IsSubjectToDebugging()) {
    context_ = Handle<Context>();
  }
  UnwrapEvaluationContext();
}

158 159 160 161 162 163 164 165 166 167 168 169
void ScopeIterator::UnwrapEvaluationContext() {
  while (true) {
    if (context_.is_null()) return;
    if (!context_->IsDebugEvaluateContext()) return;
    Handle<Object> wrapped(context_->get(Context::WRAPPED_CONTEXT_INDEX),
                           isolate_);
    if (wrapped->IsContext()) {
      context_ = Handle<Context>::cast(wrapped);
    } else {
      context_ = Handle<Context>(context_->previous(), isolate_);
    }
  }
170 171 172 173 174 175 176 177 178 179 180 181
}


MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
  // Calculate the size of the result.
  Handle<FixedArray> details =
      isolate_->factory()->NewFixedArray(kScopeDetailsSize);
  // Fill in scope details.
  details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
  Handle<JSObject> scope_object;
  ASSIGN_RETURN_ON_EXCEPTION(isolate_, scope_object, ScopeObject(), JSObject);
  details->set(kScopeDetailsObjectIndex, *scope_object);
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  Handle<JSFunction> js_function = HasContext()
                                       ? handle(CurrentContext()->closure())
                                       : Handle<JSFunction>::null();
  if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
    return isolate_->factory()->NewJSArrayWithElements(details);
  }

  int start_position = 0;
  int end_position = 0;
  if (!nested_scope_chain_.is_empty()) {
    js_function = GetFunction();
    start_position = nested_scope_chain_.last().start_position;
    end_position = nested_scope_chain_.last().end_position;
  } else if (!js_function.is_null()) {
    start_position = js_function->shared()->start_position();
    end_position = js_function->shared()->end_position();
  }

  if (!js_function.is_null()) {
201 202 203 204
    Handle<String> closure_name = JSFunction::GetDebugName(js_function);
    if (!closure_name.is_null() && closure_name->length() != 0) {
      details->set(kScopeDetailsNameIndex, *closure_name);
    }
205 206 207 208
    details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position));
    details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position));
    details->set(kScopeDetailsFunctionIndex, *js_function);
  }
209 210 211 212 213
  return isolate_->factory()->NewJSArrayWithElements(details);
}


void ScopeIterator::Next() {
214
  DCHECK(!Done());
215 216 217 218 219
  ScopeType scope_type = Type();
  if (scope_type == ScopeTypeGlobal) {
    // The global scope is always the last in the chain.
    DCHECK(context_->IsNativeContext());
    context_ = Handle<Context>();
220
  } else if (scope_type == ScopeTypeScript) {
221 222 223 224 225
    seen_script_scope_ = true;
    if (context_->IsScriptContext()) {
      context_ = Handle<Context>(context_->previous(), isolate_);
    }
    if (!nested_scope_chain_.is_empty()) {
226 227
      DCHECK_EQ(nested_scope_chain_.last().scope_info->scope_type(),
                SCRIPT_SCOPE);
228 229 230 231
      nested_scope_chain_.RemoveLast();
      DCHECK(nested_scope_chain_.is_empty());
    }
    CHECK(context_->IsNativeContext());
232
  } else if (nested_scope_chain_.is_empty()) {
233 234
    context_ = Handle<Context>(context_->previous(), isolate_);
  } else {
235 236 237 238 239 240 241 242 243
    do {
      if (nested_scope_chain_.last().scope_info->HasContext()) {
        DCHECK(context_->previous() != NULL);
        context_ = Handle<Context>(context_->previous(), isolate_);
      }
      nested_scope_chain_.RemoveLast();
      if (nested_scope_chain_.is_empty()) break;
      // Repeat to skip hidden scopes.
    } while (nested_scope_chain_.last().is_hidden());
244
  }
245
  UnwrapEvaluationContext();
246 247 248 249 250
}


// Return the type of the current scope.
ScopeIterator::ScopeType ScopeIterator::Type() {
251
  DCHECK(!Done());
252
  if (!nested_scope_chain_.is_empty()) {
253
    Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
254 255 256 257 258 259 260 261 262 263 264
    switch (scope_info->scope_type()) {
      case FUNCTION_SCOPE:
        DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
        return ScopeTypeLocal;
      case MODULE_SCOPE:
        DCHECK(context_->IsModuleContext());
        return ScopeTypeModule;
      case SCRIPT_SCOPE:
        DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
        return ScopeTypeScript;
      case WITH_SCOPE:
265
        DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
266 267 268 269 270 271 272 273
        return ScopeTypeWith;
      case CATCH_SCOPE:
        DCHECK(context_->IsCatchContext());
        return ScopeTypeCatch;
      case BLOCK_SCOPE:
        DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
        return ScopeTypeBlock;
      case EVAL_SCOPE:
274
        DCHECK(!scope_info->HasContext() || context_->IsEvalContext());
275
        return ScopeTypeEval;
276
    }
277
    UNREACHABLE();
278 279
  }
  if (context_->IsNativeContext()) {
280
    DCHECK(context_->global_object()->IsJSGlobalObject());
281 282 283 284
    // If we are at the native context and have not yet seen script scope,
    // fake it.
    return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
  }
285
  if (context_->IsFunctionContext() || context_->IsEvalContext()) {
286 287 288 289 290 291 292 293 294 295 296 297 298 299
    return ScopeTypeClosure;
  }
  if (context_->IsCatchContext()) {
    return ScopeTypeCatch;
  }
  if (context_->IsBlockContext()) {
    return ScopeTypeBlock;
  }
  if (context_->IsModuleContext()) {
    return ScopeTypeModule;
  }
  if (context_->IsScriptContext()) {
    return ScopeTypeScript;
  }
300
  DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
301 302 303 304 305
  return ScopeTypeWith;
}


MaybeHandle<JSObject> ScopeIterator::ScopeObject() {
306
  DCHECK(!Done());
307 308
  switch (Type()) {
    case ScopeIterator::ScopeTypeGlobal:
309
      return Handle<JSObject>(CurrentContext()->global_proxy());
310 311 312 313 314 315 316
    case ScopeIterator::ScopeTypeScript:
      return MaterializeScriptScope();
    case ScopeIterator::ScopeTypeLocal:
      // Materialize the content of the local scope into a JSObject.
      DCHECK(nested_scope_chain_.length() == 1);
      return MaterializeLocalScope();
    case ScopeIterator::ScopeTypeWith:
317
      return WithContextExtension();
318 319 320 321 322 323
    case ScopeIterator::ScopeTypeCatch:
      return MaterializeCatchScope();
    case ScopeIterator::ScopeTypeClosure:
      // Materialize the content of the closure scope into a JSObject.
      return MaterializeClosure();
    case ScopeIterator::ScopeTypeBlock:
324 325
    case ScopeIterator::ScopeTypeEval:
      return MaterializeInnerScope();
326 327 328 329 330 331 332 333 334 335
    case ScopeIterator::ScopeTypeModule:
      return MaterializeModuleScope();
  }
  UNREACHABLE();
  return Handle<JSObject>();
}


bool ScopeIterator::HasContext() {
  ScopeType type = Type();
336 337
  if (type == ScopeTypeBlock || type == ScopeTypeLocal ||
      type == ScopeTypeEval) {
338
    if (!nested_scope_chain_.is_empty()) {
339
      return nested_scope_chain_.last().scope_info->HasContext();
340 341 342 343 344 345 346 347
    }
  }
  return true;
}


bool ScopeIterator::SetVariableValue(Handle<String> variable_name,
                                     Handle<Object> new_value) {
348
  DCHECK(!Done());
349 350 351 352 353 354 355 356 357 358 359 360 361 362
  switch (Type()) {
    case ScopeIterator::ScopeTypeGlobal:
      break;
    case ScopeIterator::ScopeTypeLocal:
      return SetLocalVariableValue(variable_name, new_value);
    case ScopeIterator::ScopeTypeWith:
      break;
    case ScopeIterator::ScopeTypeCatch:
      return SetCatchVariableValue(variable_name, new_value);
    case ScopeIterator::ScopeTypeClosure:
      return SetClosureVariableValue(variable_name, new_value);
    case ScopeIterator::ScopeTypeScript:
      return SetScriptVariableValue(variable_name, new_value);
    case ScopeIterator::ScopeTypeBlock:
363 364
    case ScopeIterator::ScopeTypeEval:
      return SetInnerScopeVariableValue(variable_name, new_value);
365
    case ScopeIterator::ScopeTypeModule:
366
      // TODO(neis): Implement.
367 368 369 370 371 372 373
      break;
  }
  return false;
}


Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() {
374
  DCHECK(!Done());
375
  if (!nested_scope_chain_.is_empty()) {
376
    return nested_scope_chain_.last().scope_info;
377 378
  } else if (context_->IsBlockContext() || context_->IsFunctionContext() ||
             context_->IsEvalContext()) {
379
    return Handle<ScopeInfo>(context_->scope_info());
380 381 382 383 384 385
  }
  return Handle<ScopeInfo>::null();
}


Handle<Context> ScopeIterator::CurrentContext() {
386
  DCHECK(!Done());
387 388 389
  if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
      nested_scope_chain_.is_empty()) {
    return context_;
390
  } else if (nested_scope_chain_.last().scope_info->HasContext()) {
391 392 393 394 395 396
    return context_;
  } else {
    return Handle<Context>();
  }
}

397
Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
398

399 400 401 402
#ifdef DEBUG
// Debug print of the content of the current scope.
void ScopeIterator::DebugPrint() {
  OFStream os(stdout);
403
  DCHECK(!Done());
404 405 406 407 408 409 410 411 412 413 414 415
  switch (Type()) {
    case ScopeIterator::ScopeTypeGlobal:
      os << "Global:\n";
      CurrentContext()->Print(os);
      break;

    case ScopeIterator::ScopeTypeLocal: {
      os << "Local:\n";
      GetFunction()->shared()->scope_info()->Print();
      if (!CurrentContext().is_null()) {
        CurrentContext()->Print(os);
        if (CurrentContext()->has_extension()) {
416
          Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
          if (extension->IsJSContextExtensionObject()) {
            extension->Print(os);
          }
        }
      }
      break;
    }

    case ScopeIterator::ScopeTypeWith:
      os << "With:\n";
      CurrentContext()->extension()->Print(os);
      break;

    case ScopeIterator::ScopeTypeCatch:
      os << "Catch:\n";
      CurrentContext()->extension()->Print(os);
      CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
      break;

    case ScopeIterator::ScopeTypeClosure:
      os << "Closure:\n";
      CurrentContext()->Print(os);
      if (CurrentContext()->has_extension()) {
440
        Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
        if (extension->IsJSContextExtensionObject()) {
          extension->Print(os);
        }
      }
      break;

    case ScopeIterator::ScopeTypeScript:
      os << "Script:\n";
      CurrentContext()
          ->global_object()
          ->native_context()
          ->script_context_table()
          ->Print(os);
      break;

    default:
      UNREACHABLE();
  }
  PrintF("\n");
}
#endif

verwaest's avatar
verwaest committed
463 464 465 466
void ScopeIterator::RetrieveScopeChain(DeclarationScope* scope) {
  DCHECK_NOT_NULL(scope);
  int source_position = frame_inspector_->GetSourcePosition();
  GetNestedScopeChain(isolate_, scope, source_position);
467 468
}

verwaest's avatar
verwaest committed
469 470 471 472
void ScopeIterator::CollectNonLocals(ParseInfo* info, DeclarationScope* scope) {
  DCHECK_NOT_NULL(scope);
  DCHECK(non_locals_.is_null());
  non_locals_ = scope->CollectNonLocals(info, StringSet::New(isolate_));
473 474 475
}


476
MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() {
477
  Handle<JSGlobalObject> global(CurrentContext()->global_object());
478 479 480 481
  Handle<ScriptContextTable> script_contexts(
      global->native_context()->script_context_table());

  Handle<JSObject> script_scope =
482
      isolate_->factory()->NewJSObjectWithNullProto();
483 484 485 486 487

  for (int context_index = 0; context_index < script_contexts->used();
       context_index++) {
    Handle<Context> context =
        ScriptContextTable::GetContext(script_contexts, context_index);
488
    Handle<ScopeInfo> scope_info(context->scope_info());
489 490 491 492 493 494 495 496 497 498
    CopyContextLocalsToScopeObject(scope_info, context, script_scope);
  }
  return script_scope;
}


MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() {
  Handle<JSFunction> function = GetFunction();

  Handle<JSObject> local_scope =
499
      isolate_->factory()->NewJSObjectWithNullProto();
500 501
  frame_inspector_->MaterializeStackLocals(local_scope, function);

502 503
  Handle<Context> frame_context =
      Handle<Context>::cast(frame_inspector_->GetContext());
504 505 506 507 508 509 510

  HandleScope scope(isolate_);
  Handle<SharedFunctionInfo> shared(function->shared());
  Handle<ScopeInfo> scope_info(shared->scope_info());

  if (!scope_info->HasContext()) return local_scope;

511
  // Fill all context locals.
512
  Handle<Context> function_context(frame_context->closure_context());
513 514 515 516
  CopyContextLocalsToScopeObject(scope_info, function_context, local_scope);

  // Finally copy any properties from the function context extension.
  // These will be variables introduced by eval.
517 518
  if (function_context->closure() == *function &&
      !function_context->IsNativeContext()) {
519
    CopyContextExtensionToScopeObject(function_context, local_scope,
520
                                      KeyCollectionMode::kIncludePrototypes);
521 522 523 524 525 526 527 528 529 530
  }

  return local_scope;
}


// Create a plain JSObject which materializes the closure content for the
// context.
Handle<JSObject> ScopeIterator::MaterializeClosure() {
  Handle<Context> context = CurrentContext();
531
  DCHECK(context->IsFunctionContext() || context->IsEvalContext());
532 533 534 535 536 537 538

  Handle<SharedFunctionInfo> shared(context->closure()->shared());
  Handle<ScopeInfo> scope_info(shared->scope_info());

  // Allocate and initialize a JSObject with all the content of this function
  // closure.
  Handle<JSObject> closure_scope =
539
      isolate_->factory()->NewJSObjectWithNullProto();
540 541 542 543 544 545

  // Fill all context locals to the context extension.
  CopyContextLocalsToScopeObject(scope_info, context, closure_scope);

  // Finally copy any properties from the function context extension. This will
  // be variables introduced by eval.
546 547
  CopyContextExtensionToScopeObject(context, closure_scope,
                                    KeyCollectionMode::kOwnOnly);
548 549 550 551 552 553 554 555 556 557

  return closure_scope;
}


// Create a plain JSObject which materializes the scope for the specified
// catch context.
Handle<JSObject> ScopeIterator::MaterializeCatchScope() {
  Handle<Context> context = CurrentContext();
  DCHECK(context->IsCatchContext());
558
  Handle<String> name(context->catch_name());
559 560 561
  Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
                               isolate_);
  Handle<JSObject> catch_scope =
562
      isolate_->factory()->NewJSObjectWithNullProto();
563 564 565 566 567 568
  JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
                                           NONE)
      .Check();
  return catch_scope;
}

569 570 571 572 573 574 575 576 577 578
// Retrieve the with-context extension object. If the extension object is
// a proxy, return an empty object.
Handle<JSObject> ScopeIterator::WithContextExtension() {
  Handle<Context> context = CurrentContext();
  DCHECK(context->IsWithContext());
  if (context->extension_receiver()->IsJSProxy()) {
    return isolate_->factory()->NewJSObjectWithNullProto();
  }
  return handle(JSObject::cast(context->extension_receiver()));
}
579 580 581

// Create a plain JSObject which materializes the block scope for the specified
// block context.
582 583
Handle<JSObject> ScopeIterator::MaterializeInnerScope() {
  Handle<JSObject> inner_scope =
584
      isolate_->factory()->NewJSObjectWithNullProto();
585 586 587

  Handle<Context> context = Handle<Context>::null();
  if (!nested_scope_chain_.is_empty()) {
588
    Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
589
    frame_inspector_->MaterializeStackLocals(inner_scope, scope_info);
590 591 592 593 594 595 596
    if (scope_info->HasContext()) context = CurrentContext();
  } else {
    context = CurrentContext();
  }

  if (!context.is_null()) {
    // Fill all context locals.
597
    CopyContextLocalsToScopeObject(CurrentScopeInfo(), context, inner_scope);
598 599
    CopyContextExtensionToScopeObject(context, inner_scope,
                                      KeyCollectionMode::kOwnOnly);
600
  }
601
  return inner_scope;
602 603 604 605 606 607 608 609
}


// Create a plain JSObject which materializes the module scope for the specified
// module context.
MaybeHandle<JSObject> ScopeIterator::MaterializeModuleScope() {
  Handle<Context> context = CurrentContext();
  DCHECK(context->IsModuleContext());
610
  Handle<ScopeInfo> scope_info(context->scope_info());
611
  Handle<JSObject> module_scope =
612
      isolate_->factory()->NewJSObjectWithNullProto();
613
  CopyContextLocalsToScopeObject(scope_info, context, module_scope);
614
  CopyModuleVarsToScopeObject(scope_info, context, module_scope);
615 616 617
  return module_scope;
}

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
                                      JavaScriptFrame* frame,
                                      Handle<String> parameter_name,
                                      Handle<Object> new_value) {
  // Setting stack locals of optimized frames is not supported.
  if (frame->is_optimized()) return false;
  HandleScope scope(isolate_);
  for (int i = 0; i < scope_info->ParameterCount(); ++i) {
    if (String::Equals(handle(scope_info->ParameterName(i)), parameter_name)) {
      frame->SetParameterValue(i, *new_value);
      return true;
    }
  }
  return false;
}

bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
                                          Handle<String> variable_name,
                                          Handle<Object> new_value) {
637
  if (frame_inspector_ == nullptr) return false;
638
  JavaScriptFrame* frame = GetFrame();
639 640 641 642 643 644 645 646 647 648 649
  // Setting stack locals of optimized frames is not supported.
  if (frame->is_optimized()) return false;
  HandleScope scope(isolate_);
  for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
    if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
      frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
      return true;
    }
  }
  return false;
}
650

651 652 653 654 655
bool ScopeIterator::SetContextVariableValue(Handle<ScopeInfo> scope_info,
                                            Handle<Context> context,
                                            Handle<String> variable_name,
                                            Handle<Object> new_value) {
  HandleScope scope(isolate_);
656 657 658 659 660 661
  for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
    Handle<String> next_name(scope_info->ContextLocalName(i));
    if (String::Equals(variable_name, next_name)) {
      VariableMode mode;
      InitializationFlag init_flag;
      MaybeAssignedFlag maybe_assigned_flag;
662 663
      int context_index = ScopeInfo::ContextSlotIndex(
          scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
664 665 666 667 668
      context->set(context_index, *new_value);
      return true;
    }
  }

669 670 671 672 673 674 675 676 677 678 679 680 681
  if (context->has_extension()) {
    Handle<JSObject> ext(context->extension_object());
    Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
    DCHECK(maybe.IsJust());
    if (maybe.FromJust()) {
      // We don't expect this to do anything except replacing property value.
      JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
                                               NONE)
          .Check();
      return true;
    }
  }

682 683 684 685 686 687
  return false;
}

bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
                                          Handle<Object> new_value) {
  JavaScriptFrame* frame = GetFrame();
688
  Handle<ScopeInfo> scope_info(frame->function()->shared()->scope_info());
689

690 691
  // Parameter might be shadowed in context. Don't stop here.
  bool result = SetParameterValue(scope_info, frame, variable_name, new_value);
692 693

  // Stack locals.
694
  if (SetStackVariableValue(scope_info, variable_name, new_value)) {
695
    return true;
696 697
  }

698 699 700 701
  if (scope_info->HasContext() &&
      SetContextVariableValue(scope_info, CurrentContext(), variable_name,
                              new_value)) {
    return true;
702 703
  }

704
  return result;
705 706
}

707 708
bool ScopeIterator::SetInnerScopeVariableValue(Handle<String> variable_name,
                                               Handle<Object> new_value) {
709
  Handle<ScopeInfo> scope_info = CurrentScopeInfo();
710 711
  DCHECK(scope_info->scope_type() == BLOCK_SCOPE ||
         scope_info->scope_type() == EVAL_SCOPE);
712

713
  // Setting stack locals of optimized frames is not supported.
714
  if (SetStackVariableValue(scope_info, variable_name, new_value)) {
715
    return true;
716 717
  }

718 719 720
  if (HasContext() && SetContextVariableValue(scope_info, CurrentContext(),
                                              variable_name, new_value)) {
    return true;
721
  }
722

723 724 725 726 727 728
  return false;
}

// This method copies structure of MaterializeClosure method above.
bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
                                            Handle<Object> new_value) {
729 730
  DCHECK(CurrentContext()->IsFunctionContext() ||
         CurrentContext()->IsEvalContext());
731 732
  return SetContextVariableValue(CurrentScopeInfo(), CurrentContext(),
                                 variable_name, new_value);
733 734 735 736
}

bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
                                           Handle<Object> new_value) {
737 738
  Handle<String> internalized_variable_name =
      isolate_->factory()->InternalizeString(variable_name);
739 740 741 742
  Handle<Context> context = CurrentContext();
  Handle<ScriptContextTable> script_contexts(
      context->global_object()->native_context()->script_context_table());
  ScriptContextTable::LookupResult lookup_result;
743
  if (ScriptContextTable::Lookup(script_contexts, internalized_variable_name,
744 745 746 747 748 749 750 751 752 753 754 755 756 757
                                 &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;
}

bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name,
                                          Handle<Object> new_value) {
  Handle<Context> context = CurrentContext();
  DCHECK(context->IsCatchContext());
758
  Handle<String> name(context->catch_name());
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
  if (!String::Equals(name, variable_name)) {
    return false;
  }
  context->set(Context::THROWN_OBJECT_INDEX, *new_value);
  return true;
}


void ScopeIterator::CopyContextLocalsToScopeObject(
    Handle<ScopeInfo> scope_info, Handle<Context> context,
    Handle<JSObject> scope_object) {
  Isolate* isolate = scope_info->GetIsolate();
  int local_count = scope_info->ContextLocalCount();
  if (local_count == 0) return;
  // Fill all context locals to the context extension.
  for (int i = 0; i < local_count; ++i) {
775 776
    Handle<String> name(scope_info->ContextLocalName(i));
    if (ScopeInfo::VariableIsSynthetic(*name)) continue;
777 778 779
    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.
780
    if (value->IsTheHole(isolate)) continue;
781 782
    // This should always succeed.
    // TODO(verwaest): Use AddDataProperty instead.
783
    JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE)
784
        .Check();
785 786 787 788 789 790 791 792 793 794 795 796 797
  }
}

void ScopeIterator::CopyModuleVarsToScopeObject(Handle<ScopeInfo> scope_info,
                                                Handle<Context> context,
                                                Handle<JSObject> scope_object) {
  Isolate* isolate = scope_info->GetIsolate();

  int module_variable_count =
      Smi::cast(scope_info->get(scope_info->ModuleVariableCountIndex()))
          ->value();
  for (int i = 0; i < module_variable_count; ++i) {
    Handle<String> local_name;
798
    Handle<Object> value;
799 800 801 802 803 804
    {
      String* name;
      int index;
      scope_info->ModuleVariable(i, &name, &index);
      CHECK(!ScopeInfo::VariableIsSynthetic(name));
      local_name = handle(name, isolate);
805
      value = Module::LoadVariable(handle(context->module(), isolate), index);
806 807 808 809 810 811 812 813 814
    }

    // Reflect variables under TDZ as undefined in scope object.
    if (value->IsTheHole(isolate)) continue;
    // This should always succeed.
    // TODO(verwaest): Use AddDataProperty instead.
    JSObject::SetOwnPropertyIgnoreAttributes(scope_object, local_name, value,
                                             NONE)
        .Check();
815 816 817
  }
}

818 819
void ScopeIterator::CopyContextExtensionToScopeObject(
    Handle<Context> context, Handle<JSObject> scope_object,
820
    KeyCollectionMode mode) {
821 822 823
  if (context->extension_object() == nullptr) return;
  Handle<JSObject> extension(context->extension_object());
  Handle<FixedArray> keys =
824
      KeyAccumulator::GetKeys(extension, mode, ENUMERABLE_STRINGS)
825
          .ToHandleChecked();
826 827 828 829 830

  for (int i = 0; i < keys->length(); i++) {
    // Names of variables introduced by eval are strings.
    DCHECK(keys->get(i)->IsString());
    Handle<String> key(String::cast(keys->get(i)));
831 832 833 834
    Handle<Object> value =
        Object::GetPropertyOrElement(extension, key).ToHandleChecked();
    JSObject::SetOwnPropertyIgnoreAttributes(scope_object, key, value, NONE)
        .Check();
835 836 837
  }
}

838 839
void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
                                        int position) {
840 841 842 843 844
  if (scope->is_function_scope()) {
    // Do not collect scopes of nested inner functions inside the current one.
    Handle<JSFunction> function = frame_inspector_->GetFunction();
    if (scope->end_position() < function->shared()->end_position()) return;
  }
845 846 847
  if (scope->is_hidden()) {
    // We need to add this chain element in case the scope has a context
    // associated. We need to keep the scope chain and context chain in sync.
848
    nested_scope_chain_.Add(ExtendedScopeInfo(scope->scope_info()));
849
  } else {
850 851
    nested_scope_chain_.Add(ExtendedScopeInfo(
        scope->scope_info(), scope->start_position(), scope->end_position()));
852
  }
853 854
  for (Scope* inner_scope = scope->inner_scope(); inner_scope != nullptr;
       inner_scope = inner_scope->sibling()) {
855 856
    int beg_pos = inner_scope->start_position();
    int end_pos = inner_scope->end_position();
857
    DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
858 859 860 861 862 863 864
    if (beg_pos <= position && position < end_pos) {
      GetNestedScopeChain(isolate, inner_scope, position);
      return;
    }
  }
}

865 866
}  // namespace internal
}  // namespace v8