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