Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(661)

Side by Side Diff: src/debug/debug-scopes.cc

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

Powered by Google App Engine
This is Rietveld 408576698