blob: d9c615b01b4c58db22aadf5ab8d3eb004ae792c0 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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/debug/debug.h"
9#include "src/frames-inl.h"
10#include "src/globals.h"
11#include "src/isolate-inl.h"
12#include "src/parsing/parser.h"
13
14namespace v8 {
15namespace internal {
16
17ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
18 ScopeIterator::Option option)
19 : isolate_(isolate),
20 frame_inspector_(frame_inspector),
21 nested_scope_chain_(4),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022 seen_script_scope_(false),
23 failed_(false) {
24 if (!frame_inspector->GetContext()->IsContext() ||
25 !frame_inspector->GetFunction()->IsJSFunction()) {
26 // Optimized frame, context or function cannot be materialized. Give up.
27 return;
28 }
29
Ben Murdoch097c5b22016-05-18 11:27:45 +010030 context_ = Handle<Context>::cast(frame_inspector->GetContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031
32 // Catch the case when the debugger stops in an internal function.
33 Handle<JSFunction> function = GetFunction();
34 Handle<SharedFunctionInfo> shared_info(function->shared());
35 Handle<ScopeInfo> scope_info(shared_info->scope_info());
36 if (shared_info->script() == isolate->heap()->undefined_value()) {
37 while (context_->closure() == *function) {
38 context_ = Handle<Context>(context_->previous(), isolate_);
39 }
40 return;
41 }
42
43 // Currently it takes too much time to find nested scopes due to script
44 // parsing. Sometimes we want to run the ScopeIterator as fast as possible
45 // (for example, while collecting async call stacks on every
46 // addEventListener call), even if we drop some nested scopes.
47 // Later we may optimize getting the nested scopes (cache the result?)
48 // and include nested scopes into the "fast" iteration case as well.
49 bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES);
50 bool collect_non_locals = (option == COLLECT_NON_LOCALS);
51 if (!ignore_nested_scopes && shared_info->HasDebugInfo()) {
52 // The source position at return is always the end of the function,
53 // which is not consistent with the current scope chain. Therefore all
54 // nested with, catch and block contexts are skipped, and we can only
55 // inspect the function scope.
56 // This can only happen if we set a break point inside right before the
57 // return, which requires a debug info to be available.
58 Handle<DebugInfo> debug_info(shared_info->GetDebugInfo());
59
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 // Find the break point where execution has stopped.
Ben Murdoch097c5b22016-05-18 11:27:45 +010061 BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062
63 ignore_nested_scopes = location.IsReturn();
64 }
65
66 if (ignore_nested_scopes) {
67 if (scope_info->HasContext()) {
68 context_ = Handle<Context>(context_->declaration_context(), isolate_);
69 } else {
70 while (context_->closure() == *function) {
71 context_ = Handle<Context>(context_->previous(), isolate_);
72 }
73 }
74 if (scope_info->scope_type() == FUNCTION_SCOPE) {
Ben Murdochda12d292016-06-02 14:46:10 +010075 nested_scope_chain_.Add(ExtendedScopeInfo(scope_info,
76 shared_info->start_position(),
77 shared_info->end_position()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078 }
79 if (!collect_non_locals) return;
80 }
81
82 // Reparse the code and analyze the scopes.
83 Scope* scope = NULL;
84 // Check whether we are in global, eval or function code.
Ben Murdochda12d292016-06-02 14:46:10 +010085 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 if (scope_info->scope_type() != FUNCTION_SCOPE) {
87 // Global or eval code.
88 Handle<Script> script(Script::cast(shared_info->script()));
89 ParseInfo info(&zone, script);
90 if (scope_info->scope_type() == SCRIPT_SCOPE) {
91 info.set_global();
92 } else {
93 DCHECK(scope_info->scope_type() == EVAL_SCOPE);
94 info.set_eval();
95 info.set_context(Handle<Context>(function->context()));
96 }
97 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
98 scope = info.literal()->scope();
99 }
100 if (!ignore_nested_scopes) RetrieveScopeChain(scope);
101 if (collect_non_locals) CollectNonLocals(scope);
102 } else {
103 // Function code
104 ParseInfo info(&zone, function);
105 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
106 scope = info.literal()->scope();
107 }
108 if (!ignore_nested_scopes) RetrieveScopeChain(scope);
109 if (collect_non_locals) CollectNonLocals(scope);
110 }
Ben Murdochda12d292016-06-02 14:46:10 +0100111 UnwrapEvaluationContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112}
113
114
115ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
116 : isolate_(isolate),
117 frame_inspector_(NULL),
118 context_(function->context()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 seen_script_scope_(false),
120 failed_(false) {
121 if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>();
Ben Murdochda12d292016-06-02 14:46:10 +0100122 UnwrapEvaluationContext();
123}
124
125void ScopeIterator::UnwrapEvaluationContext() {
126 while (true) {
127 if (context_.is_null()) return;
128 if (!context_->IsDebugEvaluateContext()) return;
129 // An existing debug-evaluate context can only be outside the local scope.
130 DCHECK(nested_scope_chain_.is_empty());
131 Handle<Object> wrapped(context_->get(Context::WRAPPED_CONTEXT_INDEX),
132 isolate_);
133 if (wrapped->IsContext()) {
134 context_ = Handle<Context>::cast(wrapped);
135 } else {
136 context_ = Handle<Context>(context_->previous(), isolate_);
137 }
138 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139}
140
141
142MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
143 // Calculate the size of the result.
144 Handle<FixedArray> details =
145 isolate_->factory()->NewFixedArray(kScopeDetailsSize);
146 // Fill in scope details.
147 details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
148 Handle<JSObject> scope_object;
149 ASSIGN_RETURN_ON_EXCEPTION(isolate_, scope_object, ScopeObject(), JSObject);
150 details->set(kScopeDetailsObjectIndex, *scope_object);
Ben Murdochda12d292016-06-02 14:46:10 +0100151 Handle<JSFunction> js_function = HasContext()
152 ? handle(CurrentContext()->closure())
153 : Handle<JSFunction>::null();
154 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
155 return isolate_->factory()->NewJSArrayWithElements(details);
156 }
157
158 int start_position = 0;
159 int end_position = 0;
160 if (!nested_scope_chain_.is_empty()) {
161 js_function = GetFunction();
162 start_position = nested_scope_chain_.last().start_position;
163 end_position = nested_scope_chain_.last().end_position;
164 } else if (!js_function.is_null()) {
165 start_position = js_function->shared()->start_position();
166 end_position = js_function->shared()->end_position();
167 }
168
169 if (!js_function.is_null()) {
170 Handle<String> closure_name = JSFunction::GetDebugName(js_function);
171 if (!closure_name.is_null() && closure_name->length() != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 details->set(kScopeDetailsNameIndex, *closure_name);
Ben Murdochda12d292016-06-02 14:46:10 +0100173 }
174 details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position));
175 details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position));
176 details->set(kScopeDetailsFunctionIndex, *js_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177 }
178 return isolate_->factory()->NewJSArrayWithElements(details);
179}
180
181
182void ScopeIterator::Next() {
183 DCHECK(!failed_);
184 ScopeType scope_type = Type();
185 if (scope_type == ScopeTypeGlobal) {
186 // The global scope is always the last in the chain.
187 DCHECK(context_->IsNativeContext());
188 context_ = Handle<Context>();
Ben Murdochda12d292016-06-02 14:46:10 +0100189 } else if (scope_type == ScopeTypeScript) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 seen_script_scope_ = true;
191 if (context_->IsScriptContext()) {
192 context_ = Handle<Context>(context_->previous(), isolate_);
193 }
194 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100195 DCHECK_EQ(nested_scope_chain_.last().scope_info->scope_type(),
196 SCRIPT_SCOPE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 nested_scope_chain_.RemoveLast();
198 DCHECK(nested_scope_chain_.is_empty());
199 }
200 CHECK(context_->IsNativeContext());
Ben Murdochda12d292016-06-02 14:46:10 +0100201 } else if (nested_scope_chain_.is_empty()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 context_ = Handle<Context>(context_->previous(), isolate_);
203 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100204 if (nested_scope_chain_.last().scope_info->HasContext()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 DCHECK(context_->previous() != NULL);
206 context_ = Handle<Context>(context_->previous(), isolate_);
207 }
208 nested_scope_chain_.RemoveLast();
209 }
Ben Murdochda12d292016-06-02 14:46:10 +0100210 UnwrapEvaluationContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211}
212
213
214// Return the type of the current scope.
215ScopeIterator::ScopeType ScopeIterator::Type() {
216 DCHECK(!failed_);
217 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100218 Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 switch (scope_info->scope_type()) {
220 case FUNCTION_SCOPE:
221 DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
222 return ScopeTypeLocal;
223 case MODULE_SCOPE:
224 DCHECK(context_->IsModuleContext());
225 return ScopeTypeModule;
226 case SCRIPT_SCOPE:
227 DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
228 return ScopeTypeScript;
229 case WITH_SCOPE:
Ben Murdochda12d292016-06-02 14:46:10 +0100230 DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 return ScopeTypeWith;
232 case CATCH_SCOPE:
233 DCHECK(context_->IsCatchContext());
234 return ScopeTypeCatch;
235 case BLOCK_SCOPE:
236 DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
237 return ScopeTypeBlock;
238 case EVAL_SCOPE:
239 UNREACHABLE();
240 }
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 }
Ben Murdochda12d292016-06-02 14:46:10 +0100263 DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 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:
Ben Murdochda12d292016-06-02 14:46:10 +0100280 return WithContextExtension();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281 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 return MaterializeBlockScope();
288 case ScopeIterator::ScopeTypeModule:
289 return MaterializeModuleScope();
290 }
291 UNREACHABLE();
292 return Handle<JSObject>();
293}
294
295
296bool ScopeIterator::HasContext() {
297 ScopeType type = Type();
298 if (type == ScopeTypeBlock || type == ScopeTypeLocal) {
299 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100300 return nested_scope_chain_.last().scope_info->HasContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000301 }
302 }
303 return true;
304}
305
306
307bool ScopeIterator::SetVariableValue(Handle<String> variable_name,
308 Handle<Object> new_value) {
309 DCHECK(!failed_);
310 switch (Type()) {
311 case ScopeIterator::ScopeTypeGlobal:
312 break;
313 case ScopeIterator::ScopeTypeLocal:
314 return SetLocalVariableValue(variable_name, new_value);
315 case ScopeIterator::ScopeTypeWith:
316 break;
317 case ScopeIterator::ScopeTypeCatch:
318 return SetCatchVariableValue(variable_name, new_value);
319 case ScopeIterator::ScopeTypeClosure:
320 return SetClosureVariableValue(variable_name, new_value);
321 case ScopeIterator::ScopeTypeScript:
322 return SetScriptVariableValue(variable_name, new_value);
323 case ScopeIterator::ScopeTypeBlock:
324 return SetBlockVariableValue(variable_name, new_value);
325 case ScopeIterator::ScopeTypeModule:
326 // TODO(2399): should we implement it?
327 break;
328 }
329 return false;
330}
331
332
333Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() {
334 DCHECK(!failed_);
335 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100336 return nested_scope_chain_.last().scope_info;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 } else if (context_->IsBlockContext()) {
338 return Handle<ScopeInfo>(context_->scope_info());
339 } else if (context_->IsFunctionContext()) {
340 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
341 }
342 return Handle<ScopeInfo>::null();
343}
344
345
346Handle<Context> ScopeIterator::CurrentContext() {
347 DCHECK(!failed_);
348 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
349 nested_scope_chain_.is_empty()) {
350 return context_;
Ben Murdochda12d292016-06-02 14:46:10 +0100351 } else if (nested_scope_chain_.last().scope_info->HasContext()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352 return context_;
353 } else {
354 return Handle<Context>();
355 }
356}
357
Ben Murdochda12d292016-06-02 14:46:10 +0100358Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359
360#ifdef DEBUG
361// Debug print of the content of the current scope.
362void ScopeIterator::DebugPrint() {
363 OFStream os(stdout);
364 DCHECK(!failed_);
365 switch (Type()) {
366 case ScopeIterator::ScopeTypeGlobal:
367 os << "Global:\n";
368 CurrentContext()->Print(os);
369 break;
370
371 case ScopeIterator::ScopeTypeLocal: {
372 os << "Local:\n";
373 GetFunction()->shared()->scope_info()->Print();
374 if (!CurrentContext().is_null()) {
375 CurrentContext()->Print(os);
376 if (CurrentContext()->has_extension()) {
377 Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
378 if (extension->IsJSContextExtensionObject()) {
379 extension->Print(os);
380 }
381 }
382 }
383 break;
384 }
385
386 case ScopeIterator::ScopeTypeWith:
387 os << "With:\n";
388 CurrentContext()->extension()->Print(os);
389 break;
390
391 case ScopeIterator::ScopeTypeCatch:
392 os << "Catch:\n";
393 CurrentContext()->extension()->Print(os);
394 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
395 break;
396
397 case ScopeIterator::ScopeTypeClosure:
398 os << "Closure:\n";
399 CurrentContext()->Print(os);
400 if (CurrentContext()->has_extension()) {
401 Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
402 if (extension->IsJSContextExtensionObject()) {
403 extension->Print(os);
404 }
405 }
406 break;
407
408 case ScopeIterator::ScopeTypeScript:
409 os << "Script:\n";
410 CurrentContext()
411 ->global_object()
412 ->native_context()
413 ->script_context_table()
414 ->Print(os);
415 break;
416
417 default:
418 UNREACHABLE();
419 }
420 PrintF("\n");
421}
422#endif
423
424
425void ScopeIterator::RetrieveScopeChain(Scope* scope) {
426 if (scope != NULL) {
427 int source_position = frame_inspector_->GetSourcePosition();
Ben Murdochda12d292016-06-02 14:46:10 +0100428 GetNestedScopeChain(isolate_, scope, source_position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 } else {
430 // A failed reparse indicates that the preparser has diverged from the
431 // parser or that the preparse data given to the initial parse has been
432 // faulty. We fail in debug mode but in release mode we only provide the
433 // information we get from the context chain but nothing about
434 // completely stack allocated scopes or stack allocated locals.
435 // Or it could be due to stack overflow.
436 DCHECK(isolate_->has_pending_exception());
437 failed_ = true;
438 }
439}
440
441
442void ScopeIterator::CollectNonLocals(Scope* scope) {
443 if (scope != NULL) {
Ben Murdochda12d292016-06-02 14:46:10 +0100444 DCHECK(non_locals_.is_null());
445 non_locals_ = scope->CollectNonLocals(StringSet::New(isolate_));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 }
447}
448
449
450MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() {
451 Handle<JSGlobalObject> global(CurrentContext()->global_object());
452 Handle<ScriptContextTable> script_contexts(
453 global->native_context()->script_context_table());
454
455 Handle<JSObject> script_scope =
456 isolate_->factory()->NewJSObject(isolate_->object_function());
457
458 for (int context_index = 0; context_index < script_contexts->used();
459 context_index++) {
460 Handle<Context> context =
461 ScriptContextTable::GetContext(script_contexts, context_index);
462 Handle<ScopeInfo> scope_info(context->scope_info());
463 CopyContextLocalsToScopeObject(scope_info, context, script_scope);
464 }
465 return script_scope;
466}
467
468
469MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() {
470 Handle<JSFunction> function = GetFunction();
471
472 Handle<JSObject> local_scope =
473 isolate_->factory()->NewJSObject(isolate_->object_function());
474 frame_inspector_->MaterializeStackLocals(local_scope, function);
475
Ben Murdoch097c5b22016-05-18 11:27:45 +0100476 Handle<Context> frame_context =
477 Handle<Context>::cast(frame_inspector_->GetContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478
479 HandleScope scope(isolate_);
480 Handle<SharedFunctionInfo> shared(function->shared());
481 Handle<ScopeInfo> scope_info(shared->scope_info());
482
483 if (!scope_info->HasContext()) return local_scope;
484
485 // Third fill all context locals.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100486 Handle<Context> function_context(frame_context->closure_context());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 CopyContextLocalsToScopeObject(scope_info, function_context, local_scope);
488
489 // Finally copy any properties from the function context extension.
490 // These will be variables introduced by eval.
491 if (function_context->closure() == *function &&
492 function_context->has_extension() &&
493 !function_context->IsNativeContext()) {
494 bool success = CopyContextExtensionToScopeObject(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100495 handle(function_context->extension_object(), isolate_), local_scope,
496 INCLUDE_PROTOS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 if (!success) return MaybeHandle<JSObject>();
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()->NewJSObject(isolate_->object_function());
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 if (context->has_extension()) {
524 bool success = CopyContextExtensionToScopeObject(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100525 handle(context->extension_object(), isolate_), closure_scope, OWN_ONLY);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000526 DCHECK(success);
527 USE(success);
528 }
529
530 return closure_scope;
531}
532
533
534// Create a plain JSObject which materializes the scope for the specified
535// catch context.
536Handle<JSObject> ScopeIterator::MaterializeCatchScope() {
537 Handle<Context> context = CurrentContext();
538 DCHECK(context->IsCatchContext());
539 Handle<String> name(context->catch_name());
540 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
541 isolate_);
542 Handle<JSObject> catch_scope =
543 isolate_->factory()->NewJSObject(isolate_->object_function());
544 JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
545 NONE)
546 .Check();
547 return catch_scope;
548}
549
Ben Murdochda12d292016-06-02 14:46:10 +0100550// Retrieve the with-context extension object. If the extension object is
551// a proxy, return an empty object.
552Handle<JSObject> ScopeIterator::WithContextExtension() {
553 Handle<Context> context = CurrentContext();
554 DCHECK(context->IsWithContext());
555 if (context->extension_receiver()->IsJSProxy()) {
556 return isolate_->factory()->NewJSObjectWithNullProto();
557 }
558 return handle(JSObject::cast(context->extension_receiver()));
559}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560
561// Create a plain JSObject which materializes the block scope for the specified
562// block context.
563Handle<JSObject> ScopeIterator::MaterializeBlockScope() {
564 Handle<JSObject> block_scope =
565 isolate_->factory()->NewJSObject(isolate_->object_function());
566
567 Handle<Context> context = Handle<Context>::null();
568 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100569 Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000570 frame_inspector_->MaterializeStackLocals(block_scope, scope_info);
571 if (scope_info->HasContext()) context = CurrentContext();
572 } else {
573 context = CurrentContext();
574 }
575
576 if (!context.is_null()) {
577 // Fill all context locals.
578 CopyContextLocalsToScopeObject(handle(context->scope_info()),
579 context, block_scope);
580 // Fill all extension variables.
581 if (context->extension_object() != nullptr) {
582 bool success = CopyContextExtensionToScopeObject(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100583 handle(context->extension_object()), block_scope, OWN_ONLY);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 DCHECK(success);
585 USE(success);
586 }
587 }
588 return block_scope;
589}
590
591
592// Create a plain JSObject which materializes the module scope for the specified
593// module context.
594MaybeHandle<JSObject> ScopeIterator::MaterializeModuleScope() {
595 Handle<Context> context = CurrentContext();
596 DCHECK(context->IsModuleContext());
597 Handle<ScopeInfo> scope_info(context->scope_info());
598
599 // Allocate and initialize a JSObject with all the members of the debugged
600 // module.
601 Handle<JSObject> module_scope =
602 isolate_->factory()->NewJSObject(isolate_->object_function());
603
604 // Fill all context locals.
605 CopyContextLocalsToScopeObject(scope_info, context, module_scope);
606
607 return module_scope;
608}
609
610
611// Set the context local variable value.
612bool ScopeIterator::SetContextLocalValue(Handle<ScopeInfo> scope_info,
613 Handle<Context> context,
614 Handle<String> variable_name,
615 Handle<Object> new_value) {
616 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
617 Handle<String> next_name(scope_info->ContextLocalName(i));
618 if (String::Equals(variable_name, next_name)) {
619 VariableMode mode;
620 InitializationFlag init_flag;
621 MaybeAssignedFlag maybe_assigned_flag;
622 int context_index = ScopeInfo::ContextSlotIndex(
623 scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
624 context->set(context_index, *new_value);
625 return true;
626 }
627 }
628
629 return false;
630}
631
632
633bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
634 Handle<Object> new_value) {
635 JavaScriptFrame* frame = GetFrame();
636 // Optimized frames are not supported.
637 if (frame->is_optimized()) return false;
638
639 Handle<JSFunction> function(frame->function());
640 Handle<SharedFunctionInfo> shared(function->shared());
641 Handle<ScopeInfo> scope_info(shared->scope_info());
642
643 bool default_result = false;
644
645 // Parameters.
646 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
647 HandleScope scope(isolate_);
648 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
649 frame->SetParameterValue(i, *new_value);
650 // Argument might be shadowed in heap context, don't stop here.
651 default_result = true;
652 }
653 }
654
655 // Stack locals.
656 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
657 HandleScope scope(isolate_);
658 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
659 frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
660 return true;
661 }
662 }
663
664 if (scope_info->HasContext()) {
665 // Context locals.
666 Handle<Context> frame_context(Context::cast(frame->context()));
667 Handle<Context> function_context(frame_context->declaration_context());
668 if (SetContextLocalValue(scope_info, function_context, variable_name,
669 new_value)) {
670 return true;
671 }
672
673 // Function context extension. These are variables introduced by eval.
674 if (function_context->closure() == *function) {
675 if (function_context->has_extension() &&
676 !function_context->IsNativeContext()) {
677 Handle<JSObject> ext(function_context->extension_object());
678
679 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
680 DCHECK(maybe.IsJust());
681 if (maybe.FromJust()) {
682 // We don't expect this to do anything except replacing
683 // property value.
684 Runtime::SetObjectProperty(isolate_, ext, variable_name, new_value,
685 SLOPPY)
686 .Assert();
687 return true;
688 }
689 }
690 }
691 }
692
693 return default_result;
694}
695
696
697bool ScopeIterator::SetBlockVariableValue(Handle<String> variable_name,
698 Handle<Object> new_value) {
699 Handle<ScopeInfo> scope_info = CurrentScopeInfo();
700 JavaScriptFrame* frame = GetFrame();
701
702 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
703 HandleScope scope(isolate_);
704 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
705 frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
706 return true;
707 }
708 }
709
710 if (HasContext()) {
711 Handle<Context> context = CurrentContext();
712 if (SetContextLocalValue(scope_info, context, variable_name, new_value)) {
713 return true;
714 }
715
716 Handle<JSObject> ext(context->extension_object(), isolate_);
717 if (!ext.is_null()) {
718 Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
719 DCHECK(maybe.IsJust());
720 if (maybe.FromJust()) {
721 // We don't expect this to do anything except replacing property value.
722 JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
723 NONE)
724 .Check();
725 return true;
726 }
727 }
728 }
729
730 return false;
731}
732
733
734// This method copies structure of MaterializeClosure method above.
735bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
736 Handle<Object> new_value) {
737 Handle<Context> context = CurrentContext();
738 DCHECK(context->IsFunctionContext());
739
740 // Context locals to the context extension.
741 Handle<SharedFunctionInfo> shared(context->closure()->shared());
742 Handle<ScopeInfo> scope_info(shared->scope_info());
743 if (SetContextLocalValue(scope_info, context, variable_name, new_value)) {
744 return true;
745 }
746
747 // Properties from the function context extension. This will
748 // be variables introduced by eval.
749 if (context->has_extension()) {
750 Handle<JSObject> ext(JSObject::cast(context->extension_object()));
751 Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
752 DCHECK(maybe.IsJust());
753 if (maybe.FromJust()) {
754 // We don't expect this to do anything except replacing property value.
755 JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
756 NONE)
757 .Check();
758 return true;
759 }
760 }
761
762 return false;
763}
764
765
766bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
767 Handle<Object> new_value) {
768 Handle<Context> context = CurrentContext();
769 Handle<ScriptContextTable> script_contexts(
770 context->global_object()->native_context()->script_context_table());
771 ScriptContextTable::LookupResult lookup_result;
772 if (ScriptContextTable::Lookup(script_contexts, variable_name,
773 &lookup_result)) {
774 Handle<Context> script_context = ScriptContextTable::GetContext(
775 script_contexts, lookup_result.context_index);
776 script_context->set(lookup_result.slot_index, *new_value);
777 return true;
778 }
779
780 return false;
781}
782
783
784bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name,
785 Handle<Object> new_value) {
786 Handle<Context> context = CurrentContext();
787 DCHECK(context->IsCatchContext());
788 Handle<String> name(context->catch_name());
789 if (!String::Equals(name, variable_name)) {
790 return false;
791 }
792 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
793 return true;
794}
795
796
797void ScopeIterator::CopyContextLocalsToScopeObject(
798 Handle<ScopeInfo> scope_info, Handle<Context> context,
799 Handle<JSObject> scope_object) {
800 Isolate* isolate = scope_info->GetIsolate();
801 int local_count = scope_info->ContextLocalCount();
802 if (local_count == 0) return;
803 // Fill all context locals to the context extension.
804 int first_context_var = scope_info->StackLocalCount();
805 int start = scope_info->ContextLocalNameEntriesIndex();
806 for (int i = 0; i < local_count; ++i) {
807 if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
808 int context_index = Context::MIN_CONTEXT_SLOTS + i;
809 Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
810 // Reflect variables under TDZ as undefined in scope object.
811 if (value->IsTheHole()) continue;
812 // This should always succeed.
813 // TODO(verwaest): Use AddDataProperty instead.
814 JSObject::SetOwnPropertyIgnoreAttributes(
815 scope_object, handle(String::cast(scope_info->get(i + start))), value,
816 NONE)
817 .Check();
818 }
819}
820
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000821bool ScopeIterator::CopyContextExtensionToScopeObject(
822 Handle<JSObject> extension, Handle<JSObject> scope_object,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100823 KeyCollectionType type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000824 Handle<FixedArray> keys;
825 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
826 isolate_, keys, JSReceiver::GetKeys(extension, type, ENUMERABLE_STRINGS),
827 false);
828
829 for (int i = 0; i < keys->length(); i++) {
830 // Names of variables introduced by eval are strings.
831 DCHECK(keys->get(i)->IsString());
832 Handle<String> key(String::cast(keys->get(i)));
833 Handle<Object> value;
834 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
835 isolate_, value, Object::GetPropertyOrElement(extension, key), false);
836 RETURN_ON_EXCEPTION_VALUE(
837 isolate_, JSObject::SetOwnPropertyIgnoreAttributes(
838 scope_object, key, value, NONE), false);
839 }
840 return true;
841}
842
Ben Murdochda12d292016-06-02 14:46:10 +0100843void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
844 int position) {
845 if (!scope->is_eval_scope()) {
846 nested_scope_chain_.Add(ExtendedScopeInfo(scope->GetScopeInfo(isolate),
847 scope->start_position(),
848 scope->end_position()));
849 }
850 for (int i = 0; i < scope->inner_scopes()->length(); i++) {
851 Scope* inner_scope = scope->inner_scopes()->at(i);
852 int beg_pos = inner_scope->start_position();
853 int end_pos = inner_scope->end_position();
854 DCHECK(beg_pos >= 0 && end_pos >= 0);
855 if (beg_pos <= position && position < end_pos) {
856 GetNestedScopeChain(isolate, inner_scope, position);
857 return;
858 }
859 }
860}
861
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000862} // namespace internal
863} // namespace v8