blob: 400b1e147daa4c841fb55f20f9199629197a7442 [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"
Ben Murdochc5610432016-08-08 18:44:38 +01008#include "src/compiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#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),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023 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
Ben Murdoch097c5b22016-05-18 11:27:45 +010031 context_ = Handle<Context>::cast(frame_inspector->GetContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032
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());
Ben Murdoch61f157c2016-09-16 13:49:30 +010037 if (shared_info->script()->IsUndefined(isolate)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 // Find the break point where execution has stopped.
Ben Murdoch097c5b22016-05-18 11:27:45 +010062 BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063
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) {
Ben Murdochda12d292016-06-02 14:46:10 +010076 nested_scope_chain_.Add(ExtendedScopeInfo(scope_info,
77 shared_info->start_position(),
78 shared_info->end_position()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 }
80 if (!collect_non_locals) return;
81 }
82
83 // Reparse the code and analyze the scopes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 // Check whether we are in global, eval or function code.
Ben Murdochda12d292016-06-02 14:46:10 +010085 Zone zone(isolate->allocator());
Ben Murdochc5610432016-08-08 18:44:38 +010086 base::SmartPointer<ParseInfo> info;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 if (scope_info->scope_type() != FUNCTION_SCOPE) {
88 // Global or eval code.
89 Handle<Script> script(Script::cast(shared_info->script()));
Ben Murdochc5610432016-08-08 18:44:38 +010090 info.Reset(new ParseInfo(&zone, script));
91 info->set_toplevel();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 if (scope_info->scope_type() == SCRIPT_SCOPE) {
Ben Murdochc5610432016-08-08 18:44:38 +010093 info->set_global();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 } else {
95 DCHECK(scope_info->scope_type() == EVAL_SCOPE);
Ben Murdochc5610432016-08-08 18:44:38 +010096 info->set_eval();
97 info->set_context(Handle<Context>(function->context()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100100 // Inner function.
101 info.Reset(new ParseInfo(&zone, function));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 }
Ben Murdochc5610432016-08-08 18:44:38 +0100103 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);
Ben Murdochda12d292016-06-02 14:46:10 +0100107 UnwrapEvaluationContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108}
109
110
111ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
112 : isolate_(isolate),
113 frame_inspector_(NULL),
114 context_(function->context()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 seen_script_scope_(false),
116 failed_(false) {
117 if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>();
Ben Murdochda12d292016-06-02 14:46:10 +0100118 UnwrapEvaluationContext();
119}
120
121void ScopeIterator::UnwrapEvaluationContext() {
122 while (true) {
123 if (context_.is_null()) return;
124 if (!context_->IsDebugEvaluateContext()) return;
Ben Murdochda12d292016-06-02 14:46:10 +0100125 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 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133}
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);
Ben Murdochda12d292016-06-02 14:46:10 +0100145 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) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 details->set(kScopeDetailsNameIndex, *closure_name);
Ben Murdochda12d292016-06-02 14:46:10 +0100167 }
168 details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position));
169 details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position));
170 details->set(kScopeDetailsFunctionIndex, *js_function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 }
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>();
Ben Murdochda12d292016-06-02 14:46:10 +0100183 } else if (scope_type == ScopeTypeScript) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 seen_script_scope_ = true;
185 if (context_->IsScriptContext()) {
186 context_ = Handle<Context>(context_->previous(), isolate_);
187 }
188 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100189 DCHECK_EQ(nested_scope_chain_.last().scope_info->scope_type(),
190 SCRIPT_SCOPE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191 nested_scope_chain_.RemoveLast();
192 DCHECK(nested_scope_chain_.is_empty());
193 }
194 CHECK(context_->IsNativeContext());
Ben Murdochda12d292016-06-02 14:46:10 +0100195 } else if (nested_scope_chain_.is_empty()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 context_ = Handle<Context>(context_->previous(), isolate_);
197 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100198 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());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 }
Ben Murdochda12d292016-06-02 14:46:10 +0100208 UnwrapEvaluationContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209}
210
211
212// Return the type of the current scope.
213ScopeIterator::ScopeType ScopeIterator::Type() {
214 DCHECK(!failed_);
215 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100216 Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 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:
Ben Murdochda12d292016-06-02 14:46:10 +0100228 DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229 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:
Ben Murdochc5610432016-08-08 18:44:38 +0100237 DCHECK(!scope_info->HasContext() || context_->IsFunctionContext());
238 return ScopeTypeEval;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 }
Ben Murdochc5610432016-08-08 18:44:38 +0100240 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241 }
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:
Ben Murdochc5610432016-08-08 18:44:38 +0100287 case ScopeIterator::ScopeTypeEval:
288 return MaterializeInnerScope();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 case ScopeIterator::ScopeTypeModule:
290 return MaterializeModuleScope();
291 }
292 UNREACHABLE();
293 return Handle<JSObject>();
294}
295
296
297bool ScopeIterator::HasContext() {
298 ScopeType type = Type();
Ben Murdochc5610432016-08-08 18:44:38 +0100299 if (type == ScopeTypeBlock || type == ScopeTypeLocal ||
300 type == ScopeTypeEval) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000301 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100302 return nested_scope_chain_.last().scope_info->HasContext();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303 }
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:
Ben Murdochc5610432016-08-08 18:44:38 +0100326 case ScopeIterator::ScopeTypeEval:
327 return SetInnerScopeVariableValue(variable_name, new_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328 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()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100339 return nested_scope_chain_.last().scope_info;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340 } 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_;
Ben Murdochda12d292016-06-02 14:46:10 +0100354 } else if (nested_scope_chain_.last().scope_info->HasContext()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355 return context_;
356 } else {
357 return Handle<Context>();
358 }
359}
360
Ben Murdochda12d292016-06-02 14:46:10 +0100361Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362
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();
Ben Murdochda12d292016-06-02 14:46:10 +0100431 GetNestedScopeChain(isolate_, scope, source_position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 } 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) {
Ben Murdochda12d292016-06-02 14:46:10 +0100447 DCHECK(non_locals_.is_null());
448 non_locals_ = scope->CollectNonLocals(StringSet::New(isolate_));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000449 }
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 =
Ben Murdochc5610432016-08-08 18:44:38 +0100459 isolate_->factory()->NewJSObjectWithNullProto();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460
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 =
Ben Murdochc5610432016-08-08 18:44:38 +0100476 isolate_->factory()->NewJSObjectWithNullProto();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 frame_inspector_->MaterializeStackLocals(local_scope, function);
478
Ben Murdoch097c5b22016-05-18 11:27:45 +0100479 Handle<Context> frame_context =
480 Handle<Context>::cast(frame_inspector_->GetContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481
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
Ben Murdochc5610432016-08-08 18:44:38 +0100488 // Fill all context locals.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100489 Handle<Context> function_context(frame_context->closure_context());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 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 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000495 !function_context->IsNativeContext()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100496 CopyContextExtensionToScopeObject(function_context, local_scope,
Ben Murdoch61f157c2016-09-16 13:49:30 +0100497 KeyCollectionMode::kIncludePrototypes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000498 }
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 =
Ben Murdochc5610432016-08-08 18:44:38 +0100516 isolate_->factory()->NewJSObjectWithNullProto();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517
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.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100523 CopyContextExtensionToScopeObject(context, closure_scope,
524 KeyCollectionMode::kOwnOnly);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525
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 =
Ben Murdochc5610432016-08-08 18:44:38 +0100539 isolate_->factory()->NewJSObjectWithNullProto();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000540 JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
541 NONE)
542 .Check();
543 return catch_scope;
544}
545
Ben Murdochda12d292016-06-02 14:46:10 +0100546// 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}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556
557// Create a plain JSObject which materializes the block scope for the specified
558// block context.
Ben Murdochc5610432016-08-08 18:44:38 +0100559Handle<JSObject> ScopeIterator::MaterializeInnerScope() {
560 Handle<JSObject> inner_scope =
561 isolate_->factory()->NewJSObjectWithNullProto();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562
563 Handle<Context> context = Handle<Context>::null();
564 if (!nested_scope_chain_.is_empty()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100565 Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
Ben Murdochc5610432016-08-08 18:44:38 +0100566 frame_inspector_->MaterializeStackLocals(inner_scope, scope_info);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 if (scope_info->HasContext()) context = CurrentContext();
568 } else {
569 context = CurrentContext();
570 }
571
572 if (!context.is_null()) {
573 // Fill all context locals.
Ben Murdochc5610432016-08-08 18:44:38 +0100574 CopyContextLocalsToScopeObject(CurrentScopeInfo(), context, inner_scope);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100575 CopyContextExtensionToScopeObject(context, inner_scope,
576 KeyCollectionMode::kOwnOnly);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 }
Ben Murdochc5610432016-08-08 18:44:38 +0100578 return inner_scope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579}
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 =
Ben Murdochc5610432016-08-08 18:44:38 +0100592 isolate_->factory()->NewJSObjectWithNullProto();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000593
594 // Fill all context locals.
595 CopyContextLocalsToScopeObject(scope_info, context, module_scope);
596
597 return module_scope;
598}
599
Ben Murdochc5610432016-08-08 18:44:38 +0100600bool 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}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615
Ben Murdochc5610432016-08-08 18:44:38 +0100616bool 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_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000637 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 if (context->has_extension()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100651 Handle<JSObject> ext(context->extension_object());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000652 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
Ben Murdochc5610432016-08-08 18:44:38 +0100666bool 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}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000733bool 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.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000753 for (int i = 0; i < local_count; ++i) {
Ben Murdochc5610432016-08-08 18:44:38 +0100754 Handle<String> name(scope_info->ContextLocalName(i));
755 if (ScopeInfo::VariableIsSynthetic(*name)) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756 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.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100759 if (value->IsTheHole(isolate)) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000760 // This should always succeed.
761 // TODO(verwaest): Use AddDataProperty instead.
Ben Murdochc5610432016-08-08 18:44:38 +0100762 JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000763 .Check();
764 }
765}
766
Ben Murdochc5610432016-08-08 18:44:38 +0100767void ScopeIterator::CopyContextExtensionToScopeObject(
768 Handle<Context> context, Handle<JSObject> scope_object,
Ben Murdoch61f157c2016-09-16 13:49:30 +0100769 KeyCollectionMode mode) {
Ben Murdochc5610432016-08-08 18:44:38 +0100770 if (context->extension_object() == nullptr) return;
771 Handle<JSObject> extension(context->extension_object());
772 Handle<FixedArray> keys =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100773 KeyAccumulator::GetKeys(extension, mode, ENUMERABLE_STRINGS)
Ben Murdochc5610432016-08-08 18:44:38 +0100774 .ToHandleChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000775
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)));
Ben Murdochc5610432016-08-08 18:44:38 +0100780 Handle<Object> value =
781 Object::GetPropertyOrElement(extension, key).ToHandleChecked();
782 JSObject::SetOwnPropertyIgnoreAttributes(scope_object, key, value, NONE)
783 .Check();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785}
786
Ben Murdochda12d292016-06-02 14:46:10 +0100787void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
788 int position) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100789 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 }
Ben Murdochc5610432016-08-08 18:44:38 +0100795 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 {
Ben Murdochda12d292016-06-02 14:46:10 +0100800 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();
Ben Murdochc5610432016-08-08 18:44:38 +0100808 DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
Ben Murdochda12d292016-06-02 14:46:10 +0100809 if (beg_pos <= position && position < end_pos) {
810 GetNestedScopeChain(isolate, inner_scope, position);
811 return;
812 }
813 }
814}
815
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816} // namespace internal
817} // namespace v8