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

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

Issue 612023002: Split even more runtime functions into separate files. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « src/runtime/runtime-date.cc ('k') | src/runtime/runtime-generator.cc » ('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 2014 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/v8.h"
6
7 #include "src/accessors.h"
8 #include "src/arguments.h"
9 #include "src/debug.h"
10 #include "src/deoptimizer.h"
11 #include "src/isolate-inl.h"
12 #include "src/parser.h"
13 #include "src/runtime/runtime.h"
14 #include "src/runtime/runtime-utils.h"
15
16 namespace v8 {
17 namespace internal {
18
19 RUNTIME_FUNCTION(Runtime_DebugBreak) {
20 SealHandleScope shs(isolate);
21 DCHECK(args.length() == 0);
22 isolate->debug()->HandleDebugBreak();
23 return isolate->heap()->undefined_value();
24 }
25
26
27 // Helper functions for wrapping and unwrapping stack frame ids.
28 static Smi* WrapFrameId(StackFrame::Id id) {
29 DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
30 return Smi::FromInt(id >> 2);
31 }
32
33
34 static StackFrame::Id UnwrapFrameId(int wrapped) {
35 return static_cast<StackFrame::Id>(wrapped << 2);
36 }
37
38
39 // Adds a JavaScript function as a debug event listener.
40 // args[0]: debug event listener function to set or null or undefined for
41 // clearing the event listener function
42 // args[1]: object supplied during callback
43 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
44 SealHandleScope shs(isolate);
45 DCHECK(args.length() == 2);
46 RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() ||
47 args[0]->IsNull());
48 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
49 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
50 isolate->debug()->SetEventListener(callback, data);
51
52 return isolate->heap()->undefined_value();
53 }
54
55
56 RUNTIME_FUNCTION(Runtime_Break) {
57 SealHandleScope shs(isolate);
58 DCHECK(args.length() == 0);
59 isolate->stack_guard()->RequestDebugBreak();
60 return isolate->heap()->undefined_value();
61 }
62
63
64 static Handle<Object> DebugGetProperty(LookupIterator* it,
65 bool* has_caught = NULL) {
66 for (; it->IsFound(); it->Next()) {
67 switch (it->state()) {
68 case LookupIterator::NOT_FOUND:
69 case LookupIterator::TRANSITION:
70 UNREACHABLE();
71 case LookupIterator::ACCESS_CHECK:
72 // Ignore access checks.
73 break;
74 case LookupIterator::INTERCEPTOR:
75 case LookupIterator::JSPROXY:
76 return it->isolate()->factory()->undefined_value();
77 case LookupIterator::ACCESSOR: {
78 Handle<Object> accessors = it->GetAccessors();
79 if (!accessors->IsAccessorInfo()) {
80 return it->isolate()->factory()->undefined_value();
81 }
82 MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithAccessor(
83 it->GetReceiver(), it->name(), it->GetHolder<JSObject>(),
84 accessors);
85 Handle<Object> result;
86 if (!maybe_result.ToHandle(&result)) {
87 result = handle(it->isolate()->pending_exception(), it->isolate());
88 it->isolate()->clear_pending_exception();
89 if (has_caught != NULL) *has_caught = true;
90 }
91 return result;
92 }
93
94 case LookupIterator::DATA:
95 return it->GetDataValue();
96 }
97 }
98
99 return it->isolate()->factory()->undefined_value();
100 }
101
102
103 // Get debugger related details for an object property, in the following format:
104 // 0: Property value
105 // 1: Property details
106 // 2: Property value is exception
107 // 3: Getter function if defined
108 // 4: Setter function if defined
109 // Items 2-4 are only filled if the property has either a getter or a setter.
110 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
111 HandleScope scope(isolate);
112
113 DCHECK(args.length() == 2);
114
115 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
116 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
117
118 // Make sure to set the current context to the context before the debugger was
119 // entered (if the debugger is entered). The reason for switching context here
120 // is that for some property lookups (accessors and interceptors) callbacks
121 // into the embedding application can occour, and the embedding application
122 // could have the assumption that its own native context is the current
123 // context and not some internal debugger context.
124 SaveContext save(isolate);
125 if (isolate->debug()->in_debug_scope()) {
126 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
127 }
128
129 // Check if the name is trivially convertible to an index and get the element
130 // if so.
131 uint32_t index;
132 if (name->AsArrayIndex(&index)) {
133 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
134 Handle<Object> element_or_char;
135 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
136 isolate, element_or_char,
137 Runtime::GetElementOrCharAt(isolate, obj, index));
138 details->set(0, *element_or_char);
139 details->set(1,
140 PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
141 return *isolate->factory()->NewJSArrayWithElements(details);
142 }
143
144 LookupIterator it(obj, name, LookupIterator::HIDDEN);
145 bool has_caught = false;
146 Handle<Object> value = DebugGetProperty(&it, &has_caught);
147 if (!it.IsFound()) return isolate->heap()->undefined_value();
148
149 Handle<Object> maybe_pair;
150 if (it.state() == LookupIterator::ACCESSOR) {
151 maybe_pair = it.GetAccessors();
152 }
153
154 // If the callback object is a fixed array then it contains JavaScript
155 // getter and/or setter.
156 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair();
157 Handle<FixedArray> details =
158 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3);
159 details->set(0, *value);
160 // TODO(verwaest): Get rid of this random way of handling interceptors.
161 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR
162 ? PropertyDetails(NONE, NORMAL, 0)
163 : it.property_details();
164 details->set(1, d.AsSmi());
165 details->set(
166 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
167 if (has_js_accessors) {
168 AccessorPair* accessors = AccessorPair::cast(*maybe_pair);
169 details->set(3, isolate->heap()->ToBoolean(has_caught));
170 details->set(4, accessors->GetComponent(ACCESSOR_GETTER));
171 details->set(5, accessors->GetComponent(ACCESSOR_SETTER));
172 }
173
174 return *isolate->factory()->NewJSArrayWithElements(details);
175 }
176
177
178 RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
179 HandleScope scope(isolate);
180
181 DCHECK(args.length() == 2);
182
183 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
184 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
185
186 LookupIterator it(obj, name);
187 return *DebugGetProperty(&it);
188 }
189
190
191 // Return the property type calculated from the property details.
192 // args[0]: smi with property details.
193 RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
194 SealHandleScope shs(isolate);
195 DCHECK(args.length() == 1);
196 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
197 return Smi::FromInt(static_cast<int>(details.type()));
198 }
199
200
201 // Return the property attribute calculated from the property details.
202 // args[0]: smi with property details.
203 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
204 SealHandleScope shs(isolate);
205 DCHECK(args.length() == 1);
206 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
207 return Smi::FromInt(static_cast<int>(details.attributes()));
208 }
209
210
211 // Return the property insertion index calculated from the property details.
212 // args[0]: smi with property details.
213 RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
214 SealHandleScope shs(isolate);
215 DCHECK(args.length() == 1);
216 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
217 // TODO(verwaest): Depends on the type of details.
218 return Smi::FromInt(details.dictionary_index());
219 }
220
221
222 // Return property value from named interceptor.
223 // args[0]: object
224 // args[1]: property name
225 RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
226 HandleScope scope(isolate);
227 DCHECK(args.length() == 2);
228 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
229 RUNTIME_ASSERT(obj->HasNamedInterceptor());
230 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
231
232 Handle<Object> result;
233 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
234 JSObject::GetProperty(obj, name));
235 return *result;
236 }
237
238
239 // Return element value from indexed interceptor.
240 // args[0]: object
241 // args[1]: index
242 RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
243 HandleScope scope(isolate);
244 DCHECK(args.length() == 2);
245 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
246 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
247 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
248 Handle<Object> result;
249 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
250 isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index));
251 return *result;
252 }
253
254
255 RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
256 SealHandleScope shs(isolate);
257 DCHECK(args.length() == 1);
258 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
259 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
260 return isolate->heap()->true_value();
261 }
262
263
264 RUNTIME_FUNCTION(Runtime_GetFrameCount) {
265 HandleScope scope(isolate);
266 DCHECK(args.length() == 1);
267 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
268 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
269
270 // Count all frames which are relevant to debugging stack trace.
271 int n = 0;
272 StackFrame::Id id = isolate->debug()->break_frame_id();
273 if (id == StackFrame::NO_ID) {
274 // If there is no JavaScript stack frame count is 0.
275 return Smi::FromInt(0);
276 }
277
278 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
279 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
280 it.frame()->Summarize(&frames);
281 for (int i = frames.length() - 1; i >= 0; i--) {
282 // Omit functions from native scripts.
283 if (!frames[i].function()->IsFromNativeScript()) n++;
284 }
285 }
286 return Smi::FromInt(n);
287 }
288
289
290 class FrameInspector {
291 public:
292 FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index,
293 Isolate* isolate)
294 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
295 // Calculate the deoptimized frame.
296 if (frame->is_optimized()) {
297 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
298 frame, inlined_jsframe_index, isolate);
299 }
300 has_adapted_arguments_ = frame_->has_adapted_arguments();
301 is_bottommost_ = inlined_jsframe_index == 0;
302 is_optimized_ = frame_->is_optimized();
303 }
304
305 ~FrameInspector() {
306 // Get rid of the calculated deoptimized frame if any.
307 if (deoptimized_frame_ != NULL) {
308 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
309 }
310 }
311
312 int GetParametersCount() {
313 return is_optimized_ ? deoptimized_frame_->parameters_count()
314 : frame_->ComputeParametersCount();
315 }
316 int expression_count() { return deoptimized_frame_->expression_count(); }
317 Object* GetFunction() {
318 return is_optimized_ ? deoptimized_frame_->GetFunction()
319 : frame_->function();
320 }
321 Object* GetParameter(int index) {
322 return is_optimized_ ? deoptimized_frame_->GetParameter(index)
323 : frame_->GetParameter(index);
324 }
325 Object* GetExpression(int index) {
326 return is_optimized_ ? deoptimized_frame_->GetExpression(index)
327 : frame_->GetExpression(index);
328 }
329 int GetSourcePosition() {
330 return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
331 : frame_->LookupCode()->SourcePosition(frame_->pc());
332 }
333 bool IsConstructor() {
334 return is_optimized_ && !is_bottommost_
335 ? deoptimized_frame_->HasConstructStub()
336 : frame_->IsConstructor();
337 }
338 Object* GetContext() {
339 return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
340 }
341
342 // To inspect all the provided arguments the frame might need to be
343 // replaced with the arguments frame.
344 void SetArgumentsFrame(JavaScriptFrame* frame) {
345 DCHECK(has_adapted_arguments_);
346 frame_ = frame;
347 is_optimized_ = frame_->is_optimized();
348 DCHECK(!is_optimized_);
349 }
350
351 private:
352 JavaScriptFrame* frame_;
353 DeoptimizedFrameInfo* deoptimized_frame_;
354 Isolate* isolate_;
355 bool is_optimized_;
356 bool is_bottommost_;
357 bool has_adapted_arguments_;
358
359 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
360 };
361
362
363 static const int kFrameDetailsFrameIdIndex = 0;
364 static const int kFrameDetailsReceiverIndex = 1;
365 static const int kFrameDetailsFunctionIndex = 2;
366 static const int kFrameDetailsArgumentCountIndex = 3;
367 static const int kFrameDetailsLocalCountIndex = 4;
368 static const int kFrameDetailsSourcePositionIndex = 5;
369 static const int kFrameDetailsConstructCallIndex = 6;
370 static const int kFrameDetailsAtReturnIndex = 7;
371 static const int kFrameDetailsFlagsIndex = 8;
372 static const int kFrameDetailsFirstDynamicIndex = 9;
373
374
375 static SaveContext* FindSavedContextForFrame(Isolate* isolate,
376 JavaScriptFrame* frame) {
377 SaveContext* save = isolate->save_context();
378 while (save != NULL && !save->IsBelowFrame(frame)) {
379 save = save->prev();
380 }
381 DCHECK(save != NULL);
382 return save;
383 }
384
385
386 // Advances the iterator to the frame that matches the index and returns the
387 // inlined frame index, or -1 if not found. Skips native JS functions.
388 int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) {
389 int count = -1;
390 for (; !it->done(); it->Advance()) {
391 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
392 it->frame()->Summarize(&frames);
393 for (int i = frames.length() - 1; i >= 0; i--) {
394 // Omit functions from native scripts.
395 if (frames[i].function()->IsFromNativeScript()) continue;
396 if (++count == index) return i;
397 }
398 }
399 return -1;
400 }
401
402
403 // Return an array with frame details
404 // args[0]: number: break id
405 // args[1]: number: frame index
406 //
407 // The array returned contains the following information:
408 // 0: Frame id
409 // 1: Receiver
410 // 2: Function
411 // 3: Argument count
412 // 4: Local count
413 // 5: Source position
414 // 6: Constructor call
415 // 7: Is at return
416 // 8: Flags
417 // Arguments name, value
418 // Locals name, value
419 // Return value if any
420 RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
421 HandleScope scope(isolate);
422 DCHECK(args.length() == 2);
423 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
424 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
425
426 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
427 Heap* heap = isolate->heap();
428
429 // Find the relevant frame with the requested index.
430 StackFrame::Id id = isolate->debug()->break_frame_id();
431 if (id == StackFrame::NO_ID) {
432 // If there are no JavaScript stack frames return undefined.
433 return heap->undefined_value();
434 }
435
436 JavaScriptFrameIterator it(isolate, id);
437 // Inlined frame index in optimized frame, starting from outer function.
438 int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index);
439 if (inlined_jsframe_index == -1) return heap->undefined_value();
440
441 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
442 bool is_optimized = it.frame()->is_optimized();
443
444 // Traverse the saved contexts chain to find the active context for the
445 // selected frame.
446 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
447
448 // Get the frame id.
449 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
450
451 // Find source position in unoptimized code.
452 int position = frame_inspector.GetSourcePosition();
453
454 // Check for constructor frame.
455 bool constructor = frame_inspector.IsConstructor();
456
457 // Get scope info and read from it for local variable information.
458 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
459 Handle<SharedFunctionInfo> shared(function->shared());
460 Handle<ScopeInfo> scope_info(shared->scope_info());
461 DCHECK(*scope_info != ScopeInfo::Empty(isolate));
462
463 // Get the locals names and values into a temporary array.
464 int local_count = scope_info->LocalCount();
465 for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
466 // Hide compiler-introduced temporary variables, whether on the stack or on
467 // the context.
468 if (scope_info->LocalIsSynthetic(slot)) local_count--;
469 }
470
471 Handle<FixedArray> locals =
472 isolate->factory()->NewFixedArray(local_count * 2);
473
474 // Fill in the values of the locals.
475 int local = 0;
476 int i = 0;
477 for (; i < scope_info->StackLocalCount(); ++i) {
478 // Use the value from the stack.
479 if (scope_info->LocalIsSynthetic(i)) continue;
480 locals->set(local * 2, scope_info->LocalName(i));
481 locals->set(local * 2 + 1, frame_inspector.GetExpression(i));
482 local++;
483 }
484 if (local < local_count) {
485 // Get the context containing declarations.
486 Handle<Context> context(
487 Context::cast(frame_inspector.GetContext())->declaration_context());
488 for (; i < scope_info->LocalCount(); ++i) {
489 if (scope_info->LocalIsSynthetic(i)) continue;
490 Handle<String> name(scope_info->LocalName(i));
491 VariableMode mode;
492 InitializationFlag init_flag;
493 MaybeAssignedFlag maybe_assigned_flag;
494 locals->set(local * 2, *name);
495 int context_slot_index = ScopeInfo::ContextSlotIndex(
496 scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
497 Object* value = context->get(context_slot_index);
498 locals->set(local * 2 + 1, value);
499 local++;
500 }
501 }
502
503 // Check whether this frame is positioned at return. If not top
504 // frame or if the frame is optimized it cannot be at a return.
505 bool at_return = false;
506 if (!is_optimized && index == 0) {
507 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
508 }
509
510 // If positioned just before return find the value to be returned and add it
511 // to the frame information.
512 Handle<Object> return_value = isolate->factory()->undefined_value();
513 if (at_return) {
514 StackFrameIterator it2(isolate);
515 Address internal_frame_sp = NULL;
516 while (!it2.done()) {
517 if (it2.frame()->is_internal()) {
518 internal_frame_sp = it2.frame()->sp();
519 } else {
520 if (it2.frame()->is_java_script()) {
521 if (it2.frame()->id() == it.frame()->id()) {
522 // The internal frame just before the JavaScript frame contains the
523 // value to return on top. A debug break at return will create an
524 // internal frame to store the return value (eax/rax/r0) before
525 // entering the debug break exit frame.
526 if (internal_frame_sp != NULL) {
527 return_value =
528 Handle<Object>(Memory::Object_at(internal_frame_sp), isolate);
529 break;
530 }
531 }
532 }
533
534 // Indicate that the previous frame was not an internal frame.
535 internal_frame_sp = NULL;
536 }
537 it2.Advance();
538 }
539 }
540
541 // Now advance to the arguments adapter frame (if any). It contains all
542 // the provided parameters whereas the function frame always have the number
543 // of arguments matching the functions parameters. The rest of the
544 // information (except for what is collected above) is the same.
545 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
546 it.AdvanceToArgumentsFrame();
547 frame_inspector.SetArgumentsFrame(it.frame());
548 }
549
550 // Find the number of arguments to fill. At least fill the number of
551 // parameters for the function and fill more if more parameters are provided.
552 int argument_count = scope_info->ParameterCount();
553 if (argument_count < frame_inspector.GetParametersCount()) {
554 argument_count = frame_inspector.GetParametersCount();
555 }
556
557 // Calculate the size of the result.
558 int details_size = kFrameDetailsFirstDynamicIndex +
559 2 * (argument_count + local_count) + (at_return ? 1 : 0);
560 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
561
562 // Add the frame id.
563 details->set(kFrameDetailsFrameIdIndex, *frame_id);
564
565 // Add the function (same as in function frame).
566 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
567
568 // Add the arguments count.
569 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
570
571 // Add the locals count
572 details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count));
573
574 // Add the source position.
575 if (position != RelocInfo::kNoPosition) {
576 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
577 } else {
578 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
579 }
580
581 // Add the constructor information.
582 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
583
584 // Add the at return information.
585 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
586
587 // Add flags to indicate information on whether this frame is
588 // bit 0: invoked in the debugger context.
589 // bit 1: optimized frame.
590 // bit 2: inlined in optimized frame
591 int flags = 0;
592 if (*save->context() == *isolate->debug()->debug_context()) {
593 flags |= 1 << 0;
594 }
595 if (is_optimized) {
596 flags |= 1 << 1;
597 flags |= inlined_jsframe_index << 2;
598 }
599 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
600
601 // Fill the dynamic part.
602 int details_index = kFrameDetailsFirstDynamicIndex;
603
604 // Add arguments name and value.
605 for (int i = 0; i < argument_count; i++) {
606 // Name of the argument.
607 if (i < scope_info->ParameterCount()) {
608 details->set(details_index++, scope_info->ParameterName(i));
609 } else {
610 details->set(details_index++, heap->undefined_value());
611 }
612
613 // Parameter value.
614 if (i < frame_inspector.GetParametersCount()) {
615 // Get the value from the stack.
616 details->set(details_index++, frame_inspector.GetParameter(i));
617 } else {
618 details->set(details_index++, heap->undefined_value());
619 }
620 }
621
622 // Add locals name and value from the temporary copy from the function frame.
623 for (int i = 0; i < local_count * 2; i++) {
624 details->set(details_index++, locals->get(i));
625 }
626
627 // Add the value being returned.
628 if (at_return) {
629 details->set(details_index++, *return_value);
630 }
631
632 // Add the receiver (same as in function frame).
633 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
634 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
635 Handle<Object> receiver(it.frame()->receiver(), isolate);
636 if (!receiver->IsJSObject() && shared->strict_mode() == SLOPPY &&
637 !function->IsBuiltin()) {
638 // If the receiver is not a JSObject and the function is not a
639 // builtin or strict-mode we have hit an optimization where a
640 // value object is not converted into a wrapped JS objects. To
641 // hide this optimization from the debugger, we wrap the receiver
642 // by creating correct wrapper object based on the calling frame's
643 // native context.
644 it.Advance();
645 if (receiver->IsUndefined()) {
646 receiver = handle(function->global_proxy());
647 } else {
648 Context* context = Context::cast(it.frame()->context());
649 Handle<Context> native_context(Context::cast(context->native_context()));
650 if (!Object::ToObject(isolate, receiver, native_context)
651 .ToHandle(&receiver)) {
652 // This only happens if the receiver is forcibly set in %_CallFunction.
653 return heap->undefined_value();
654 }
655 }
656 }
657 details->set(kFrameDetailsReceiverIndex, *receiver);
658
659 DCHECK_EQ(details_size, details_index);
660 return *isolate->factory()->NewJSArrayWithElements(details);
661 }
662
663
664 static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
665 Handle<String> parameter_name) {
666 VariableMode mode;
667 InitializationFlag init_flag;
668 MaybeAssignedFlag maybe_assigned_flag;
669 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
670 &maybe_assigned_flag) != -1;
671 }
672
673
674 // Create a plain JSObject which materializes the local scope for the specified
675 // frame.
676 MUST_USE_RESULT
677 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector(
678 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
679 FrameInspector* frame_inspector) {
680 Handle<SharedFunctionInfo> shared(function->shared());
681 Handle<ScopeInfo> scope_info(shared->scope_info());
682
683 // First fill all parameters.
684 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
685 // Do not materialize the parameter if it is shadowed by a context local.
686 Handle<String> name(scope_info->ParameterName(i));
687 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
688
689 HandleScope scope(isolate);
690 Handle<Object> value(i < frame_inspector->GetParametersCount()
691 ? frame_inspector->GetParameter(i)
692 : isolate->heap()->undefined_value(),
693 isolate);
694 DCHECK(!value->IsTheHole());
695
696 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
697 isolate, target, name, value, SLOPPY),
698 JSObject);
699 }
700
701 // Second fill all stack locals.
702 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
703 if (scope_info->LocalIsSynthetic(i)) continue;
704 Handle<String> name(scope_info->StackLocalName(i));
705 Handle<Object> value(frame_inspector->GetExpression(i), isolate);
706 if (value->IsTheHole()) continue;
707
708 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
709 isolate, target, name, value, SLOPPY),
710 JSObject);
711 }
712
713 return target;
714 }
715
716
717 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
718 Handle<JSObject> target,
719 Handle<JSFunction> function,
720 JavaScriptFrame* frame,
721 int inlined_jsframe_index) {
722 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
723 // Optimized frames are not supported.
724 // TODO(yangguo): make sure all code deoptimized when debugger is active
725 // and assert that this cannot happen.
726 return;
727 }
728
729 Handle<SharedFunctionInfo> shared(function->shared());
730 Handle<ScopeInfo> scope_info(shared->scope_info());
731
732 // Parameters.
733 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
734 // Shadowed parameters were not materialized.
735 Handle<String> name(scope_info->ParameterName(i));
736 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
737
738 DCHECK(!frame->GetParameter(i)->IsTheHole());
739 HandleScope scope(isolate);
740 Handle<Object> value =
741 Object::GetPropertyOrElement(target, name).ToHandleChecked();
742 frame->SetParameterValue(i, *value);
743 }
744
745 // Stack locals.
746 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
747 if (scope_info->LocalIsSynthetic(i)) continue;
748 if (frame->GetExpression(i)->IsTheHole()) continue;
749 HandleScope scope(isolate);
750 Handle<Object> value = Object::GetPropertyOrElement(
751 target, handle(scope_info->StackLocalName(i),
752 isolate)).ToHandleChecked();
753 frame->SetExpression(i, *value);
754 }
755 }
756
757
758 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
759 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
760 JavaScriptFrame* frame) {
761 HandleScope scope(isolate);
762 Handle<SharedFunctionInfo> shared(function->shared());
763 Handle<ScopeInfo> scope_info(shared->scope_info());
764
765 if (!scope_info->HasContext()) return target;
766
767 // Third fill all context locals.
768 Handle<Context> frame_context(Context::cast(frame->context()));
769 Handle<Context> function_context(frame_context->declaration_context());
770 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context,
771 target)) {
772 return MaybeHandle<JSObject>();
773 }
774
775 // Finally copy any properties from the function context extension.
776 // These will be variables introduced by eval.
777 if (function_context->closure() == *function) {
778 if (function_context->has_extension() &&
779 !function_context->IsNativeContext()) {
780 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
781 Handle<FixedArray> keys;
782 ASSIGN_RETURN_ON_EXCEPTION(
783 isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
784 JSObject);
785
786 for (int i = 0; i < keys->length(); i++) {
787 // Names of variables introduced by eval are strings.
788 DCHECK(keys->get(i)->IsString());
789 Handle<String> key(String::cast(keys->get(i)));
790 Handle<Object> value;
791 ASSIGN_RETURN_ON_EXCEPTION(
792 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
793 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
794 isolate, target, key, value, SLOPPY),
795 JSObject);
796 }
797 }
798 }
799
800 return target;
801 }
802
803
804 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
805 Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) {
806 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
807 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
808
809 Handle<JSObject> local_scope =
810 isolate->factory()->NewJSObject(isolate->object_function());
811 ASSIGN_RETURN_ON_EXCEPTION(
812 isolate, local_scope,
813 MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function,
814 &frame_inspector),
815 JSObject);
816
817 return MaterializeLocalContext(isolate, local_scope, function, frame);
818 }
819
820
821 // Set the context local variable value.
822 static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info,
823 Handle<Context> context,
824 Handle<String> variable_name,
825 Handle<Object> new_value) {
826 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
827 Handle<String> next_name(scope_info->ContextLocalName(i));
828 if (String::Equals(variable_name, next_name)) {
829 VariableMode mode;
830 InitializationFlag init_flag;
831 MaybeAssignedFlag maybe_assigned_flag;
832 int context_index = ScopeInfo::ContextSlotIndex(
833 scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
834 context->set(context_index, *new_value);
835 return true;
836 }
837 }
838
839 return false;
840 }
841
842
843 static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
844 int inlined_jsframe_index,
845 Handle<String> variable_name,
846 Handle<Object> new_value) {
847 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
848 // Optimized frames are not supported.
849 return false;
850 }
851
852 Handle<JSFunction> function(frame->function());
853 Handle<SharedFunctionInfo> shared(function->shared());
854 Handle<ScopeInfo> scope_info(shared->scope_info());
855
856 bool default_result = false;
857
858 // Parameters.
859 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
860 HandleScope scope(isolate);
861 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
862 frame->SetParameterValue(i, *new_value);
863 // Argument might be shadowed in heap context, don't stop here.
864 default_result = true;
865 }
866 }
867
868 // Stack locals.
869 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
870 HandleScope scope(isolate);
871 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
872 frame->SetExpression(i, *new_value);
873 return true;
874 }
875 }
876
877 if (scope_info->HasContext()) {
878 // Context locals.
879 Handle<Context> frame_context(Context::cast(frame->context()));
880 Handle<Context> function_context(frame_context->declaration_context());
881 if (SetContextLocalValue(isolate, scope_info, function_context,
882 variable_name, new_value)) {
883 return true;
884 }
885
886 // Function context extension. These are variables introduced by eval.
887 if (function_context->closure() == *function) {
888 if (function_context->has_extension() &&
889 !function_context->IsNativeContext()) {
890 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
891
892 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
893 DCHECK(maybe.has_value);
894 if (maybe.value) {
895 // We don't expect this to do anything except replacing
896 // property value.
897 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
898 SLOPPY).Assert();
899 return true;
900 }
901 }
902 }
903 }
904
905 return default_result;
906 }
907
908
909 // Create a plain JSObject which materializes the closure content for the
910 // context.
911 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure(
912 Isolate* isolate, Handle<Context> context) {
913 DCHECK(context->IsFunctionContext());
914
915 Handle<SharedFunctionInfo> shared(context->closure()->shared());
916 Handle<ScopeInfo> scope_info(shared->scope_info());
917
918 // Allocate and initialize a JSObject with all the content of this function
919 // closure.
920 Handle<JSObject> closure_scope =
921 isolate->factory()->NewJSObject(isolate->object_function());
922
923 // Fill all context locals to the context extension.
924 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
925 closure_scope)) {
926 return MaybeHandle<JSObject>();
927 }
928
929 // Finally copy any properties from the function context extension. This will
930 // be variables introduced by eval.
931 if (context->has_extension()) {
932 Handle<JSObject> ext(JSObject::cast(context->extension()));
933 Handle<FixedArray> keys;
934 ASSIGN_RETURN_ON_EXCEPTION(
935 isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
936 JSObject);
937
938 for (int i = 0; i < keys->length(); i++) {
939 HandleScope scope(isolate);
940 // Names of variables introduced by eval are strings.
941 DCHECK(keys->get(i)->IsString());
942 Handle<String> key(String::cast(keys->get(i)));
943 Handle<Object> value;
944 ASSIGN_RETURN_ON_EXCEPTION(
945 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
946 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
947 closure_scope, key, value, NONE),
948 JSObject);
949 }
950 }
951
952 return closure_scope;
953 }
954
955
956 // This method copies structure of MaterializeClosure method above.
957 static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
958 Handle<String> variable_name,
959 Handle<Object> new_value) {
960 DCHECK(context->IsFunctionContext());
961
962 Handle<SharedFunctionInfo> shared(context->closure()->shared());
963 Handle<ScopeInfo> scope_info(shared->scope_info());
964
965 // Context locals to the context extension.
966 if (SetContextLocalValue(isolate, scope_info, context, variable_name,
967 new_value)) {
968 return true;
969 }
970
971 // Properties from the function context extension. This will
972 // be variables introduced by eval.
973 if (context->has_extension()) {
974 Handle<JSObject> ext(JSObject::cast(context->extension()));
975 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
976 DCHECK(maybe.has_value);
977 if (maybe.value) {
978 // We don't expect this to do anything except replacing property value.
979 Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE)
980 .Assert();
981 return true;
982 }
983 }
984
985 return false;
986 }
987
988
989 // Create a plain JSObject which materializes the scope for the specified
990 // catch context.
991 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope(
992 Isolate* isolate, Handle<Context> context) {
993 DCHECK(context->IsCatchContext());
994 Handle<String> name(String::cast(context->extension()));
995 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
996 isolate);
997 Handle<JSObject> catch_scope =
998 isolate->factory()->NewJSObject(isolate->object_function());
999 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
1000 catch_scope, name, thrown_object, NONE),
1001 JSObject);
1002 return catch_scope;
1003 }
1004
1005
1006 static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context,
1007 Handle<String> variable_name,
1008 Handle<Object> new_value) {
1009 DCHECK(context->IsCatchContext());
1010 Handle<String> name(String::cast(context->extension()));
1011 if (!String::Equals(name, variable_name)) {
1012 return false;
1013 }
1014 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
1015 return true;
1016 }
1017
1018
1019 // Create a plain JSObject which materializes the block scope for the specified
1020 // block context.
1021 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope(
1022 Isolate* isolate, Handle<Context> context) {
1023 DCHECK(context->IsBlockContext());
1024 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
1025
1026 // Allocate and initialize a JSObject with all the arguments, stack locals
1027 // heap locals and extension properties of the debugged function.
1028 Handle<JSObject> block_scope =
1029 isolate->factory()->NewJSObject(isolate->object_function());
1030
1031 // Fill all context locals.
1032 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
1033 block_scope)) {
1034 return MaybeHandle<JSObject>();
1035 }
1036
1037 return block_scope;
1038 }
1039
1040
1041 // Create a plain JSObject which materializes the module scope for the specified
1042 // module context.
1043 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
1044 Isolate* isolate, Handle<Context> context) {
1045 DCHECK(context->IsModuleContext());
1046 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
1047
1048 // Allocate and initialize a JSObject with all the members of the debugged
1049 // module.
1050 Handle<JSObject> module_scope =
1051 isolate->factory()->NewJSObject(isolate->object_function());
1052
1053 // Fill all context locals.
1054 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
1055 module_scope)) {
1056 return MaybeHandle<JSObject>();
1057 }
1058
1059 return module_scope;
1060 }
1061
1062
1063 // Iterate over the actual scopes visible from a stack frame or from a closure.
1064 // The iteration proceeds from the innermost visible nested scope outwards.
1065 // All scopes are backed by an actual context except the local scope,
1066 // which is inserted "artificially" in the context chain.
1067 class ScopeIterator {
1068 public:
1069 enum ScopeType {
1070 ScopeTypeGlobal = 0,
1071 ScopeTypeLocal,
1072 ScopeTypeWith,
1073 ScopeTypeClosure,
1074 ScopeTypeCatch,
1075 ScopeTypeBlock,
1076 ScopeTypeModule
1077 };
1078
1079 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame,
1080 int inlined_jsframe_index, bool ignore_nested_scopes = false)
1081 : isolate_(isolate),
1082 frame_(frame),
1083 inlined_jsframe_index_(inlined_jsframe_index),
1084 function_(frame->function()),
1085 context_(Context::cast(frame->context())),
1086 nested_scope_chain_(4),
1087 failed_(false) {
1088 // Catch the case when the debugger stops in an internal function.
1089 Handle<SharedFunctionInfo> shared_info(function_->shared());
1090 Handle<ScopeInfo> scope_info(shared_info->scope_info());
1091 if (shared_info->script() == isolate->heap()->undefined_value()) {
1092 while (context_->closure() == *function_) {
1093 context_ = Handle<Context>(context_->previous(), isolate_);
1094 }
1095 return;
1096 }
1097
1098 // Get the debug info (create it if it does not exist).
1099 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
1100 // Return if ensuring debug info failed.
1101 return;
1102 }
1103
1104 // Currently it takes too much time to find nested scopes due to script
1105 // parsing. Sometimes we want to run the ScopeIterator as fast as possible
1106 // (for example, while collecting async call stacks on every
1107 // addEventListener call), even if we drop some nested scopes.
1108 // Later we may optimize getting the nested scopes (cache the result?)
1109 // and include nested scopes into the "fast" iteration case as well.
1110 if (!ignore_nested_scopes) {
1111 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
1112
1113 // Find the break point where execution has stopped.
1114 BreakLocationIterator break_location_iterator(debug_info,
1115 ALL_BREAK_LOCATIONS);
1116 // pc points to the instruction after the current one, possibly a break
1117 // location as well. So the "- 1" to exclude it from the search.
1118 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
1119
1120 // Within the return sequence at the moment it is not possible to
1121 // get a source position which is consistent with the current scope chain.
1122 // Thus all nested with, catch and block contexts are skipped and we only
1123 // provide the function scope.
1124 ignore_nested_scopes = break_location_iterator.IsExit();
1125 }
1126
1127 if (ignore_nested_scopes) {
1128 if (scope_info->HasContext()) {
1129 context_ = Handle<Context>(context_->declaration_context(), isolate_);
1130 } else {
1131 while (context_->closure() == *function_) {
1132 context_ = Handle<Context>(context_->previous(), isolate_);
1133 }
1134 }
1135 if (scope_info->scope_type() == FUNCTION_SCOPE) {
1136 nested_scope_chain_.Add(scope_info);
1137 }
1138 } else {
1139 // Reparse the code and analyze the scopes.
1140 Handle<Script> script(Script::cast(shared_info->script()));
1141 Scope* scope = NULL;
1142
1143 // Check whether we are in global, eval or function code.
1144 Handle<ScopeInfo> scope_info(shared_info->scope_info());
1145 if (scope_info->scope_type() != FUNCTION_SCOPE) {
1146 // Global or eval code.
1147 CompilationInfoWithZone info(script);
1148 if (scope_info->scope_type() == GLOBAL_SCOPE) {
1149 info.MarkAsGlobal();
1150 } else {
1151 DCHECK(scope_info->scope_type() == EVAL_SCOPE);
1152 info.MarkAsEval();
1153 info.SetContext(Handle<Context>(function_->context()));
1154 }
1155 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
1156 scope = info.function()->scope();
1157 }
1158 RetrieveScopeChain(scope, shared_info);
1159 } else {
1160 // Function code
1161 CompilationInfoWithZone info(shared_info);
1162 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
1163 scope = info.function()->scope();
1164 }
1165 RetrieveScopeChain(scope, shared_info);
1166 }
1167 }
1168 }
1169
1170 ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
1171 : isolate_(isolate),
1172 frame_(NULL),
1173 inlined_jsframe_index_(0),
1174 function_(function),
1175 context_(function->context()),
1176 failed_(false) {
1177 if (function->IsBuiltin()) {
1178 context_ = Handle<Context>();
1179 }
1180 }
1181
1182 // More scopes?
1183 bool Done() {
1184 DCHECK(!failed_);
1185 return context_.is_null();
1186 }
1187
1188 bool Failed() { return failed_; }
1189
1190 // Move to the next scope.
1191 void Next() {
1192 DCHECK(!failed_);
1193 ScopeType scope_type = Type();
1194 if (scope_type == ScopeTypeGlobal) {
1195 // The global scope is always the last in the chain.
1196 DCHECK(context_->IsNativeContext());
1197 context_ = Handle<Context>();
1198 return;
1199 }
1200 if (nested_scope_chain_.is_empty()) {
1201 context_ = Handle<Context>(context_->previous(), isolate_);
1202 } else {
1203 if (nested_scope_chain_.last()->HasContext()) {
1204 DCHECK(context_->previous() != NULL);
1205 context_ = Handle<Context>(context_->previous(), isolate_);
1206 }
1207 nested_scope_chain_.RemoveLast();
1208 }
1209 }
1210
1211 // Return the type of the current scope.
1212 ScopeType Type() {
1213 DCHECK(!failed_);
1214 if (!nested_scope_chain_.is_empty()) {
1215 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
1216 switch (scope_info->scope_type()) {
1217 case FUNCTION_SCOPE:
1218 DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
1219 return ScopeTypeLocal;
1220 case MODULE_SCOPE:
1221 DCHECK(context_->IsModuleContext());
1222 return ScopeTypeModule;
1223 case GLOBAL_SCOPE:
1224 DCHECK(context_->IsNativeContext());
1225 return ScopeTypeGlobal;
1226 case WITH_SCOPE:
1227 DCHECK(context_->IsWithContext());
1228 return ScopeTypeWith;
1229 case CATCH_SCOPE:
1230 DCHECK(context_->IsCatchContext());
1231 return ScopeTypeCatch;
1232 case BLOCK_SCOPE:
1233 DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
1234 return ScopeTypeBlock;
1235 case EVAL_SCOPE:
1236 UNREACHABLE();
1237 }
1238 }
1239 if (context_->IsNativeContext()) {
1240 DCHECK(context_->global_object()->IsGlobalObject());
1241 return ScopeTypeGlobal;
1242 }
1243 if (context_->IsFunctionContext()) {
1244 return ScopeTypeClosure;
1245 }
1246 if (context_->IsCatchContext()) {
1247 return ScopeTypeCatch;
1248 }
1249 if (context_->IsBlockContext()) {
1250 return ScopeTypeBlock;
1251 }
1252 if (context_->IsModuleContext()) {
1253 return ScopeTypeModule;
1254 }
1255 DCHECK(context_->IsWithContext());
1256 return ScopeTypeWith;
1257 }
1258
1259 // Return the JavaScript object with the content of the current scope.
1260 MaybeHandle<JSObject> ScopeObject() {
1261 DCHECK(!failed_);
1262 switch (Type()) {
1263 case ScopeIterator::ScopeTypeGlobal:
1264 return Handle<JSObject>(CurrentContext()->global_object());
1265 case ScopeIterator::ScopeTypeLocal:
1266 // Materialize the content of the local scope into a JSObject.
1267 DCHECK(nested_scope_chain_.length() == 1);
1268 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
1269 case ScopeIterator::ScopeTypeWith:
1270 // Return the with object.
1271 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
1272 case ScopeIterator::ScopeTypeCatch:
1273 return MaterializeCatchScope(isolate_, CurrentContext());
1274 case ScopeIterator::ScopeTypeClosure:
1275 // Materialize the content of the closure scope into a JSObject.
1276 return MaterializeClosure(isolate_, CurrentContext());
1277 case ScopeIterator::ScopeTypeBlock:
1278 return MaterializeBlockScope(isolate_, CurrentContext());
1279 case ScopeIterator::ScopeTypeModule:
1280 return MaterializeModuleScope(isolate_, CurrentContext());
1281 }
1282 UNREACHABLE();
1283 return Handle<JSObject>();
1284 }
1285
1286 bool SetVariableValue(Handle<String> variable_name,
1287 Handle<Object> new_value) {
1288 DCHECK(!failed_);
1289 switch (Type()) {
1290 case ScopeIterator::ScopeTypeGlobal:
1291 break;
1292 case ScopeIterator::ScopeTypeLocal:
1293 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
1294 variable_name, new_value);
1295 case ScopeIterator::ScopeTypeWith:
1296 break;
1297 case ScopeIterator::ScopeTypeCatch:
1298 return SetCatchVariableValue(isolate_, CurrentContext(), variable_name,
1299 new_value);
1300 case ScopeIterator::ScopeTypeClosure:
1301 return SetClosureVariableValue(isolate_, CurrentContext(),
1302 variable_name, new_value);
1303 case ScopeIterator::ScopeTypeBlock:
1304 // TODO(2399): should we implement it?
1305 break;
1306 case ScopeIterator::ScopeTypeModule:
1307 // TODO(2399): should we implement it?
1308 break;
1309 }
1310 return false;
1311 }
1312
1313 Handle<ScopeInfo> CurrentScopeInfo() {
1314 DCHECK(!failed_);
1315 if (!nested_scope_chain_.is_empty()) {
1316 return nested_scope_chain_.last();
1317 } else if (context_->IsBlockContext()) {
1318 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
1319 } else if (context_->IsFunctionContext()) {
1320 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
1321 }
1322 return Handle<ScopeInfo>::null();
1323 }
1324
1325 // Return the context for this scope. For the local context there might not
1326 // be an actual context.
1327 Handle<Context> CurrentContext() {
1328 DCHECK(!failed_);
1329 if (Type() == ScopeTypeGlobal || nested_scope_chain_.is_empty()) {
1330 return context_;
1331 } else if (nested_scope_chain_.last()->HasContext()) {
1332 return context_;
1333 } else {
1334 return Handle<Context>();
1335 }
1336 }
1337
1338 #ifdef DEBUG
1339 // Debug print of the content of the current scope.
1340 void DebugPrint() {
1341 OFStream os(stdout);
1342 DCHECK(!failed_);
1343 switch (Type()) {
1344 case ScopeIterator::ScopeTypeGlobal:
1345 os << "Global:\n";
1346 CurrentContext()->Print(os);
1347 break;
1348
1349 case ScopeIterator::ScopeTypeLocal: {
1350 os << "Local:\n";
1351 function_->shared()->scope_info()->Print();
1352 if (!CurrentContext().is_null()) {
1353 CurrentContext()->Print(os);
1354 if (CurrentContext()->has_extension()) {
1355 Handle<Object> extension(CurrentContext()->extension(), isolate_);
1356 if (extension->IsJSContextExtensionObject()) {
1357 extension->Print(os);
1358 }
1359 }
1360 }
1361 break;
1362 }
1363
1364 case ScopeIterator::ScopeTypeWith:
1365 os << "With:\n";
1366 CurrentContext()->extension()->Print(os);
1367 break;
1368
1369 case ScopeIterator::ScopeTypeCatch:
1370 os << "Catch:\n";
1371 CurrentContext()->extension()->Print(os);
1372 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
1373 break;
1374
1375 case ScopeIterator::ScopeTypeClosure:
1376 os << "Closure:\n";
1377 CurrentContext()->Print(os);
1378 if (CurrentContext()->has_extension()) {
1379 Handle<Object> extension(CurrentContext()->extension(), isolate_);
1380 if (extension->IsJSContextExtensionObject()) {
1381 extension->Print(os);
1382 }
1383 }
1384 break;
1385
1386 default:
1387 UNREACHABLE();
1388 }
1389 PrintF("\n");
1390 }
1391 #endif
1392
1393 private:
1394 Isolate* isolate_;
1395 JavaScriptFrame* frame_;
1396 int inlined_jsframe_index_;
1397 Handle<JSFunction> function_;
1398 Handle<Context> context_;
1399 List<Handle<ScopeInfo> > nested_scope_chain_;
1400 bool failed_;
1401
1402 void RetrieveScopeChain(Scope* scope,
1403 Handle<SharedFunctionInfo> shared_info) {
1404 if (scope != NULL) {
1405 int source_position = shared_info->code()->SourcePosition(frame_->pc());
1406 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
1407 } else {
1408 // A failed reparse indicates that the preparser has diverged from the
1409 // parser or that the preparse data given to the initial parse has been
1410 // faulty. We fail in debug mode but in release mode we only provide the
1411 // information we get from the context chain but nothing about
1412 // completely stack allocated scopes or stack allocated locals.
1413 // Or it could be due to stack overflow.
1414 DCHECK(isolate_->has_pending_exception());
1415 failed_ = true;
1416 }
1417 }
1418
1419 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
1420 };
1421
1422
1423 RUNTIME_FUNCTION(Runtime_GetScopeCount) {
1424 HandleScope scope(isolate);
1425 DCHECK(args.length() == 2);
1426 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1427 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1428
1429 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1430
1431 // Get the frame where the debugging is performed.
1432 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1433 JavaScriptFrameIterator it(isolate, id);
1434 JavaScriptFrame* frame = it.frame();
1435
1436 // Count the visible scopes.
1437 int n = 0;
1438 for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
1439 n++;
1440 }
1441
1442 return Smi::FromInt(n);
1443 }
1444
1445
1446 // Returns the list of step-in positions (text offset) in a function of the
1447 // stack frame in a range from the current debug break position to the end
1448 // of the corresponding statement.
1449 RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
1450 HandleScope scope(isolate);
1451 DCHECK(args.length() == 2);
1452 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1453 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1454
1455 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1456
1457 // Get the frame where the debugging is performed.
1458 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1459 JavaScriptFrameIterator frame_it(isolate, id);
1460 RUNTIME_ASSERT(!frame_it.done());
1461
1462 JavaScriptFrame* frame = frame_it.frame();
1463
1464 Handle<JSFunction> fun = Handle<JSFunction>(frame->function());
1465 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
1466
1467 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
1468 return isolate->heap()->undefined_value();
1469 }
1470
1471 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
1472
1473 int len = 0;
1474 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
1475 // Find the break point where execution has stopped.
1476 BreakLocationIterator break_location_iterator(debug_info,
1477 ALL_BREAK_LOCATIONS);
1478
1479 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
1480 int current_statement_pos = break_location_iterator.statement_position();
1481
1482 while (!break_location_iterator.Done()) {
1483 bool accept;
1484 if (break_location_iterator.pc() > frame->pc()) {
1485 accept = true;
1486 } else {
1487 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
1488 // The break point is near our pc. Could be a step-in possibility,
1489 // that is currently taken by active debugger call.
1490 if (break_frame_id == StackFrame::NO_ID) {
1491 // We are not stepping.
1492 accept = false;
1493 } else {
1494 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
1495 // If our frame is a top frame and we are stepping, we can do step-in
1496 // at this place.
1497 accept = additional_frame_it.frame()->id() == id;
1498 }
1499 }
1500 if (accept) {
1501 if (break_location_iterator.IsStepInLocation(isolate)) {
1502 Smi* position_value = Smi::FromInt(break_location_iterator.position());
1503 RETURN_FAILURE_ON_EXCEPTION(
1504 isolate, JSObject::SetElement(
1505 array, len, Handle<Object>(position_value, isolate),
1506 NONE, SLOPPY));
1507 len++;
1508 }
1509 }
1510 // Advance iterator.
1511 break_location_iterator.Next();
1512 if (current_statement_pos != break_location_iterator.statement_position()) {
1513 break;
1514 }
1515 }
1516 return *array;
1517 }
1518
1519
1520 static const int kScopeDetailsTypeIndex = 0;
1521 static const int kScopeDetailsObjectIndex = 1;
1522 static const int kScopeDetailsSize = 2;
1523
1524
1525 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
1526 Isolate* isolate, ScopeIterator* it) {
1527 // Calculate the size of the result.
1528 int details_size = kScopeDetailsSize;
1529 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
1530
1531 // Fill in scope details.
1532 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
1533 Handle<JSObject> scope_object;
1534 ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(),
1535 JSObject);
1536 details->set(kScopeDetailsObjectIndex, *scope_object);
1537
1538 return isolate->factory()->NewJSArrayWithElements(details);
1539 }
1540
1541
1542 // Return an array with scope details
1543 // args[0]: number: break id
1544 // args[1]: number: frame index
1545 // args[2]: number: inlined frame index
1546 // args[3]: number: scope index
1547 //
1548 // The array returned contains the following information:
1549 // 0: Scope type
1550 // 1: Scope object
1551 RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
1552 HandleScope scope(isolate);
1553 DCHECK(args.length() == 4);
1554 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1555 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1556
1557 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1558 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1559 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
1560
1561 // Get the frame where the debugging is performed.
1562 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1563 JavaScriptFrameIterator frame_it(isolate, id);
1564 JavaScriptFrame* frame = frame_it.frame();
1565
1566 // Find the requested scope.
1567 int n = 0;
1568 ScopeIterator it(isolate, frame, inlined_jsframe_index);
1569 for (; !it.Done() && n < index; it.Next()) {
1570 n++;
1571 }
1572 if (it.Done()) {
1573 return isolate->heap()->undefined_value();
1574 }
1575 Handle<JSObject> details;
1576 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
1577 MaterializeScopeDetails(isolate, &it));
1578 return *details;
1579 }
1580
1581
1582 // Return an array of scope details
1583 // args[0]: number: break id
1584 // args[1]: number: frame index
1585 // args[2]: number: inlined frame index
1586 // args[3]: boolean: ignore nested scopes
1587 //
1588 // The array returned contains arrays with the following information:
1589 // 0: Scope type
1590 // 1: Scope object
1591 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
1592 HandleScope scope(isolate);
1593 DCHECK(args.length() == 3 || args.length() == 4);
1594 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1595 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1596
1597 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1598 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1599
1600 bool ignore_nested_scopes = false;
1601 if (args.length() == 4) {
1602 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
1603 ignore_nested_scopes = flag;
1604 }
1605
1606 // Get the frame where the debugging is performed.
1607 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1608 JavaScriptFrameIterator frame_it(isolate, id);
1609 JavaScriptFrame* frame = frame_it.frame();
1610
1611 List<Handle<JSObject> > result(4);
1612 ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
1613 for (; !it.Done(); it.Next()) {
1614 Handle<JSObject> details;
1615 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
1616 MaterializeScopeDetails(isolate, &it));
1617 result.Add(details);
1618 }
1619
1620 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
1621 for (int i = 0; i < result.length(); ++i) {
1622 array->set(i, *result[i]);
1623 }
1624 return *isolate->factory()->NewJSArrayWithElements(array);
1625 }
1626
1627
1628 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
1629 HandleScope scope(isolate);
1630 DCHECK(args.length() == 1);
1631
1632 // Check arguments.
1633 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1634
1635 // Count the visible scopes.
1636 int n = 0;
1637 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
1638 n++;
1639 }
1640
1641 return Smi::FromInt(n);
1642 }
1643
1644
1645 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
1646 HandleScope scope(isolate);
1647 DCHECK(args.length() == 2);
1648
1649 // Check arguments.
1650 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1651 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
1652
1653 // Find the requested scope.
1654 int n = 0;
1655 ScopeIterator it(isolate, fun);
1656 for (; !it.Done() && n < index; it.Next()) {
1657 n++;
1658 }
1659 if (it.Done()) {
1660 return isolate->heap()->undefined_value();
1661 }
1662
1663 Handle<JSObject> details;
1664 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
1665 MaterializeScopeDetails(isolate, &it));
1666 return *details;
1667 }
1668
1669
1670 static bool SetScopeVariableValue(ScopeIterator* it, int index,
1671 Handle<String> variable_name,
1672 Handle<Object> new_value) {
1673 for (int n = 0; !it->Done() && n < index; it->Next()) {
1674 n++;
1675 }
1676 if (it->Done()) {
1677 return false;
1678 }
1679 return it->SetVariableValue(variable_name, new_value);
1680 }
1681
1682
1683 // Change variable value in closure or local scope
1684 // args[0]: number or JsFunction: break id or function
1685 // args[1]: number: frame index (when arg[0] is break id)
1686 // args[2]: number: inlined frame index (when arg[0] is break id)
1687 // args[3]: number: scope index
1688 // args[4]: string: variable name
1689 // args[5]: object: new value
1690 //
1691 // Return true if success and false otherwise
1692 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
1693 HandleScope scope(isolate);
1694 DCHECK(args.length() == 6);
1695
1696 // Check arguments.
1697 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
1698 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
1699 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5);
1700
1701 bool res;
1702 if (args[0]->IsNumber()) {
1703 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1704 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1705
1706 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1707 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1708
1709 // Get the frame where the debugging is performed.
1710 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1711 JavaScriptFrameIterator frame_it(isolate, id);
1712 JavaScriptFrame* frame = frame_it.frame();
1713
1714 ScopeIterator it(isolate, frame, inlined_jsframe_index);
1715 res = SetScopeVariableValue(&it, index, variable_name, new_value);
1716 } else {
1717 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1718 ScopeIterator it(isolate, fun);
1719 res = SetScopeVariableValue(&it, index, variable_name, new_value);
1720 }
1721
1722 return isolate->heap()->ToBoolean(res);
1723 }
1724
1725
1726 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
1727 HandleScope scope(isolate);
1728 DCHECK(args.length() == 0);
1729
1730 #ifdef DEBUG
1731 // Print the scopes for the top frame.
1732 StackFrameLocator locator(isolate);
1733 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
1734 for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
1735 it.DebugPrint();
1736 }
1737 #endif
1738 return isolate->heap()->undefined_value();
1739 }
1740
1741
1742 RUNTIME_FUNCTION(Runtime_GetThreadCount) {
1743 HandleScope scope(isolate);
1744 DCHECK(args.length() == 1);
1745 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1746 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1747
1748 // Count all archived V8 threads.
1749 int n = 0;
1750 for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
1751 thread != NULL; thread = thread->Next()) {
1752 n++;
1753 }
1754
1755 // Total number of threads is current thread and archived threads.
1756 return Smi::FromInt(n + 1);
1757 }
1758
1759
1760 static const int kThreadDetailsCurrentThreadIndex = 0;
1761 static const int kThreadDetailsThreadIdIndex = 1;
1762 static const int kThreadDetailsSize = 2;
1763
1764 // Return an array with thread details
1765 // args[0]: number: break id
1766 // args[1]: number: thread index
1767 //
1768 // The array returned contains the following information:
1769 // 0: Is current thread?
1770 // 1: Thread id
1771 RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
1772 HandleScope scope(isolate);
1773 DCHECK(args.length() == 2);
1774 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1775 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1776
1777 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
1778
1779 // Allocate array for result.
1780 Handle<FixedArray> details =
1781 isolate->factory()->NewFixedArray(kThreadDetailsSize);
1782
1783 // Thread index 0 is current thread.
1784 if (index == 0) {
1785 // Fill the details.
1786 details->set(kThreadDetailsCurrentThreadIndex,
1787 isolate->heap()->true_value());
1788 details->set(kThreadDetailsThreadIdIndex,
1789 Smi::FromInt(ThreadId::Current().ToInteger()));
1790 } else {
1791 // Find the thread with the requested index.
1792 int n = 1;
1793 ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
1794 while (index != n && thread != NULL) {
1795 thread = thread->Next();
1796 n++;
1797 }
1798 if (thread == NULL) {
1799 return isolate->heap()->undefined_value();
1800 }
1801
1802 // Fill the details.
1803 details->set(kThreadDetailsCurrentThreadIndex,
1804 isolate->heap()->false_value());
1805 details->set(kThreadDetailsThreadIdIndex,
1806 Smi::FromInt(thread->id().ToInteger()));
1807 }
1808
1809 // Convert to JS array and return.
1810 return *isolate->factory()->NewJSArrayWithElements(details);
1811 }
1812
1813
1814 // Sets the disable break state
1815 // args[0]: disable break state
1816 RUNTIME_FUNCTION(Runtime_SetDisableBreak) {
1817 HandleScope scope(isolate);
1818 DCHECK(args.length() == 1);
1819 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
1820 isolate->debug()->set_disable_break(disable_break);
1821 return isolate->heap()->undefined_value();
1822 }
1823
1824
1825 static bool IsPositionAlignmentCodeCorrect(int alignment) {
1826 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
1827 }
1828
1829
1830 RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
1831 HandleScope scope(isolate);
1832 DCHECK(args.length() == 2);
1833
1834 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1835 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
1836
1837 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1838 return isolate->ThrowIllegalOperation();
1839 }
1840 BreakPositionAlignment alignment =
1841 static_cast<BreakPositionAlignment>(statement_aligned_code);
1842
1843 Handle<SharedFunctionInfo> shared(fun->shared());
1844 // Find the number of break points
1845 Handle<Object> break_locations =
1846 Debug::GetSourceBreakLocations(shared, alignment);
1847 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
1848 // Return array as JS array
1849 return *isolate->factory()->NewJSArrayWithElements(
1850 Handle<FixedArray>::cast(break_locations));
1851 }
1852
1853
1854 // Set a break point in a function.
1855 // args[0]: function
1856 // args[1]: number: break source position (within the function source)
1857 // args[2]: number: break point object
1858 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
1859 HandleScope scope(isolate);
1860 DCHECK(args.length() == 3);
1861 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1862 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1863 RUNTIME_ASSERT(source_position >= function->shared()->start_position() &&
1864 source_position <= function->shared()->end_position());
1865 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
1866
1867 // Set break point.
1868 RUNTIME_ASSERT(isolate->debug()->SetBreakPoint(
1869 function, break_point_object_arg, &source_position));
1870
1871 return Smi::FromInt(source_position);
1872 }
1873
1874
1875 // Changes the state of a break point in a script and returns source position
1876 // where break point was set. NOTE: Regarding performance see the NOTE for
1877 // GetScriptFromScriptData.
1878 // args[0]: script to set break point in
1879 // args[1]: number: break source position (within the script source)
1880 // args[2]: number, breakpoint position alignment
1881 // args[3]: number: break point object
1882 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
1883 HandleScope scope(isolate);
1884 DCHECK(args.length() == 4);
1885 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
1886 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1887 RUNTIME_ASSERT(source_position >= 0);
1888 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
1889 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
1890
1891 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1892 return isolate->ThrowIllegalOperation();
1893 }
1894 BreakPositionAlignment alignment =
1895 static_cast<BreakPositionAlignment>(statement_aligned_code);
1896
1897 // Get the script from the script wrapper.
1898 RUNTIME_ASSERT(wrapper->value()->IsScript());
1899 Handle<Script> script(Script::cast(wrapper->value()));
1900
1901 // Set break point.
1902 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
1903 &source_position, alignment)) {
1904 return isolate->heap()->undefined_value();
1905 }
1906
1907 return Smi::FromInt(source_position);
1908 }
1909
1910
1911 // Clear a break point
1912 // args[0]: number: break point object
1913 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
1914 HandleScope scope(isolate);
1915 DCHECK(args.length() == 1);
1916 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
1917
1918 // Clear break point.
1919 isolate->debug()->ClearBreakPoint(break_point_object_arg);
1920
1921 return isolate->heap()->undefined_value();
1922 }
1923
1924
1925 // Change the state of break on exceptions.
1926 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
1927 // args[1]: Boolean indicating on/off.
1928 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) {
1929 HandleScope scope(isolate);
1930 DCHECK(args.length() == 2);
1931 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
1932 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
1933
1934 // If the number doesn't match an enum value, the ChangeBreakOnException
1935 // function will default to affecting caught exceptions.
1936 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
1937 // Update break point state.
1938 isolate->debug()->ChangeBreakOnException(type, enable);
1939 return isolate->heap()->undefined_value();
1940 }
1941
1942
1943 // Returns the state of break on exceptions
1944 // args[0]: boolean indicating uncaught exceptions
1945 RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
1946 HandleScope scope(isolate);
1947 DCHECK(args.length() == 1);
1948 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
1949
1950 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
1951 bool result = isolate->debug()->IsBreakOnException(type);
1952 return Smi::FromInt(result);
1953 }
1954
1955
1956 // Prepare for stepping
1957 // args[0]: break id for checking execution state
1958 // args[1]: step action from the enumeration StepAction
1959 // args[2]: number of times to perform the step, for step out it is the number
1960 // of frames to step down.
1961 RUNTIME_FUNCTION(Runtime_PrepareStep) {
1962 HandleScope scope(isolate);
1963 DCHECK(args.length() == 4);
1964 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1965 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1966
1967 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
1968 return isolate->Throw(isolate->heap()->illegal_argument_string());
1969 }
1970
1971 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
1972
1973 StackFrame::Id frame_id;
1974 if (wrapped_frame_id == 0) {
1975 frame_id = StackFrame::NO_ID;
1976 } else {
1977 frame_id = UnwrapFrameId(wrapped_frame_id);
1978 }
1979
1980 // Get the step action and check validity.
1981 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
1982 if (step_action != StepIn && step_action != StepNext &&
1983 step_action != StepOut && step_action != StepInMin &&
1984 step_action != StepMin) {
1985 return isolate->Throw(isolate->heap()->illegal_argument_string());
1986 }
1987
1988 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
1989 step_action != StepMin && step_action != StepOut) {
1990 return isolate->ThrowIllegalOperation();
1991 }
1992
1993 // Get the number of steps.
1994 int step_count = NumberToInt32(args[2]);
1995 if (step_count < 1) {
1996 return isolate->Throw(isolate->heap()->illegal_argument_string());
1997 }
1998
1999 // Clear all current stepping setup.
2000 isolate->debug()->ClearStepping();
2001
2002 // Prepare step.
2003 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
2004 step_count, frame_id);
2005 return isolate->heap()->undefined_value();
2006 }
2007
2008
2009 // Clear all stepping set by PrepareStep.
2010 RUNTIME_FUNCTION(Runtime_ClearStepping) {
2011 HandleScope scope(isolate);
2012 DCHECK(args.length() == 0);
2013 isolate->debug()->ClearStepping();
2014 return isolate->heap()->undefined_value();
2015 }
2016
2017
2018 // Helper function to find or create the arguments object for
2019 // Runtime_DebugEvaluate.
2020 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
2021 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function) {
2022 // Do not materialize the arguments object for eval or top-level code.
2023 // Skip if "arguments" is already taken.
2024 if (!function->shared()->is_function()) return target;
2025 Maybe<bool> maybe = JSReceiver::HasOwnProperty(
2026 target, isolate->factory()->arguments_string());
2027 if (!maybe.has_value) return MaybeHandle<JSObject>();
2028 if (maybe.value) return target;
2029
2030 // FunctionGetArguments can't throw an exception.
2031 Handle<JSObject> arguments =
2032 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
2033 Handle<String> arguments_str = isolate->factory()->arguments_string();
2034 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
2035 target, arguments_str, arguments, NONE),
2036 JSObject);
2037 return target;
2038 }
2039
2040
2041 // Compile and evaluate source for the given context.
2042 static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
2043 Handle<Context> context,
2044 Handle<Object> context_extension,
2045 Handle<Object> receiver,
2046 Handle<String> source) {
2047 if (context_extension->IsJSObject()) {
2048 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
2049 Handle<JSFunction> closure(context->closure(), isolate);
2050 context = isolate->factory()->NewWithContext(closure, context, extension);
2051 }
2052
2053 Handle<JSFunction> eval_fun;
2054 ASSIGN_RETURN_ON_EXCEPTION(
2055 isolate, eval_fun, Compiler::GetFunctionFromEval(source, context, SLOPPY,
2056 NO_PARSE_RESTRICTION,
2057 RelocInfo::kNoPosition),
2058 Object);
2059
2060 Handle<Object> result;
2061 ASSIGN_RETURN_ON_EXCEPTION(
2062 isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
2063 Object);
2064
2065 // Skip the global proxy as it has no properties and always delegates to the
2066 // real global object.
2067 if (result->IsJSGlobalProxy()) {
2068 PrototypeIterator iter(isolate, result);
2069 // TODO(verwaest): This will crash when the global proxy is detached.
2070 result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
2071 }
2072
2073 // Clear the oneshot breakpoints so that the debugger does not step further.
2074 isolate->debug()->ClearStepping();
2075 return result;
2076 }
2077
2078
2079 static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
2080 Handle<JSObject> result =
2081 isolate->factory()->NewJSObject(isolate->object_function());
2082 Handle<Map> new_map = Map::Copy(Handle<Map>(result->map()));
2083 new_map->set_prototype(*isolate->factory()->null_value());
2084 JSObject::MigrateToMap(result, new_map);
2085 return result;
2086 }
2087
2088
2089 // Evaluate a piece of JavaScript in the context of a stack frame for
2090 // debugging. Things that need special attention are:
2091 // - Parameters and stack-allocated locals need to be materialized. Altered
2092 // values need to be written back to the stack afterwards.
2093 // - The arguments object needs to materialized.
2094 RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
2095 HandleScope scope(isolate);
2096
2097 // Check the execution state and decode arguments frame and source to be
2098 // evaluated.
2099 DCHECK(args.length() == 6);
2100 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
2101 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
2102
2103 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
2104 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
2105 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
2106 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
2107 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
2108
2109 // Handle the processing of break.
2110 DisableBreak disable_break_scope(isolate->debug(), disable_break);
2111
2112 // Get the frame where the debugging is performed.
2113 StackFrame::Id id = UnwrapFrameId(wrapped_id);
2114 JavaScriptFrameIterator it(isolate, id);
2115 JavaScriptFrame* frame = it.frame();
2116 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
2117 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
2118
2119 // Traverse the saved contexts chain to find the active context for the
2120 // selected frame.
2121 SaveContext* save = FindSavedContextForFrame(isolate, frame);
2122
2123 SaveContext savex(isolate);
2124 isolate->set_context(*(save->context()));
2125
2126 // Materialize stack locals and the arguments object.
2127 Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate);
2128
2129 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2130 isolate, materialized,
2131 MaterializeStackLocalsWithFrameInspector(isolate, materialized, function,
2132 &frame_inspector));
2133
2134 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2135 isolate, materialized,
2136 MaterializeArgumentsObject(isolate, materialized, function));
2137
2138 // At this point, the lookup chain may look like this:
2139 // [inner context] -> [function stack]+[function context] -> [outer context]
2140 // The function stack is not an actual context, it complements the function
2141 // context. In order to have the same lookup chain when debug-evaluating,
2142 // we materialize the stack and insert it into the context chain as a
2143 // with-context before the function context.
2144 // [inner context] -> [with context] -> [function context] -> [outer context]
2145 // Ordering the with-context before the function context forces a dynamic
2146 // lookup instead of a static lookup that could fail as the scope info is
2147 // outdated and may expect variables to still be stack-allocated.
2148 // Afterwards, we write changes to the with-context back to the stack
2149 // and remove it from the context chain.
2150 // This could cause lookup failures if debug-evaluate creates a closure that
2151 // uses this temporary context chain.
2152
2153 Handle<Context> eval_context(Context::cast(frame_inspector.GetContext()));
2154 DCHECK(!eval_context.is_null());
2155 Handle<Context> function_context = eval_context;
2156 Handle<Context> outer_context(function->context(), isolate);
2157 Handle<Context> inner_context;
2158 // We iterate to find the function's context. If the function has no
2159 // context-allocated variables, we iterate until we hit the outer context.
2160 while (!function_context->IsFunctionContext() &&
2161 !function_context.is_identical_to(outer_context)) {
2162 inner_context = function_context;
2163 function_context = Handle<Context>(function_context->previous(), isolate);
2164 }
2165
2166 Handle<Context> materialized_context = isolate->factory()->NewWithContext(
2167 function, function_context, materialized);
2168
2169 if (inner_context.is_null()) {
2170 // No inner context. The with-context is now inner-most.
2171 eval_context = materialized_context;
2172 } else {
2173 inner_context->set_previous(*materialized_context);
2174 }
2175
2176 Handle<Object> receiver(frame->receiver(), isolate);
2177 MaybeHandle<Object> maybe_result =
2178 DebugEvaluate(isolate, eval_context, context_extension, receiver, source);
2179
2180 // Remove with-context if it was inserted in between.
2181 if (!inner_context.is_null()) inner_context->set_previous(*function_context);
2182
2183 Handle<Object> result;
2184 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
2185
2186 // Write back potential changes to materialized stack locals to the stack.
2187 UpdateStackLocalsFromMaterializedObject(isolate, materialized, function,
2188 frame, inlined_jsframe_index);
2189
2190 return *result;
2191 }
2192
2193
2194 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
2195 HandleScope scope(isolate);
2196
2197 // Check the execution state and decode arguments frame and source to be
2198 // evaluated.
2199 DCHECK(args.length() == 4);
2200 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
2201 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
2202
2203 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2204 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
2205 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
2206
2207 // Handle the processing of break.
2208 DisableBreak disable_break_scope(isolate->debug(), disable_break);
2209
2210 // Enter the top context from before the debugger was invoked.
2211 SaveContext save(isolate);
2212 SaveContext* top = &save;
2213 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
2214 top = top->prev();
2215 }
2216 if (top != NULL) {
2217 isolate->set_context(*top->context());
2218 }
2219
2220 // Get the native context now set to the top context from before the
2221 // debugger was invoked.
2222 Handle<Context> context = isolate->native_context();
2223 Handle<JSObject> receiver(context->global_proxy());
2224 Handle<Object> result;
2225 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2226 isolate, result,
2227 DebugEvaluate(isolate, context, context_extension, receiver, source));
2228 return *result;
2229 }
2230
2231
2232 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
2233 HandleScope scope(isolate);
2234 DCHECK(args.length() == 0);
2235
2236 // Fill the script objects.
2237 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
2238
2239 // Convert the script objects to proper JS objects.
2240 for (int i = 0; i < instances->length(); i++) {
2241 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
2242 // Get the script wrapper in a local handle before calling GetScriptWrapper,
2243 // because using
2244 // instances->set(i, *GetScriptWrapper(script))
2245 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
2246 // already have dereferenced the instances handle.
2247 Handle<JSObject> wrapper = Script::GetWrapper(script);
2248 instances->set(i, *wrapper);
2249 }
2250
2251 // Return result as a JS array.
2252 Handle<JSObject> result =
2253 isolate->factory()->NewJSObject(isolate->array_function());
2254 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
2255 return *result;
2256 }
2257
2258
2259 // Helper function used by Runtime_DebugReferencedBy below.
2260 static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
2261 Object* instance_filter, int max_references,
2262 FixedArray* instances, int instances_size,
2263 JSFunction* arguments_function) {
2264 Isolate* isolate = target->GetIsolate();
2265 SealHandleScope shs(isolate);
2266 DisallowHeapAllocation no_allocation;
2267
2268 // Iterate the heap.
2269 int count = 0;
2270 JSObject* last = NULL;
2271 HeapObject* heap_obj = NULL;
2272 while (((heap_obj = iterator->next()) != NULL) &&
2273 (max_references == 0 || count < max_references)) {
2274 // Only look at all JSObjects.
2275 if (heap_obj->IsJSObject()) {
2276 // Skip context extension objects and argument arrays as these are
2277 // checked in the context of functions using them.
2278 JSObject* obj = JSObject::cast(heap_obj);
2279 if (obj->IsJSContextExtensionObject() ||
2280 obj->map()->constructor() == arguments_function) {
2281 continue;
2282 }
2283
2284 // Check if the JS object has a reference to the object looked for.
2285 if (obj->ReferencesObject(target)) {
2286 // Check instance filter if supplied. This is normally used to avoid
2287 // references from mirror objects (see Runtime_IsInPrototypeChain).
2288 if (!instance_filter->IsUndefined()) {
2289 for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
2290 iter.Advance()) {
2291 if (iter.GetCurrent() == instance_filter) {
2292 obj = NULL; // Don't add this object.
2293 break;
2294 }
2295 }
2296 }
2297
2298 if (obj != NULL) {
2299 // Valid reference found add to instance array if supplied an update
2300 // count.
2301 if (instances != NULL && count < instances_size) {
2302 instances->set(count, obj);
2303 }
2304 last = obj;
2305 count++;
2306 }
2307 }
2308 }
2309 }
2310
2311 // Check for circular reference only. This can happen when the object is only
2312 // referenced from mirrors and has a circular reference in which case the
2313 // object is not really alive and would have been garbage collected if not
2314 // referenced from the mirror.
2315 if (count == 1 && last == target) {
2316 count = 0;
2317 }
2318
2319 // Return the number of referencing objects found.
2320 return count;
2321 }
2322
2323
2324 // Scan the heap for objects with direct references to an object
2325 // args[0]: the object to find references to
2326 // args[1]: constructor function for instances to exclude (Mirror)
2327 // args[2]: the the maximum number of objects to return
2328 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
2329 HandleScope scope(isolate);
2330 DCHECK(args.length() == 3);
2331
2332 // Check parameters.
2333 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
2334 CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
2335 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
2336 instance_filter->IsJSObject());
2337 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
2338 RUNTIME_ASSERT(max_references >= 0);
2339
2340
2341 // Get the constructor function for context extension and arguments array.
2342 Handle<JSFunction> arguments_function(
2343 JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
2344
2345 // Get the number of referencing objects.
2346 int count;
2347 // First perform a full GC in order to avoid dead objects and to make the heap
2348 // iterable.
2349 Heap* heap = isolate->heap();
2350 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
2351 {
2352 HeapIterator heap_iterator(heap);
2353 count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
2354 max_references, NULL, 0, *arguments_function);
2355 }
2356
2357 // Allocate an array to hold the result.
2358 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
2359
2360 // Fill the referencing objects.
2361 {
2362 HeapIterator heap_iterator(heap);
2363 count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
2364 max_references, *instances, count,
2365 *arguments_function);
2366 }
2367
2368 // Return result as JS array.
2369 Handle<JSFunction> constructor = isolate->array_function();
2370
2371 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
2372 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
2373 return *result;
2374 }
2375
2376
2377 // Helper function used by Runtime_DebugConstructedBy below.
2378 static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
2379 int max_references, FixedArray* instances,
2380 int instances_size) {
2381 DisallowHeapAllocation no_allocation;
2382
2383 // Iterate the heap.
2384 int count = 0;
2385 HeapObject* heap_obj = NULL;
2386 while (((heap_obj = iterator->next()) != NULL) &&
2387 (max_references == 0 || count < max_references)) {
2388 // Only look at all JSObjects.
2389 if (heap_obj->IsJSObject()) {
2390 JSObject* obj = JSObject::cast(heap_obj);
2391 if (obj->map()->constructor() == constructor) {
2392 // Valid reference found add to instance array if supplied an update
2393 // count.
2394 if (instances != NULL && count < instances_size) {
2395 instances->set(count, obj);
2396 }
2397 count++;
2398 }
2399 }
2400 }
2401
2402 // Return the number of referencing objects found.
2403 return count;
2404 }
2405
2406
2407 // Scan the heap for objects constructed by a specific function.
2408 // args[0]: the constructor to find instances of
2409 // args[1]: the the maximum number of objects to return
2410 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
2411 HandleScope scope(isolate);
2412 DCHECK(args.length() == 2);
2413
2414
2415 // Check parameters.
2416 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
2417 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
2418 RUNTIME_ASSERT(max_references >= 0);
2419
2420 // Get the number of referencing objects.
2421 int count;
2422 // First perform a full GC in order to avoid dead objects and to make the heap
2423 // iterable.
2424 Heap* heap = isolate->heap();
2425 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
2426 {
2427 HeapIterator heap_iterator(heap);
2428 count = DebugConstructedBy(&heap_iterator, *constructor, max_references,
2429 NULL, 0);
2430 }
2431
2432 // Allocate an array to hold the result.
2433 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
2434
2435 // Fill the referencing objects.
2436 {
2437 HeapIterator heap_iterator2(heap);
2438 count = DebugConstructedBy(&heap_iterator2, *constructor, max_references,
2439 *instances, count);
2440 }
2441
2442 // Return result as JS array.
2443 Handle<JSFunction> array_function = isolate->array_function();
2444 Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
2445 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
2446 return *result;
2447 }
2448
2449
2450 // Find the effective prototype object as returned by __proto__.
2451 // args[0]: the object to find the prototype for.
2452 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) {
2453 HandleScope shs(isolate);
2454 DCHECK(args.length() == 1);
2455 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
2456 return *Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
2457 }
2458
2459
2460 // Patches script source (should be called upon BeforeCompile event).
2461 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
2462 HandleScope scope(isolate);
2463 DCHECK(args.length() == 2);
2464
2465 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
2466 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2467
2468 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
2469 Handle<Script> script(Script::cast(script_wrapper->value()));
2470
2471 int compilation_state = script->compilation_state();
2472 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
2473 script->set_source(*source);
2474
2475 return isolate->heap()->undefined_value();
2476 }
2477
2478
2479 RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
2480 HandleScope scope(isolate);
2481 #ifdef DEBUG
2482 DCHECK(args.length() == 1);
2483 // Get the function and make sure it is compiled.
2484 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
2485 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
2486 return isolate->heap()->exception();
2487 }
2488 OFStream os(stdout);
2489 func->code()->Print(os);
2490 os << endl;
2491 #endif // DEBUG
2492 return isolate->heap()->undefined_value();
2493 }
2494
2495
2496 RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) {
2497 HandleScope scope(isolate);
2498 #ifdef DEBUG
2499 DCHECK(args.length() == 1);
2500 // Get the function and make sure it is compiled.
2501 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
2502 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
2503 return isolate->heap()->exception();
2504 }
2505 OFStream os(stdout);
2506 func->shared()->construct_stub()->Print(os);
2507 os << endl;
2508 #endif // DEBUG
2509 return isolate->heap()->undefined_value();
2510 }
2511
2512
2513 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
2514 SealHandleScope shs(isolate);
2515 DCHECK(args.length() == 1);
2516
2517 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2518 return f->shared()->inferred_name();
2519 }
2520
2521
2522 // A testing entry. Returns statement position which is the closest to
2523 // source_position.
2524 RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
2525 HandleScope scope(isolate);
2526 CHECK(isolate->debug()->live_edit_enabled());
2527 DCHECK(args.length() == 2);
2528 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
2529 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
2530
2531 Handle<Code> code(function->code(), isolate);
2532
2533 if (code->kind() != Code::FUNCTION &&
2534 code->kind() != Code::OPTIMIZED_FUNCTION) {
2535 return isolate->heap()->undefined_value();
2536 }
2537
2538 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
2539 int closest_pc = 0;
2540 int distance = kMaxInt;
2541 while (!it.done()) {
2542 int statement_position = static_cast<int>(it.rinfo()->data());
2543 // Check if this break point is closer that what was previously found.
2544 if (source_position <= statement_position &&
2545 statement_position - source_position < distance) {
2546 closest_pc =
2547 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
2548 distance = statement_position - source_position;
2549 // Check whether we can't get any closer.
2550 if (distance == 0) break;
2551 }
2552 it.next();
2553 }
2554
2555 return Smi::FromInt(closest_pc);
2556 }
2557
2558
2559 // Calls specified function with or without entering the debugger.
2560 // This is used in unit tests to run code as if debugger is entered or simply
2561 // to have a stack with C++ frame in the middle.
2562 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
2563 HandleScope scope(isolate);
2564 DCHECK(args.length() == 2);
2565 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
2566 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
2567
2568 MaybeHandle<Object> maybe_result;
2569 if (without_debugger) {
2570 maybe_result = Execution::Call(isolate, function,
2571 handle(function->global_proxy()), 0, NULL);
2572 } else {
2573 DebugScope debug_scope(isolate->debug());
2574 maybe_result = Execution::Call(isolate, function,
2575 handle(function->global_proxy()), 0, NULL);
2576 }
2577 Handle<Object> result;
2578 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
2579 return *result;
2580 }
2581
2582
2583 // Performs a GC.
2584 // Presently, it only does a full GC.
2585 RUNTIME_FUNCTION(Runtime_CollectGarbage) {
2586 SealHandleScope shs(isolate);
2587 DCHECK(args.length() == 1);
2588 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
2589 return isolate->heap()->undefined_value();
2590 }
2591
2592
2593 // Gets the current heap usage.
2594 RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
2595 SealHandleScope shs(isolate);
2596 DCHECK(args.length() == 0);
2597 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
2598 if (!Smi::IsValid(usage)) {
2599 return *isolate->factory()->NewNumberFromInt(usage);
2600 }
2601 return Smi::FromInt(usage);
2602 }
2603
2604
2605 // Finds the script object from the script data. NOTE: This operation uses
2606 // heap traversal to find the function generated for the source position
2607 // for the requested break point. For lazily compiled functions several heap
2608 // traversals might be required rendering this operation as a rather slow
2609 // operation. However for setting break points which is normally done through
2610 // some kind of user interaction the performance is not crucial.
2611 static Handle<Object> Runtime_GetScriptFromScriptName(
2612 Handle<String> script_name) {
2613 // Scan the heap for Script objects to find the script with the requested
2614 // script data.
2615 Handle<Script> script;
2616 Factory* factory = script_name->GetIsolate()->factory();
2617 Heap* heap = script_name->GetHeap();
2618 HeapIterator iterator(heap);
2619 HeapObject* obj = NULL;
2620 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
2621 // If a script is found check if it has the script data requested.
2622 if (obj->IsScript()) {
2623 if (Script::cast(obj)->name()->IsString()) {
2624 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
2625 script = Handle<Script>(Script::cast(obj));
2626 }
2627 }
2628 }
2629 }
2630
2631 // If no script with the requested script data is found return undefined.
2632 if (script.is_null()) return factory->undefined_value();
2633
2634 // Return the script found.
2635 return Script::GetWrapper(script);
2636 }
2637
2638
2639 // Get the script object from script data. NOTE: Regarding performance
2640 // see the NOTE for GetScriptFromScriptData.
2641 // args[0]: script data for the script to find the source for
2642 RUNTIME_FUNCTION(Runtime_GetScript) {
2643 HandleScope scope(isolate);
2644
2645 DCHECK(args.length() == 1);
2646
2647 CONVERT_ARG_CHECKED(String, script_name, 0);
2648
2649 // Find the requested script.
2650 Handle<Object> result =
2651 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
2652 return *result;
2653 }
2654
2655
2656 // Check whether debugger and is about to step into the callback that is passed
2657 // to a built-in function such as Array.forEach.
2658 RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
2659 DCHECK(args.length() == 1);
2660 if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) {
2661 return isolate->heap()->false_value();
2662 }
2663 CONVERT_ARG_CHECKED(Object, callback, 0);
2664 // We do not step into the callback if it's a builtin or not even a function.
2665 return isolate->heap()->ToBoolean(callback->IsJSFunction() &&
2666 !JSFunction::cast(callback)->IsBuiltin());
2667 }
2668
2669
2670 // Set one shot breakpoints for the callback function that is passed to a
2671 // built-in function such as Array.forEach to enable stepping into the callback.
2672 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
2673 DCHECK(args.length() == 1);
2674 Debug* debug = isolate->debug();
2675 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
2676
2677 HandleScope scope(isolate);
2678 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
2679 RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject());
2680 Handle<JSFunction> fun;
2681 if (object->IsJSFunction()) {
2682 fun = Handle<JSFunction>::cast(object);
2683 } else {
2684 fun = Handle<JSFunction>(
2685 Handle<JSGeneratorObject>::cast(object)->function(), isolate);
2686 }
2687 // When leaving the function, step out has been activated, but not performed
2688 // if we do not leave the builtin. To be able to step into the function
2689 // again, we need to clear the step out at this point.
2690 debug->ClearStepOut();
2691 debug->FloodWithOneShot(fun);
2692 return isolate->heap()->undefined_value();
2693 }
2694
2695
2696 RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
2697 DCHECK(args.length() == 1);
2698 HandleScope scope(isolate);
2699 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
2700 isolate->PushPromise(promise);
2701 return isolate->heap()->undefined_value();
2702 }
2703
2704
2705 RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
2706 DCHECK(args.length() == 0);
2707 SealHandleScope shs(isolate);
2708 isolate->PopPromise();
2709 return isolate->heap()->undefined_value();
2710 }
2711
2712
2713 RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
2714 DCHECK(args.length() == 1);
2715 HandleScope scope(isolate);
2716 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
2717 isolate->debug()->OnPromiseEvent(data);
2718 return isolate->heap()->undefined_value();
2719 }
2720
2721
2722 RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
2723 DCHECK(args.length() == 1);
2724 HandleScope scope(isolate);
2725 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
2726 isolate->debug()->OnAsyncTaskEvent(data);
2727 return isolate->heap()->undefined_value();
2728 }
2729
2730
2731 RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) {
2732 SealHandleScope shs(isolate);
2733 return Smi::FromInt(isolate->debug()->is_active());
2734 }
2735 }
2736 } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime/runtime-date.cc ('k') | src/runtime/runtime-generator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698