1// Copyright 2015 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/debug/debug-scopes.h" 6 7#include "src/ast/scopes.h" 8#include "src/compiler.h" 9#include "src/debug/debug.h" 10#include "src/frames-inl.h" 11#include "src/globals.h" 12#include "src/isolate-inl.h" 13#include "src/parsing/parser.h" 14 15namespace v8 { 16namespace internal { 17 18ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, 19 ScopeIterator::Option option) 20 : isolate_(isolate), 21 frame_inspector_(frame_inspector), 22 nested_scope_chain_(4), 23 seen_script_scope_(false), 24 failed_(false) { 25 if (!frame_inspector->GetContext()->IsContext() || 26 !frame_inspector->GetFunction()->IsJSFunction()) { 27 // Optimized frame, context or function cannot be materialized. Give up. 28 return; 29 } 30 31 context_ = Handle<Context>::cast(frame_inspector->GetContext()); 32 33 // Catch the case when the debugger stops in an internal function. 34 Handle<JSFunction> function = GetFunction(); 35 Handle<SharedFunctionInfo> shared_info(function->shared()); 36 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 37 if (shared_info->script()->IsUndefined(isolate)) { 38 while (context_->closure() == *function) { 39 context_ = Handle<Context>(context_->previous(), isolate_); 40 } 41 return; 42 } 43 44 // Currently it takes too much time to find nested scopes due to script 45 // parsing. Sometimes we want to run the ScopeIterator as fast as possible 46 // (for example, while collecting async call stacks on every 47 // addEventListener call), even if we drop some nested scopes. 48 // Later we may optimize getting the nested scopes (cache the result?) 49 // and include nested scopes into the "fast" iteration case as well. 50 bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES); 51 bool collect_non_locals = (option == COLLECT_NON_LOCALS); 52 if (!ignore_nested_scopes && shared_info->HasDebugInfo()) { 53 // The source position at return is always the end of the function, 54 // which is not consistent with the current scope chain. Therefore all 55 // nested with, catch and block contexts are skipped, and we can only 56 // inspect the function scope. 57 // This can only happen if we set a break point inside right before the 58 // return, which requires a debug info to be available. 59 Handle<DebugInfo> debug_info(shared_info->GetDebugInfo()); 60 61 // Find the break point where execution has stopped. 62 BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame()); 63 64 ignore_nested_scopes = location.IsReturn(); 65 } 66 67 if (ignore_nested_scopes) { 68 if (scope_info->HasContext()) { 69 context_ = Handle<Context>(context_->declaration_context(), isolate_); 70 } else { 71 while (context_->closure() == *function) { 72 context_ = Handle<Context>(context_->previous(), isolate_); 73 } 74 } 75 if (scope_info->scope_type() == FUNCTION_SCOPE) { 76 nested_scope_chain_.Add(ExtendedScopeInfo(scope_info, 77 shared_info->start_position(), 78 shared_info->end_position())); 79 } 80 if (!collect_non_locals) return; 81 } 82 83 // Reparse the code and analyze the scopes. 84 // Check whether we are in global, eval or function code. 85 Zone zone(isolate->allocator()); 86 base::SmartPointer<ParseInfo> info; 87 if (scope_info->scope_type() != FUNCTION_SCOPE) { 88 // Global or eval code. 89 Handle<Script> script(Script::cast(shared_info->script())); 90 info.Reset(new ParseInfo(&zone, script)); 91 info->set_toplevel(); 92 if (scope_info->scope_type() == SCRIPT_SCOPE) { 93 info->set_global(); 94 } else { 95 DCHECK(scope_info->scope_type() == EVAL_SCOPE); 96 info->set_eval(); 97 info->set_context(Handle<Context>(function->context())); 98 } 99 } else { 100 // Inner function. 101 info.Reset(new ParseInfo(&zone, function)); 102 } 103 Scope* scope = NULL; 104 if (Compiler::ParseAndAnalyze(info.get())) scope = info->literal()->scope(); 105 if (!ignore_nested_scopes) RetrieveScopeChain(scope); 106 if (collect_non_locals) CollectNonLocals(scope); 107 UnwrapEvaluationContext(); 108} 109 110 111ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function) 112 : isolate_(isolate), 113 frame_inspector_(NULL), 114 context_(function->context()), 115 seen_script_scope_(false), 116 failed_(false) { 117 if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>(); 118 UnwrapEvaluationContext(); 119} 120 121void ScopeIterator::UnwrapEvaluationContext() { 122 while (true) { 123 if (context_.is_null()) return; 124 if (!context_->IsDebugEvaluateContext()) return; 125 Handle<Object> wrapped(context_->get(Context::WRAPPED_CONTEXT_INDEX), 126 isolate_); 127 if (wrapped->IsContext()) { 128 context_ = Handle<Context>::cast(wrapped); 129 } else { 130 context_ = Handle<Context>(context_->previous(), isolate_); 131 } 132 } 133} 134 135 136MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() { 137 // Calculate the size of the result. 138 Handle<FixedArray> details = 139 isolate_->factory()->NewFixedArray(kScopeDetailsSize); 140 // Fill in scope details. 141 details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type())); 142 Handle<JSObject> scope_object; 143 ASSIGN_RETURN_ON_EXCEPTION(isolate_, scope_object, ScopeObject(), JSObject); 144 details->set(kScopeDetailsObjectIndex, *scope_object); 145 Handle<JSFunction> js_function = HasContext() 146 ? handle(CurrentContext()->closure()) 147 : Handle<JSFunction>::null(); 148 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) { 149 return isolate_->factory()->NewJSArrayWithElements(details); 150 } 151 152 int start_position = 0; 153 int end_position = 0; 154 if (!nested_scope_chain_.is_empty()) { 155 js_function = GetFunction(); 156 start_position = nested_scope_chain_.last().start_position; 157 end_position = nested_scope_chain_.last().end_position; 158 } else if (!js_function.is_null()) { 159 start_position = js_function->shared()->start_position(); 160 end_position = js_function->shared()->end_position(); 161 } 162 163 if (!js_function.is_null()) { 164 Handle<String> closure_name = JSFunction::GetDebugName(js_function); 165 if (!closure_name.is_null() && closure_name->length() != 0) { 166 details->set(kScopeDetailsNameIndex, *closure_name); 167 } 168 details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position)); 169 details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position)); 170 details->set(kScopeDetailsFunctionIndex, *js_function); 171 } 172 return isolate_->factory()->NewJSArrayWithElements(details); 173} 174 175 176void ScopeIterator::Next() { 177 DCHECK(!failed_); 178 ScopeType scope_type = Type(); 179 if (scope_type == ScopeTypeGlobal) { 180 // The global scope is always the last in the chain. 181 DCHECK(context_->IsNativeContext()); 182 context_ = Handle<Context>(); 183 } else if (scope_type == ScopeTypeScript) { 184 seen_script_scope_ = true; 185 if (context_->IsScriptContext()) { 186 context_ = Handle<Context>(context_->previous(), isolate_); 187 } 188 if (!nested_scope_chain_.is_empty()) { 189 DCHECK_EQ(nested_scope_chain_.last().scope_info->scope_type(), 190 SCRIPT_SCOPE); 191 nested_scope_chain_.RemoveLast(); 192 DCHECK(nested_scope_chain_.is_empty()); 193 } 194 CHECK(context_->IsNativeContext()); 195 } else if (nested_scope_chain_.is_empty()) { 196 context_ = Handle<Context>(context_->previous(), isolate_); 197 } else { 198 do { 199 if (nested_scope_chain_.last().scope_info->HasContext()) { 200 DCHECK(context_->previous() != NULL); 201 context_ = Handle<Context>(context_->previous(), isolate_); 202 } 203 nested_scope_chain_.RemoveLast(); 204 if (nested_scope_chain_.is_empty()) break; 205 // Repeat to skip hidden scopes. 206 } while (nested_scope_chain_.last().is_hidden()); 207 } 208 UnwrapEvaluationContext(); 209} 210 211 212// Return the type of the current scope. 213ScopeIterator::ScopeType ScopeIterator::Type() { 214 DCHECK(!failed_); 215 if (!nested_scope_chain_.is_empty()) { 216 Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info; 217 switch (scope_info->scope_type()) { 218 case FUNCTION_SCOPE: 219 DCHECK(context_->IsFunctionContext() || !scope_info->HasContext()); 220 return ScopeTypeLocal; 221 case MODULE_SCOPE: 222 DCHECK(context_->IsModuleContext()); 223 return ScopeTypeModule; 224 case SCRIPT_SCOPE: 225 DCHECK(context_->IsScriptContext() || context_->IsNativeContext()); 226 return ScopeTypeScript; 227 case WITH_SCOPE: 228 DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext()); 229 return ScopeTypeWith; 230 case CATCH_SCOPE: 231 DCHECK(context_->IsCatchContext()); 232 return ScopeTypeCatch; 233 case BLOCK_SCOPE: 234 DCHECK(!scope_info->HasContext() || context_->IsBlockContext()); 235 return ScopeTypeBlock; 236 case EVAL_SCOPE: 237 DCHECK(!scope_info->HasContext() || context_->IsFunctionContext()); 238 return ScopeTypeEval; 239 } 240 UNREACHABLE(); 241 } 242 if (context_->IsNativeContext()) { 243 DCHECK(context_->global_object()->IsJSGlobalObject()); 244 // If we are at the native context and have not yet seen script scope, 245 // fake it. 246 return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript; 247 } 248 if (context_->IsFunctionContext()) { 249 return ScopeTypeClosure; 250 } 251 if (context_->IsCatchContext()) { 252 return ScopeTypeCatch; 253 } 254 if (context_->IsBlockContext()) { 255 return ScopeTypeBlock; 256 } 257 if (context_->IsModuleContext()) { 258 return ScopeTypeModule; 259 } 260 if (context_->IsScriptContext()) { 261 return ScopeTypeScript; 262 } 263 DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext()); 264 return ScopeTypeWith; 265} 266 267 268MaybeHandle<JSObject> ScopeIterator::ScopeObject() { 269 DCHECK(!failed_); 270 switch (Type()) { 271 case ScopeIterator::ScopeTypeGlobal: 272 return Handle<JSObject>(CurrentContext()->global_proxy()); 273 case ScopeIterator::ScopeTypeScript: 274 return MaterializeScriptScope(); 275 case ScopeIterator::ScopeTypeLocal: 276 // Materialize the content of the local scope into a JSObject. 277 DCHECK(nested_scope_chain_.length() == 1); 278 return MaterializeLocalScope(); 279 case ScopeIterator::ScopeTypeWith: 280 return WithContextExtension(); 281 case ScopeIterator::ScopeTypeCatch: 282 return MaterializeCatchScope(); 283 case ScopeIterator::ScopeTypeClosure: 284 // Materialize the content of the closure scope into a JSObject. 285 return MaterializeClosure(); 286 case ScopeIterator::ScopeTypeBlock: 287 case ScopeIterator::ScopeTypeEval: 288 return MaterializeInnerScope(); 289 case ScopeIterator::ScopeTypeModule: 290 return MaterializeModuleScope(); 291 } 292 UNREACHABLE(); 293 return Handle<JSObject>(); 294} 295 296 297bool ScopeIterator::HasContext() { 298 ScopeType type = Type(); 299 if (type == ScopeTypeBlock || type == ScopeTypeLocal || 300 type == ScopeTypeEval) { 301 if (!nested_scope_chain_.is_empty()) { 302 return nested_scope_chain_.last().scope_info->HasContext(); 303 } 304 } 305 return true; 306} 307 308 309bool ScopeIterator::SetVariableValue(Handle<String> variable_name, 310 Handle<Object> new_value) { 311 DCHECK(!failed_); 312 switch (Type()) { 313 case ScopeIterator::ScopeTypeGlobal: 314 break; 315 case ScopeIterator::ScopeTypeLocal: 316 return SetLocalVariableValue(variable_name, new_value); 317 case ScopeIterator::ScopeTypeWith: 318 break; 319 case ScopeIterator::ScopeTypeCatch: 320 return SetCatchVariableValue(variable_name, new_value); 321 case ScopeIterator::ScopeTypeClosure: 322 return SetClosureVariableValue(variable_name, new_value); 323 case ScopeIterator::ScopeTypeScript: 324 return SetScriptVariableValue(variable_name, new_value); 325 case ScopeIterator::ScopeTypeBlock: 326 case ScopeIterator::ScopeTypeEval: 327 return SetInnerScopeVariableValue(variable_name, new_value); 328 case ScopeIterator::ScopeTypeModule: 329 // TODO(2399): should we implement it? 330 break; 331 } 332 return false; 333} 334 335 336Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() { 337 DCHECK(!failed_); 338 if (!nested_scope_chain_.is_empty()) { 339 return nested_scope_chain_.last().scope_info; 340 } else if (context_->IsBlockContext()) { 341 return Handle<ScopeInfo>(context_->scope_info()); 342 } else if (context_->IsFunctionContext()) { 343 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); 344 } 345 return Handle<ScopeInfo>::null(); 346} 347 348 349Handle<Context> ScopeIterator::CurrentContext() { 350 DCHECK(!failed_); 351 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript || 352 nested_scope_chain_.is_empty()) { 353 return context_; 354 } else if (nested_scope_chain_.last().scope_info->HasContext()) { 355 return context_; 356 } else { 357 return Handle<Context>(); 358 } 359} 360 361Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; } 362 363#ifdef DEBUG 364// Debug print of the content of the current scope. 365void ScopeIterator::DebugPrint() { 366 OFStream os(stdout); 367 DCHECK(!failed_); 368 switch (Type()) { 369 case ScopeIterator::ScopeTypeGlobal: 370 os << "Global:\n"; 371 CurrentContext()->Print(os); 372 break; 373 374 case ScopeIterator::ScopeTypeLocal: { 375 os << "Local:\n"; 376 GetFunction()->shared()->scope_info()->Print(); 377 if (!CurrentContext().is_null()) { 378 CurrentContext()->Print(os); 379 if (CurrentContext()->has_extension()) { 380 Handle<HeapObject> extension(CurrentContext()->extension(), isolate_); 381 if (extension->IsJSContextExtensionObject()) { 382 extension->Print(os); 383 } 384 } 385 } 386 break; 387 } 388 389 case ScopeIterator::ScopeTypeWith: 390 os << "With:\n"; 391 CurrentContext()->extension()->Print(os); 392 break; 393 394 case ScopeIterator::ScopeTypeCatch: 395 os << "Catch:\n"; 396 CurrentContext()->extension()->Print(os); 397 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os); 398 break; 399 400 case ScopeIterator::ScopeTypeClosure: 401 os << "Closure:\n"; 402 CurrentContext()->Print(os); 403 if (CurrentContext()->has_extension()) { 404 Handle<HeapObject> extension(CurrentContext()->extension(), isolate_); 405 if (extension->IsJSContextExtensionObject()) { 406 extension->Print(os); 407 } 408 } 409 break; 410 411 case ScopeIterator::ScopeTypeScript: 412 os << "Script:\n"; 413 CurrentContext() 414 ->global_object() 415 ->native_context() 416 ->script_context_table() 417 ->Print(os); 418 break; 419 420 default: 421 UNREACHABLE(); 422 } 423 PrintF("\n"); 424} 425#endif 426 427 428void ScopeIterator::RetrieveScopeChain(Scope* scope) { 429 if (scope != NULL) { 430 int source_position = frame_inspector_->GetSourcePosition(); 431 GetNestedScopeChain(isolate_, scope, source_position); 432 } else { 433 // A failed reparse indicates that the preparser has diverged from the 434 // parser or that the preparse data given to the initial parse has been 435 // faulty. We fail in debug mode but in release mode we only provide the 436 // information we get from the context chain but nothing about 437 // completely stack allocated scopes or stack allocated locals. 438 // Or it could be due to stack overflow. 439 DCHECK(isolate_->has_pending_exception()); 440 failed_ = true; 441 } 442} 443 444 445void ScopeIterator::CollectNonLocals(Scope* scope) { 446 if (scope != NULL) { 447 DCHECK(non_locals_.is_null()); 448 non_locals_ = scope->CollectNonLocals(StringSet::New(isolate_)); 449 } 450} 451 452 453MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() { 454 Handle<JSGlobalObject> global(CurrentContext()->global_object()); 455 Handle<ScriptContextTable> script_contexts( 456 global->native_context()->script_context_table()); 457 458 Handle<JSObject> script_scope = 459 isolate_->factory()->NewJSObjectWithNullProto(); 460 461 for (int context_index = 0; context_index < script_contexts->used(); 462 context_index++) { 463 Handle<Context> context = 464 ScriptContextTable::GetContext(script_contexts, context_index); 465 Handle<ScopeInfo> scope_info(context->scope_info()); 466 CopyContextLocalsToScopeObject(scope_info, context, script_scope); 467 } 468 return script_scope; 469} 470 471 472MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() { 473 Handle<JSFunction> function = GetFunction(); 474 475 Handle<JSObject> local_scope = 476 isolate_->factory()->NewJSObjectWithNullProto(); 477 frame_inspector_->MaterializeStackLocals(local_scope, function); 478 479 Handle<Context> frame_context = 480 Handle<Context>::cast(frame_inspector_->GetContext()); 481 482 HandleScope scope(isolate_); 483 Handle<SharedFunctionInfo> shared(function->shared()); 484 Handle<ScopeInfo> scope_info(shared->scope_info()); 485 486 if (!scope_info->HasContext()) return local_scope; 487 488 // Fill all context locals. 489 Handle<Context> function_context(frame_context->closure_context()); 490 CopyContextLocalsToScopeObject(scope_info, function_context, local_scope); 491 492 // Finally copy any properties from the function context extension. 493 // These will be variables introduced by eval. 494 if (function_context->closure() == *function && 495 !function_context->IsNativeContext()) { 496 CopyContextExtensionToScopeObject(function_context, local_scope, 497 KeyCollectionMode::kIncludePrototypes); 498 } 499 500 return local_scope; 501} 502 503 504// Create a plain JSObject which materializes the closure content for the 505// context. 506Handle<JSObject> ScopeIterator::MaterializeClosure() { 507 Handle<Context> context = CurrentContext(); 508 DCHECK(context->IsFunctionContext()); 509 510 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 511 Handle<ScopeInfo> scope_info(shared->scope_info()); 512 513 // Allocate and initialize a JSObject with all the content of this function 514 // closure. 515 Handle<JSObject> closure_scope = 516 isolate_->factory()->NewJSObjectWithNullProto(); 517 518 // Fill all context locals to the context extension. 519 CopyContextLocalsToScopeObject(scope_info, context, closure_scope); 520 521 // Finally copy any properties from the function context extension. This will 522 // be variables introduced by eval. 523 CopyContextExtensionToScopeObject(context, closure_scope, 524 KeyCollectionMode::kOwnOnly); 525 526 return closure_scope; 527} 528 529 530// Create a plain JSObject which materializes the scope for the specified 531// catch context. 532Handle<JSObject> ScopeIterator::MaterializeCatchScope() { 533 Handle<Context> context = CurrentContext(); 534 DCHECK(context->IsCatchContext()); 535 Handle<String> name(context->catch_name()); 536 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), 537 isolate_); 538 Handle<JSObject> catch_scope = 539 isolate_->factory()->NewJSObjectWithNullProto(); 540 JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object, 541 NONE) 542 .Check(); 543 return catch_scope; 544} 545 546// Retrieve the with-context extension object. If the extension object is 547// a proxy, return an empty object. 548Handle<JSObject> ScopeIterator::WithContextExtension() { 549 Handle<Context> context = CurrentContext(); 550 DCHECK(context->IsWithContext()); 551 if (context->extension_receiver()->IsJSProxy()) { 552 return isolate_->factory()->NewJSObjectWithNullProto(); 553 } 554 return handle(JSObject::cast(context->extension_receiver())); 555} 556 557// Create a plain JSObject which materializes the block scope for the specified 558// block context. 559Handle<JSObject> ScopeIterator::MaterializeInnerScope() { 560 Handle<JSObject> inner_scope = 561 isolate_->factory()->NewJSObjectWithNullProto(); 562 563 Handle<Context> context = Handle<Context>::null(); 564 if (!nested_scope_chain_.is_empty()) { 565 Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info; 566 frame_inspector_->MaterializeStackLocals(inner_scope, scope_info); 567 if (scope_info->HasContext()) context = CurrentContext(); 568 } else { 569 context = CurrentContext(); 570 } 571 572 if (!context.is_null()) { 573 // Fill all context locals. 574 CopyContextLocalsToScopeObject(CurrentScopeInfo(), context, inner_scope); 575 CopyContextExtensionToScopeObject(context, inner_scope, 576 KeyCollectionMode::kOwnOnly); 577 } 578 return inner_scope; 579} 580 581 582// Create a plain JSObject which materializes the module scope for the specified 583// module context. 584MaybeHandle<JSObject> ScopeIterator::MaterializeModuleScope() { 585 Handle<Context> context = CurrentContext(); 586 DCHECK(context->IsModuleContext()); 587 Handle<ScopeInfo> scope_info(context->scope_info()); 588 589 // Allocate and initialize a JSObject with all the members of the debugged 590 // module. 591 Handle<JSObject> module_scope = 592 isolate_->factory()->NewJSObjectWithNullProto(); 593 594 // Fill all context locals. 595 CopyContextLocalsToScopeObject(scope_info, context, module_scope); 596 597 return module_scope; 598} 599 600bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info, 601 JavaScriptFrame* frame, 602 Handle<String> parameter_name, 603 Handle<Object> new_value) { 604 // Setting stack locals of optimized frames is not supported. 605 if (frame->is_optimized()) return false; 606 HandleScope scope(isolate_); 607 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 608 if (String::Equals(handle(scope_info->ParameterName(i)), parameter_name)) { 609 frame->SetParameterValue(i, *new_value); 610 return true; 611 } 612 } 613 return false; 614} 615 616bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info, 617 JavaScriptFrame* frame, 618 Handle<String> variable_name, 619 Handle<Object> new_value) { 620 // Setting stack locals of optimized frames is not supported. 621 if (frame->is_optimized()) return false; 622 HandleScope scope(isolate_); 623 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 624 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { 625 frame->SetExpression(scope_info->StackLocalIndex(i), *new_value); 626 return true; 627 } 628 } 629 return false; 630} 631 632bool ScopeIterator::SetContextVariableValue(Handle<ScopeInfo> scope_info, 633 Handle<Context> context, 634 Handle<String> variable_name, 635 Handle<Object> new_value) { 636 HandleScope scope(isolate_); 637 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { 638 Handle<String> next_name(scope_info->ContextLocalName(i)); 639 if (String::Equals(variable_name, next_name)) { 640 VariableMode mode; 641 InitializationFlag init_flag; 642 MaybeAssignedFlag maybe_assigned_flag; 643 int context_index = ScopeInfo::ContextSlotIndex( 644 scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag); 645 context->set(context_index, *new_value); 646 return true; 647 } 648 } 649 650 if (context->has_extension()) { 651 Handle<JSObject> ext(context->extension_object()); 652 Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name); 653 DCHECK(maybe.IsJust()); 654 if (maybe.FromJust()) { 655 // We don't expect this to do anything except replacing property value. 656 JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value, 657 NONE) 658 .Check(); 659 return true; 660 } 661 } 662 663 return false; 664} 665 666bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name, 667 Handle<Object> new_value) { 668 JavaScriptFrame* frame = GetFrame(); 669 Handle<ScopeInfo> scope_info(frame->function()->shared()->scope_info()); 670 671 // Parameter might be shadowed in context. Don't stop here. 672 bool result = SetParameterValue(scope_info, frame, variable_name, new_value); 673 674 // Stack locals. 675 if (SetStackVariableValue(scope_info, frame, variable_name, new_value)) { 676 return true; 677 } 678 679 if (scope_info->HasContext() && 680 SetContextVariableValue(scope_info, CurrentContext(), variable_name, 681 new_value)) { 682 return true; 683 } 684 685 return result; 686} 687 688bool ScopeIterator::SetInnerScopeVariableValue(Handle<String> variable_name, 689 Handle<Object> new_value) { 690 Handle<ScopeInfo> scope_info = CurrentScopeInfo(); 691 DCHECK(scope_info->scope_type() == BLOCK_SCOPE || 692 scope_info->scope_type() == EVAL_SCOPE); 693 JavaScriptFrame* frame = GetFrame(); 694 695 // Setting stack locals of optimized frames is not supported. 696 if (SetStackVariableValue(scope_info, frame, variable_name, new_value)) { 697 return true; 698 } 699 700 if (HasContext() && SetContextVariableValue(scope_info, CurrentContext(), 701 variable_name, new_value)) { 702 return true; 703 } 704 705 return false; 706} 707 708// This method copies structure of MaterializeClosure method above. 709bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name, 710 Handle<Object> new_value) { 711 DCHECK(CurrentContext()->IsFunctionContext()); 712 return SetContextVariableValue(CurrentScopeInfo(), CurrentContext(), 713 variable_name, new_value); 714} 715 716bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name, 717 Handle<Object> new_value) { 718 Handle<Context> context = CurrentContext(); 719 Handle<ScriptContextTable> script_contexts( 720 context->global_object()->native_context()->script_context_table()); 721 ScriptContextTable::LookupResult lookup_result; 722 if (ScriptContextTable::Lookup(script_contexts, variable_name, 723 &lookup_result)) { 724 Handle<Context> script_context = ScriptContextTable::GetContext( 725 script_contexts, lookup_result.context_index); 726 script_context->set(lookup_result.slot_index, *new_value); 727 return true; 728 } 729 730 return false; 731} 732 733bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name, 734 Handle<Object> new_value) { 735 Handle<Context> context = CurrentContext(); 736 DCHECK(context->IsCatchContext()); 737 Handle<String> name(context->catch_name()); 738 if (!String::Equals(name, variable_name)) { 739 return false; 740 } 741 context->set(Context::THROWN_OBJECT_INDEX, *new_value); 742 return true; 743} 744 745 746void ScopeIterator::CopyContextLocalsToScopeObject( 747 Handle<ScopeInfo> scope_info, Handle<Context> context, 748 Handle<JSObject> scope_object) { 749 Isolate* isolate = scope_info->GetIsolate(); 750 int local_count = scope_info->ContextLocalCount(); 751 if (local_count == 0) return; 752 // Fill all context locals to the context extension. 753 for (int i = 0; i < local_count; ++i) { 754 Handle<String> name(scope_info->ContextLocalName(i)); 755 if (ScopeInfo::VariableIsSynthetic(*name)) continue; 756 int context_index = Context::MIN_CONTEXT_SLOTS + i; 757 Handle<Object> value = Handle<Object>(context->get(context_index), isolate); 758 // Reflect variables under TDZ as undefined in scope object. 759 if (value->IsTheHole(isolate)) continue; 760 // This should always succeed. 761 // TODO(verwaest): Use AddDataProperty instead. 762 JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE) 763 .Check(); 764 } 765} 766 767void ScopeIterator::CopyContextExtensionToScopeObject( 768 Handle<Context> context, Handle<JSObject> scope_object, 769 KeyCollectionMode mode) { 770 if (context->extension_object() == nullptr) return; 771 Handle<JSObject> extension(context->extension_object()); 772 Handle<FixedArray> keys = 773 KeyAccumulator::GetKeys(extension, mode, ENUMERABLE_STRINGS) 774 .ToHandleChecked(); 775 776 for (int i = 0; i < keys->length(); i++) { 777 // Names of variables introduced by eval are strings. 778 DCHECK(keys->get(i)->IsString()); 779 Handle<String> key(String::cast(keys->get(i))); 780 Handle<Object> value = 781 Object::GetPropertyOrElement(extension, key).ToHandleChecked(); 782 JSObject::SetOwnPropertyIgnoreAttributes(scope_object, key, value, NONE) 783 .Check(); 784 } 785} 786 787void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope, 788 int position) { 789 if (scope->is_function_scope()) { 790 // Do not collect scopes of nested inner functions inside the current one. 791 Handle<JSFunction> function = 792 Handle<JSFunction>::cast(frame_inspector_->GetFunction()); 793 if (scope->end_position() < function->shared()->end_position()) return; 794 } 795 if (scope->is_hidden()) { 796 // We need to add this chain element in case the scope has a context 797 // associated. We need to keep the scope chain and context chain in sync. 798 nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate))); 799 } else { 800 nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate), 801 scope->start_position(), 802 scope->end_position())); 803 } 804 for (int i = 0; i < scope->inner_scopes()->length(); i++) { 805 Scope* inner_scope = scope->inner_scopes()->at(i); 806 int beg_pos = inner_scope->start_position(); 807 int end_pos = inner_scope->end_position(); 808 DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden()); 809 if (beg_pos <= position && position < end_pos) { 810 GetNestedScopeChain(isolate, inner_scope, position); 811 return; 812 } 813 } 814} 815 816} // namespace internal 817} // namespace v8 818