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