blob: 9b71a4f95e01170d334653a4973cf9b1b67e761c [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
16namespace v8 {
17namespace internal {
18
19RUNTIME_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.
28static Smi* WrapFrameId(StackFrame::Id id) {
29 DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
30 return Smi::FromInt(id >> 2);
31}
32
33
34static 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
43RUNTIME_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
56RUNTIME_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
64static 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.
110RUNTIME_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, PropertyDetails(NONE, FIELD, 0).AsSmi());
140 return *isolate->factory()->NewJSArrayWithElements(details);
141 }
142
143 LookupIterator it(obj, name, LookupIterator::HIDDEN);
144 bool has_caught = false;
145 Handle<Object> value = DebugGetProperty(&it, &has_caught);
146 if (!it.IsFound()) return isolate->heap()->undefined_value();
147
148 Handle<Object> maybe_pair;
149 if (it.state() == LookupIterator::ACCESSOR) {
150 maybe_pair = it.GetAccessors();
151 }
152
153 // If the callback object is a fixed array then it contains JavaScript
154 // getter and/or setter.
155 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair();
156 Handle<FixedArray> details =
157 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3);
158 details->set(0, *value);
159 // TODO(verwaest): Get rid of this random way of handling interceptors.
160 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR
161 ? PropertyDetails(NONE, FIELD, 0)
162 : it.property_details();
163 details->set(1, d.AsSmi());
164 details->set(
165 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
166 if (has_js_accessors) {
167 AccessorPair* accessors = AccessorPair::cast(*maybe_pair);
168 details->set(3, isolate->heap()->ToBoolean(has_caught));
169 details->set(4, accessors->GetComponent(ACCESSOR_GETTER));
170 details->set(5, accessors->GetComponent(ACCESSOR_SETTER));
171 }
172
173 return *isolate->factory()->NewJSArrayWithElements(details);
174}
175
176
177RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
178 HandleScope scope(isolate);
179
180 DCHECK(args.length() == 2);
181
182 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
183 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
184
185 LookupIterator it(obj, name);
186 return *DebugGetProperty(&it);
187}
188
189
190// Return the property type calculated from the property details.
191// args[0]: smi with property details.
192RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
193 SealHandleScope shs(isolate);
194 DCHECK(args.length() == 1);
195 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
196 return Smi::FromInt(static_cast<int>(details.type()));
197}
198
199
200// Return the property attribute calculated from the property details.
201// args[0]: smi with property details.
202RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
203 SealHandleScope shs(isolate);
204 DCHECK(args.length() == 1);
205 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
206 return Smi::FromInt(static_cast<int>(details.attributes()));
207}
208
209
210// Return the property insertion index calculated from the property details.
211// args[0]: smi with property details.
212RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
213 SealHandleScope shs(isolate);
214 DCHECK(args.length() == 1);
215 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
216 // TODO(verwaest): Works only for dictionary mode holders.
217 return Smi::FromInt(details.dictionary_index());
218}
219
220
221// Return property value from named interceptor.
222// args[0]: object
223// args[1]: property name
224RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
225 HandleScope scope(isolate);
226 DCHECK(args.length() == 2);
227 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
228 RUNTIME_ASSERT(obj->HasNamedInterceptor());
229 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
230
231 Handle<Object> result;
232 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
233 JSObject::GetProperty(obj, name));
234 return *result;
235}
236
237
238// Return element value from indexed interceptor.
239// args[0]: object
240// args[1]: index
241RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
242 HandleScope scope(isolate);
243 DCHECK(args.length() == 2);
244 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
245 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
246 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
247 Handle<Object> result;
248 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
249 isolate, result,
250 JSObject::GetElementWithInterceptor(obj, obj, index, true));
251 return *result;
252}
253
254
255RUNTIME_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
264RUNTIME_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
290class 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
363static const int kFrameDetailsFrameIdIndex = 0;
364static const int kFrameDetailsReceiverIndex = 1;
365static const int kFrameDetailsFunctionIndex = 2;
366static const int kFrameDetailsArgumentCountIndex = 3;
367static const int kFrameDetailsLocalCountIndex = 4;
368static const int kFrameDetailsSourcePositionIndex = 5;
369static const int kFrameDetailsConstructCallIndex = 6;
370static const int kFrameDetailsAtReturnIndex = 7;
371static const int kFrameDetailsFlagsIndex = 8;
372static const int kFrameDetailsFirstDynamicIndex = 9;
373
374
375static 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.
388int Runtime::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
420RUNTIME_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 = Runtime::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
664static 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.
676MUST_USE_RESULT
677static 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
717static 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
758MUST_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
804MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScriptScope(
805 Handle<GlobalObject> global) {
806 Isolate* isolate = global->GetIsolate();
807 Handle<ScriptContextTable> script_contexts(
808 global->native_context()->script_context_table());
809
810 Handle<JSObject> script_scope =
811 isolate->factory()->NewJSObject(isolate->object_function());
812
813 for (int context_index = 0; context_index < script_contexts->used();
814 context_index++) {
815 Handle<Context> context =
816 ScriptContextTable::GetContext(script_contexts, context_index);
817 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
818 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
819 script_scope)) {
820 return MaybeHandle<JSObject>();
821 }
822 }
823 return script_scope;
824}
825
826
827MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
828 Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) {
829 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
830 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
831
832 Handle<JSObject> local_scope =
833 isolate->factory()->NewJSObject(isolate->object_function());
834 ASSIGN_RETURN_ON_EXCEPTION(
835 isolate, local_scope,
836 MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function,
837 &frame_inspector),
838 JSObject);
839
840 return MaterializeLocalContext(isolate, local_scope, function, frame);
841}
842
843
844// Set the context local variable value.
845static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info,
846 Handle<Context> context,
847 Handle<String> variable_name,
848 Handle<Object> new_value) {
849 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
850 Handle<String> next_name(scope_info->ContextLocalName(i));
851 if (String::Equals(variable_name, next_name)) {
852 VariableMode mode;
853 InitializationFlag init_flag;
854 MaybeAssignedFlag maybe_assigned_flag;
855 int context_index = ScopeInfo::ContextSlotIndex(
856 scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
857 context->set(context_index, *new_value);
858 return true;
859 }
860 }
861
862 return false;
863}
864
865
866static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
867 int inlined_jsframe_index,
868 Handle<String> variable_name,
869 Handle<Object> new_value) {
870 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
871 // Optimized frames are not supported.
872 return false;
873 }
874
875 Handle<JSFunction> function(frame->function());
876 Handle<SharedFunctionInfo> shared(function->shared());
877 Handle<ScopeInfo> scope_info(shared->scope_info());
878
879 bool default_result = false;
880
881 // Parameters.
882 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
883 HandleScope scope(isolate);
884 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
885 frame->SetParameterValue(i, *new_value);
886 // Argument might be shadowed in heap context, don't stop here.
887 default_result = true;
888 }
889 }
890
891 // Stack locals.
892 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
893 HandleScope scope(isolate);
894 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
895 frame->SetExpression(i, *new_value);
896 return true;
897 }
898 }
899
900 if (scope_info->HasContext()) {
901 // Context locals.
902 Handle<Context> frame_context(Context::cast(frame->context()));
903 Handle<Context> function_context(frame_context->declaration_context());
904 if (SetContextLocalValue(isolate, scope_info, function_context,
905 variable_name, new_value)) {
906 return true;
907 }
908
909 // Function context extension. These are variables introduced by eval.
910 if (function_context->closure() == *function) {
911 if (function_context->has_extension() &&
912 !function_context->IsNativeContext()) {
913 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
914
915 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
916 DCHECK(maybe.has_value);
917 if (maybe.value) {
918 // We don't expect this to do anything except replacing
919 // property value.
920 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
921 SLOPPY).Assert();
922 return true;
923 }
924 }
925 }
926 }
927
928 return default_result;
929}
930
931
932// Create a plain JSObject which materializes the closure content for the
933// context.
934MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure(
935 Isolate* isolate, Handle<Context> context) {
936 DCHECK(context->IsFunctionContext());
937
938 Handle<SharedFunctionInfo> shared(context->closure()->shared());
939 Handle<ScopeInfo> scope_info(shared->scope_info());
940
941 // Allocate and initialize a JSObject with all the content of this function
942 // closure.
943 Handle<JSObject> closure_scope =
944 isolate->factory()->NewJSObject(isolate->object_function());
945
946 // Fill all context locals to the context extension.
947 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
948 closure_scope)) {
949 return MaybeHandle<JSObject>();
950 }
951
952 // Finally copy any properties from the function context extension. This will
953 // be variables introduced by eval.
954 if (context->has_extension()) {
955 Handle<JSObject> ext(JSObject::cast(context->extension()));
956 Handle<FixedArray> keys;
957 ASSIGN_RETURN_ON_EXCEPTION(
958 isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
959 JSObject);
960
961 for (int i = 0; i < keys->length(); i++) {
962 HandleScope scope(isolate);
963 // Names of variables introduced by eval are strings.
964 DCHECK(keys->get(i)->IsString());
965 Handle<String> key(String::cast(keys->get(i)));
966 Handle<Object> value;
967 ASSIGN_RETURN_ON_EXCEPTION(
968 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
969 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
970 closure_scope, key, value, NONE),
971 JSObject);
972 }
973 }
974
975 return closure_scope;
976}
977
978
979// This method copies structure of MaterializeClosure method above.
980static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
981 Handle<String> variable_name,
982 Handle<Object> new_value) {
983 DCHECK(context->IsFunctionContext());
984
985 Handle<SharedFunctionInfo> shared(context->closure()->shared());
986 Handle<ScopeInfo> scope_info(shared->scope_info());
987
988 // Context locals to the context extension.
989 if (SetContextLocalValue(isolate, scope_info, context, variable_name,
990 new_value)) {
991 return true;
992 }
993
994 // Properties from the function context extension. This will
995 // be variables introduced by eval.
996 if (context->has_extension()) {
997 Handle<JSObject> ext(JSObject::cast(context->extension()));
998 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
999 DCHECK(maybe.has_value);
1000 if (maybe.value) {
1001 // We don't expect this to do anything except replacing property value.
1002 Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE)
1003 .Assert();
1004 return true;
1005 }
1006 }
1007
1008 return false;
1009}
1010
1011
1012static bool SetBlockContextVariableValue(Handle<Context> block_context,
1013 Handle<String> variable_name,
1014 Handle<Object> new_value) {
1015 DCHECK(block_context->IsBlockContext());
1016 Handle<ScopeInfo> scope_info(ScopeInfo::cast(block_context->extension()));
1017
1018 return SetContextLocalValue(block_context->GetIsolate(), scope_info,
1019 block_context, variable_name, new_value);
1020}
1021
1022
1023static bool SetScriptVariableValue(Handle<Context> context,
1024 Handle<String> variable_name,
1025 Handle<Object> new_value) {
1026 Handle<ScriptContextTable> script_contexts(
1027 context->global_object()->native_context()->script_context_table());
1028 ScriptContextTable::LookupResult lookup_result;
1029 if (ScriptContextTable::Lookup(script_contexts, variable_name,
1030 &lookup_result)) {
1031 Handle<Context> script_context = ScriptContextTable::GetContext(
1032 script_contexts, lookup_result.context_index);
1033 script_context->set(lookup_result.slot_index, *new_value);
1034 return true;
1035 }
1036
1037 return false;
1038}
1039
1040
1041// Create a plain JSObject which materializes the scope for the specified
1042// catch context.
1043MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope(
1044 Isolate* isolate, Handle<Context> context) {
1045 DCHECK(context->IsCatchContext());
1046 Handle<String> name(String::cast(context->extension()));
1047 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
1048 isolate);
1049 Handle<JSObject> catch_scope =
1050 isolate->factory()->NewJSObject(isolate->object_function());
1051 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
1052 catch_scope, name, thrown_object, NONE),
1053 JSObject);
1054 return catch_scope;
1055}
1056
1057
1058static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context,
1059 Handle<String> variable_name,
1060 Handle<Object> new_value) {
1061 DCHECK(context->IsCatchContext());
1062 Handle<String> name(String::cast(context->extension()));
1063 if (!String::Equals(name, variable_name)) {
1064 return false;
1065 }
1066 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
1067 return true;
1068}
1069
1070
1071// Create a plain JSObject which materializes the block scope for the specified
1072// block context.
1073MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope(
1074 Isolate* isolate, Handle<Context> context) {
1075 DCHECK(context->IsBlockContext());
1076 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
1077
1078 // Allocate and initialize a JSObject with all the arguments, stack locals
1079 // heap locals and extension properties of the debugged function.
1080 Handle<JSObject> block_scope =
1081 isolate->factory()->NewJSObject(isolate->object_function());
1082
1083 // Fill all context locals.
1084 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
1085 block_scope)) {
1086 return MaybeHandle<JSObject>();
1087 }
1088
1089 return block_scope;
1090}
1091
1092
1093// Create a plain JSObject which materializes the module scope for the specified
1094// module context.
1095MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
1096 Isolate* isolate, Handle<Context> context) {
1097 DCHECK(context->IsModuleContext());
1098 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
1099
1100 // Allocate and initialize a JSObject with all the members of the debugged
1101 // module.
1102 Handle<JSObject> module_scope =
1103 isolate->factory()->NewJSObject(isolate->object_function());
1104
1105 // Fill all context locals.
1106 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
1107 module_scope)) {
1108 return MaybeHandle<JSObject>();
1109 }
1110
1111 return module_scope;
1112}
1113
1114
1115// Iterate over the actual scopes visible from a stack frame or from a closure.
1116// The iteration proceeds from the innermost visible nested scope outwards.
1117// All scopes are backed by an actual context except the local scope,
1118// which is inserted "artificially" in the context chain.
1119class ScopeIterator {
1120 public:
1121 enum ScopeType {
1122 ScopeTypeGlobal = 0,
1123 ScopeTypeLocal,
1124 ScopeTypeWith,
1125 ScopeTypeClosure,
1126 ScopeTypeCatch,
1127 ScopeTypeBlock,
1128 ScopeTypeScript,
1129 ScopeTypeModule
1130 };
1131
1132 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame,
1133 int inlined_jsframe_index, bool ignore_nested_scopes = false)
1134 : isolate_(isolate),
1135 frame_(frame),
1136 inlined_jsframe_index_(inlined_jsframe_index),
1137 function_(frame->function()),
1138 context_(Context::cast(frame->context())),
1139 nested_scope_chain_(4),
1140 seen_script_scope_(false),
1141 failed_(false) {
1142 // Catch the case when the debugger stops in an internal function.
1143 Handle<SharedFunctionInfo> shared_info(function_->shared());
1144 Handle<ScopeInfo> scope_info(shared_info->scope_info());
1145 if (shared_info->script() == isolate->heap()->undefined_value()) {
1146 while (context_->closure() == *function_) {
1147 context_ = Handle<Context>(context_->previous(), isolate_);
1148 }
1149 return;
1150 }
1151
1152 // Get the debug info (create it if it does not exist).
1153 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
1154 // Return if ensuring debug info failed.
1155 return;
1156 }
1157
1158 // Currently it takes too much time to find nested scopes due to script
1159 // parsing. Sometimes we want to run the ScopeIterator as fast as possible
1160 // (for example, while collecting async call stacks on every
1161 // addEventListener call), even if we drop some nested scopes.
1162 // Later we may optimize getting the nested scopes (cache the result?)
1163 // and include nested scopes into the "fast" iteration case as well.
1164 if (!ignore_nested_scopes) {
1165 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
1166
1167 // Find the break point where execution has stopped.
1168 BreakLocationIterator break_location_iterator(debug_info,
1169 ALL_BREAK_LOCATIONS);
1170 // pc points to the instruction after the current one, possibly a break
1171 // location as well. So the "- 1" to exclude it from the search.
1172 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
1173
1174 // Within the return sequence at the moment it is not possible to
1175 // get a source position which is consistent with the current scope chain.
1176 // Thus all nested with, catch and block contexts are skipped and we only
1177 // provide the function scope.
1178 ignore_nested_scopes = break_location_iterator.IsExit();
1179 }
1180
1181 if (ignore_nested_scopes) {
1182 if (scope_info->HasContext()) {
1183 context_ = Handle<Context>(context_->declaration_context(), isolate_);
1184 } else {
1185 while (context_->closure() == *function_) {
1186 context_ = Handle<Context>(context_->previous(), isolate_);
1187 }
1188 }
1189 if (scope_info->scope_type() == FUNCTION_SCOPE ||
1190 scope_info->scope_type() == ARROW_SCOPE) {
1191 nested_scope_chain_.Add(scope_info);
1192 }
1193 } else {
1194 // Reparse the code and analyze the scopes.
1195 Handle<Script> script(Script::cast(shared_info->script()));
1196 Scope* scope = NULL;
1197
1198 // Check whether we are in global, eval or function code.
1199 Handle<ScopeInfo> scope_info(shared_info->scope_info());
1200 if (scope_info->scope_type() != FUNCTION_SCOPE &&
1201 scope_info->scope_type() != ARROW_SCOPE) {
1202 // Global or eval code.
1203 CompilationInfoWithZone info(script);
1204 if (scope_info->scope_type() == SCRIPT_SCOPE) {
1205 info.MarkAsGlobal();
1206 } else {
1207 DCHECK(scope_info->scope_type() == EVAL_SCOPE);
1208 info.MarkAsEval();
1209 info.SetContext(Handle<Context>(function_->context()));
1210 }
1211 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
1212 scope = info.function()->scope();
1213 }
1214 RetrieveScopeChain(scope, shared_info);
1215 } else {
1216 // Function code
1217 CompilationInfoWithZone info(shared_info);
1218 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
1219 scope = info.function()->scope();
1220 }
1221 RetrieveScopeChain(scope, shared_info);
1222 }
1223 }
1224 }
1225
1226 ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
1227 : isolate_(isolate),
1228 frame_(NULL),
1229 inlined_jsframe_index_(0),
1230 function_(function),
1231 context_(function->context()),
1232 seen_script_scope_(false),
1233 failed_(false) {
1234 if (function->IsBuiltin()) {
1235 context_ = Handle<Context>();
1236 }
1237 }
1238
1239 // More scopes?
1240 bool Done() {
1241 DCHECK(!failed_);
1242 return context_.is_null();
1243 }
1244
1245 bool Failed() { return failed_; }
1246
1247 // Move to the next scope.
1248 void Next() {
1249 DCHECK(!failed_);
1250 ScopeType scope_type = Type();
1251 if (scope_type == ScopeTypeGlobal) {
1252 // The global scope is always the last in the chain.
1253 DCHECK(context_->IsNativeContext());
1254 context_ = Handle<Context>();
1255 return;
1256 }
1257 if (scope_type == ScopeTypeScript) seen_script_scope_ = true;
1258 if (nested_scope_chain_.is_empty()) {
1259 if (scope_type == ScopeTypeScript) {
1260 if (context_->IsScriptContext()) {
1261 context_ = Handle<Context>(context_->previous(), isolate_);
1262 }
1263 CHECK(context_->IsNativeContext());
1264 } else {
1265 context_ = Handle<Context>(context_->previous(), isolate_);
1266 }
1267 } else {
1268 if (nested_scope_chain_.last()->HasContext()) {
1269 DCHECK(context_->previous() != NULL);
1270 context_ = Handle<Context>(context_->previous(), isolate_);
1271 }
1272 nested_scope_chain_.RemoveLast();
1273 }
1274 }
1275
1276 // Return the type of the current scope.
1277 ScopeType Type() {
1278 DCHECK(!failed_);
1279 if (!nested_scope_chain_.is_empty()) {
1280 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
1281 switch (scope_info->scope_type()) {
1282 case FUNCTION_SCOPE:
1283 case ARROW_SCOPE:
1284 DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
1285 return ScopeTypeLocal;
1286 case MODULE_SCOPE:
1287 DCHECK(context_->IsModuleContext());
1288 return ScopeTypeModule;
1289 case SCRIPT_SCOPE:
1290 DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
1291 return ScopeTypeScript;
1292 case WITH_SCOPE:
1293 DCHECK(context_->IsWithContext());
1294 return ScopeTypeWith;
1295 case CATCH_SCOPE:
1296 DCHECK(context_->IsCatchContext());
1297 return ScopeTypeCatch;
1298 case BLOCK_SCOPE:
1299 DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
1300 return ScopeTypeBlock;
1301 case EVAL_SCOPE:
1302 UNREACHABLE();
1303 }
1304 }
1305 if (context_->IsNativeContext()) {
1306 DCHECK(context_->global_object()->IsGlobalObject());
1307 // If we are at the native context and have not yet seen script scope,
1308 // fake it.
1309 return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
1310 }
1311 if (context_->IsFunctionContext()) {
1312 return ScopeTypeClosure;
1313 }
1314 if (context_->IsCatchContext()) {
1315 return ScopeTypeCatch;
1316 }
1317 if (context_->IsBlockContext()) {
1318 return ScopeTypeBlock;
1319 }
1320 if (context_->IsModuleContext()) {
1321 return ScopeTypeModule;
1322 }
1323 if (context_->IsScriptContext()) {
1324 return ScopeTypeScript;
1325 }
1326 DCHECK(context_->IsWithContext());
1327 return ScopeTypeWith;
1328 }
1329
1330 // Return the JavaScript object with the content of the current scope.
1331 MaybeHandle<JSObject> ScopeObject() {
1332 DCHECK(!failed_);
1333 switch (Type()) {
1334 case ScopeIterator::ScopeTypeGlobal:
1335 return Handle<JSObject>(CurrentContext()->global_object());
1336 case ScopeIterator::ScopeTypeScript:
1337 return MaterializeScriptScope(
1338 Handle<GlobalObject>(CurrentContext()->global_object()));
1339 case ScopeIterator::ScopeTypeLocal:
1340 // Materialize the content of the local scope into a JSObject.
1341 DCHECK(nested_scope_chain_.length() == 1);
1342 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
1343 case ScopeIterator::ScopeTypeWith:
1344 // Return the with object.
1345 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
1346 case ScopeIterator::ScopeTypeCatch:
1347 return MaterializeCatchScope(isolate_, CurrentContext());
1348 case ScopeIterator::ScopeTypeClosure:
1349 // Materialize the content of the closure scope into a JSObject.
1350 return MaterializeClosure(isolate_, CurrentContext());
1351 case ScopeIterator::ScopeTypeBlock:
1352 return MaterializeBlockScope(isolate_, CurrentContext());
1353 case ScopeIterator::ScopeTypeModule:
1354 return MaterializeModuleScope(isolate_, CurrentContext());
1355 }
1356 UNREACHABLE();
1357 return Handle<JSObject>();
1358 }
1359
1360 bool SetVariableValue(Handle<String> variable_name,
1361 Handle<Object> new_value) {
1362 DCHECK(!failed_);
1363 switch (Type()) {
1364 case ScopeIterator::ScopeTypeGlobal:
1365 break;
1366 case ScopeIterator::ScopeTypeLocal:
1367 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
1368 variable_name, new_value);
1369 case ScopeIterator::ScopeTypeWith:
1370 break;
1371 case ScopeIterator::ScopeTypeCatch:
1372 return SetCatchVariableValue(isolate_, CurrentContext(), variable_name,
1373 new_value);
1374 case ScopeIterator::ScopeTypeClosure:
1375 return SetClosureVariableValue(isolate_, CurrentContext(),
1376 variable_name, new_value);
1377 case ScopeIterator::ScopeTypeScript:
1378 return SetScriptVariableValue(CurrentContext(), variable_name,
1379 new_value);
1380 case ScopeIterator::ScopeTypeBlock:
1381 return SetBlockContextVariableValue(CurrentContext(), variable_name,
1382 new_value);
1383 case ScopeIterator::ScopeTypeModule:
1384 // TODO(2399): should we implement it?
1385 break;
1386 }
1387 return false;
1388 }
1389
1390 Handle<ScopeInfo> CurrentScopeInfo() {
1391 DCHECK(!failed_);
1392 if (!nested_scope_chain_.is_empty()) {
1393 return nested_scope_chain_.last();
1394 } else if (context_->IsBlockContext()) {
1395 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
1396 } else if (context_->IsFunctionContext()) {
1397 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
1398 }
1399 return Handle<ScopeInfo>::null();
1400 }
1401
1402 // Return the context for this scope. For the local context there might not
1403 // be an actual context.
1404 Handle<Context> CurrentContext() {
1405 DCHECK(!failed_);
1406 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
1407 nested_scope_chain_.is_empty()) {
1408 return context_;
1409 } else if (nested_scope_chain_.last()->HasContext()) {
1410 return context_;
1411 } else {
1412 return Handle<Context>();
1413 }
1414 }
1415
1416#ifdef DEBUG
1417 // Debug print of the content of the current scope.
1418 void DebugPrint() {
1419 OFStream os(stdout);
1420 DCHECK(!failed_);
1421 switch (Type()) {
1422 case ScopeIterator::ScopeTypeGlobal:
1423 os << "Global:\n";
1424 CurrentContext()->Print(os);
1425 break;
1426
1427 case ScopeIterator::ScopeTypeLocal: {
1428 os << "Local:\n";
1429 function_->shared()->scope_info()->Print();
1430 if (!CurrentContext().is_null()) {
1431 CurrentContext()->Print(os);
1432 if (CurrentContext()->has_extension()) {
1433 Handle<Object> extension(CurrentContext()->extension(), isolate_);
1434 if (extension->IsJSContextExtensionObject()) {
1435 extension->Print(os);
1436 }
1437 }
1438 }
1439 break;
1440 }
1441
1442 case ScopeIterator::ScopeTypeWith:
1443 os << "With:\n";
1444 CurrentContext()->extension()->Print(os);
1445 break;
1446
1447 case ScopeIterator::ScopeTypeCatch:
1448 os << "Catch:\n";
1449 CurrentContext()->extension()->Print(os);
1450 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
1451 break;
1452
1453 case ScopeIterator::ScopeTypeClosure:
1454 os << "Closure:\n";
1455 CurrentContext()->Print(os);
1456 if (CurrentContext()->has_extension()) {
1457 Handle<Object> extension(CurrentContext()->extension(), isolate_);
1458 if (extension->IsJSContextExtensionObject()) {
1459 extension->Print(os);
1460 }
1461 }
1462 break;
1463
1464 case ScopeIterator::ScopeTypeScript:
1465 os << "Script:\n";
1466 CurrentContext()
1467 ->global_object()
1468 ->native_context()
1469 ->script_context_table()
1470 ->Print(os);
1471 break;
1472
1473 default:
1474 UNREACHABLE();
1475 }
1476 PrintF("\n");
1477 }
1478#endif
1479
1480 private:
1481 Isolate* isolate_;
1482 JavaScriptFrame* frame_;
1483 int inlined_jsframe_index_;
1484 Handle<JSFunction> function_;
1485 Handle<Context> context_;
1486 List<Handle<ScopeInfo> > nested_scope_chain_;
1487 bool seen_script_scope_;
1488 bool failed_;
1489
1490 void RetrieveScopeChain(Scope* scope,
1491 Handle<SharedFunctionInfo> shared_info) {
1492 if (scope != NULL) {
1493 int source_position = shared_info->code()->SourcePosition(frame_->pc());
1494 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
1495 } else {
1496 // A failed reparse indicates that the preparser has diverged from the
1497 // parser or that the preparse data given to the initial parse has been
1498 // faulty. We fail in debug mode but in release mode we only provide the
1499 // information we get from the context chain but nothing about
1500 // completely stack allocated scopes or stack allocated locals.
1501 // Or it could be due to stack overflow.
1502 DCHECK(isolate_->has_pending_exception());
1503 failed_ = true;
1504 }
1505 }
1506
1507 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
1508};
1509
1510
1511RUNTIME_FUNCTION(Runtime_GetScopeCount) {
1512 HandleScope scope(isolate);
1513 DCHECK(args.length() == 2);
1514 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1515 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1516
1517 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1518
1519 // Get the frame where the debugging is performed.
1520 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1521 JavaScriptFrameIterator it(isolate, id);
1522 JavaScriptFrame* frame = it.frame();
1523
1524 // Count the visible scopes.
1525 int n = 0;
1526 for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
1527 n++;
1528 }
1529
1530 return Smi::FromInt(n);
1531}
1532
1533
1534// Returns the list of step-in positions (text offset) in a function of the
1535// stack frame in a range from the current debug break position to the end
1536// of the corresponding statement.
1537RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
1538 HandleScope scope(isolate);
1539 DCHECK(args.length() == 2);
1540 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1541 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1542
1543 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1544
1545 // Get the frame where the debugging is performed.
1546 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1547 JavaScriptFrameIterator frame_it(isolate, id);
1548 RUNTIME_ASSERT(!frame_it.done());
1549
1550 JavaScriptFrame* frame = frame_it.frame();
1551
1552 Handle<JSFunction> fun = Handle<JSFunction>(frame->function());
1553 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
1554
1555 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
1556 return isolate->heap()->undefined_value();
1557 }
1558
1559 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
1560
1561 int len = 0;
1562 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
1563 // Find the break point where execution has stopped.
1564 BreakLocationIterator break_location_iterator(debug_info,
1565 ALL_BREAK_LOCATIONS);
1566
1567 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
1568 int current_statement_pos = break_location_iterator.statement_position();
1569
1570 while (!break_location_iterator.Done()) {
1571 bool accept;
1572 if (break_location_iterator.pc() > frame->pc()) {
1573 accept = true;
1574 } else {
1575 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
1576 // The break point is near our pc. Could be a step-in possibility,
1577 // that is currently taken by active debugger call.
1578 if (break_frame_id == StackFrame::NO_ID) {
1579 // We are not stepping.
1580 accept = false;
1581 } else {
1582 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
1583 // If our frame is a top frame and we are stepping, we can do step-in
1584 // at this place.
1585 accept = additional_frame_it.frame()->id() == id;
1586 }
1587 }
1588 if (accept) {
1589 if (break_location_iterator.IsStepInLocation(isolate)) {
1590 Smi* position_value = Smi::FromInt(break_location_iterator.position());
1591 RETURN_FAILURE_ON_EXCEPTION(
1592 isolate, JSObject::SetElement(
1593 array, len, Handle<Object>(position_value, isolate),
1594 NONE, SLOPPY));
1595 len++;
1596 }
1597 }
1598 // Advance iterator.
1599 break_location_iterator.Next();
1600 if (current_statement_pos != break_location_iterator.statement_position()) {
1601 break;
1602 }
1603 }
1604 return *array;
1605}
1606
1607
1608static const int kScopeDetailsTypeIndex = 0;
1609static const int kScopeDetailsObjectIndex = 1;
1610static const int kScopeDetailsSize = 2;
1611
1612
1613MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
1614 Isolate* isolate, ScopeIterator* it) {
1615 // Calculate the size of the result.
1616 int details_size = kScopeDetailsSize;
1617 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
1618
1619 // Fill in scope details.
1620 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
1621 Handle<JSObject> scope_object;
1622 ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(),
1623 JSObject);
1624 details->set(kScopeDetailsObjectIndex, *scope_object);
1625
1626 return isolate->factory()->NewJSArrayWithElements(details);
1627}
1628
1629
1630// Return an array with scope details
1631// args[0]: number: break id
1632// args[1]: number: frame index
1633// args[2]: number: inlined frame index
1634// args[3]: number: scope index
1635//
1636// The array returned contains the following information:
1637// 0: Scope type
1638// 1: Scope object
1639RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
1640 HandleScope scope(isolate);
1641 DCHECK(args.length() == 4);
1642 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1643 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1644
1645 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1646 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1647 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
1648
1649 // Get the frame where the debugging is performed.
1650 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1651 JavaScriptFrameIterator frame_it(isolate, id);
1652 JavaScriptFrame* frame = frame_it.frame();
1653
1654 // Find the requested scope.
1655 int n = 0;
1656 ScopeIterator it(isolate, frame, inlined_jsframe_index);
1657 for (; !it.Done() && n < index; it.Next()) {
1658 n++;
1659 }
1660 if (it.Done()) {
1661 return isolate->heap()->undefined_value();
1662 }
1663 Handle<JSObject> details;
1664 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
1665 MaterializeScopeDetails(isolate, &it));
1666 return *details;
1667}
1668
1669
1670// Return an array of scope details
1671// args[0]: number: break id
1672// args[1]: number: frame index
1673// args[2]: number: inlined frame index
1674// args[3]: boolean: ignore nested scopes
1675//
1676// The array returned contains arrays with the following information:
1677// 0: Scope type
1678// 1: Scope object
1679RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
1680 HandleScope scope(isolate);
1681 DCHECK(args.length() == 3 || args.length() == 4);
1682 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1683 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1684
1685 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1686 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1687
1688 bool ignore_nested_scopes = false;
1689 if (args.length() == 4) {
1690 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
1691 ignore_nested_scopes = flag;
1692 }
1693
1694 // Get the frame where the debugging is performed.
1695 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1696 JavaScriptFrameIterator frame_it(isolate, id);
1697 JavaScriptFrame* frame = frame_it.frame();
1698
1699 List<Handle<JSObject> > result(4);
1700 ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
1701 for (; !it.Done(); it.Next()) {
1702 Handle<JSObject> details;
1703 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
1704 MaterializeScopeDetails(isolate, &it));
1705 result.Add(details);
1706 }
1707
1708 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
1709 for (int i = 0; i < result.length(); ++i) {
1710 array->set(i, *result[i]);
1711 }
1712 return *isolate->factory()->NewJSArrayWithElements(array);
1713}
1714
1715
1716RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
1717 HandleScope scope(isolate);
1718 DCHECK(args.length() == 1);
1719
1720 // Check arguments.
1721 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1722
1723 // Count the visible scopes.
1724 int n = 0;
1725 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
1726 n++;
1727 }
1728
1729 return Smi::FromInt(n);
1730}
1731
1732
1733RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
1734 HandleScope scope(isolate);
1735 DCHECK(args.length() == 2);
1736
1737 // Check arguments.
1738 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1739 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
1740
1741 // Find the requested scope.
1742 int n = 0;
1743 ScopeIterator it(isolate, fun);
1744 for (; !it.Done() && n < index; it.Next()) {
1745 n++;
1746 }
1747 if (it.Done()) {
1748 return isolate->heap()->undefined_value();
1749 }
1750
1751 Handle<JSObject> details;
1752 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
1753 MaterializeScopeDetails(isolate, &it));
1754 return *details;
1755}
1756
1757
1758static bool SetScopeVariableValue(ScopeIterator* it, int index,
1759 Handle<String> variable_name,
1760 Handle<Object> new_value) {
1761 for (int n = 0; !it->Done() && n < index; it->Next()) {
1762 n++;
1763 }
1764 if (it->Done()) {
1765 return false;
1766 }
1767 return it->SetVariableValue(variable_name, new_value);
1768}
1769
1770
1771// Change variable value in closure or local scope
1772// args[0]: number or JsFunction: break id or function
1773// args[1]: number: frame index (when arg[0] is break id)
1774// args[2]: number: inlined frame index (when arg[0] is break id)
1775// args[3]: number: scope index
1776// args[4]: string: variable name
1777// args[5]: object: new value
1778//
1779// Return true if success and false otherwise
1780RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
1781 HandleScope scope(isolate);
1782 DCHECK(args.length() == 6);
1783
1784 // Check arguments.
1785 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
1786 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
1787 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5);
1788
1789 bool res;
1790 if (args[0]->IsNumber()) {
1791 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1792 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1793
1794 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1795 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1796
1797 // Get the frame where the debugging is performed.
1798 StackFrame::Id id = UnwrapFrameId(wrapped_id);
1799 JavaScriptFrameIterator frame_it(isolate, id);
1800 JavaScriptFrame* frame = frame_it.frame();
1801
1802 ScopeIterator it(isolate, frame, inlined_jsframe_index);
1803 res = SetScopeVariableValue(&it, index, variable_name, new_value);
1804 } else {
1805 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1806 ScopeIterator it(isolate, fun);
1807 res = SetScopeVariableValue(&it, index, variable_name, new_value);
1808 }
1809
1810 return isolate->heap()->ToBoolean(res);
1811}
1812
1813
1814RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
1815 HandleScope scope(isolate);
1816 DCHECK(args.length() == 0);
1817
1818#ifdef DEBUG
1819 // Print the scopes for the top frame.
1820 StackFrameLocator locator(isolate);
1821 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
1822 for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
1823 it.DebugPrint();
1824 }
1825#endif
1826 return isolate->heap()->undefined_value();
1827}
1828
1829
1830RUNTIME_FUNCTION(Runtime_GetThreadCount) {
1831 HandleScope scope(isolate);
1832 DCHECK(args.length() == 1);
1833 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1834 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1835
1836 // Count all archived V8 threads.
1837 int n = 0;
1838 for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
1839 thread != NULL; thread = thread->Next()) {
1840 n++;
1841 }
1842
1843 // Total number of threads is current thread and archived threads.
1844 return Smi::FromInt(n + 1);
1845}
1846
1847
1848static const int kThreadDetailsCurrentThreadIndex = 0;
1849static const int kThreadDetailsThreadIdIndex = 1;
1850static const int kThreadDetailsSize = 2;
1851
1852// Return an array with thread details
1853// args[0]: number: break id
1854// args[1]: number: thread index
1855//
1856// The array returned contains the following information:
1857// 0: Is current thread?
1858// 1: Thread id
1859RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
1860 HandleScope scope(isolate);
1861 DCHECK(args.length() == 2);
1862 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1863 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1864
1865 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
1866
1867 // Allocate array for result.
1868 Handle<FixedArray> details =
1869 isolate->factory()->NewFixedArray(kThreadDetailsSize);
1870
1871 // Thread index 0 is current thread.
1872 if (index == 0) {
1873 // Fill the details.
1874 details->set(kThreadDetailsCurrentThreadIndex,
1875 isolate->heap()->true_value());
1876 details->set(kThreadDetailsThreadIdIndex,
1877 Smi::FromInt(ThreadId::Current().ToInteger()));
1878 } else {
1879 // Find the thread with the requested index.
1880 int n = 1;
1881 ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
1882 while (index != n && thread != NULL) {
1883 thread = thread->Next();
1884 n++;
1885 }
1886 if (thread == NULL) {
1887 return isolate->heap()->undefined_value();
1888 }
1889
1890 // Fill the details.
1891 details->set(kThreadDetailsCurrentThreadIndex,
1892 isolate->heap()->false_value());
1893 details->set(kThreadDetailsThreadIdIndex,
1894 Smi::FromInt(thread->id().ToInteger()));
1895 }
1896
1897 // Convert to JS array and return.
1898 return *isolate->factory()->NewJSArrayWithElements(details);
1899}
1900
1901
1902// Sets the disable break state
1903// args[0]: disable break state
1904RUNTIME_FUNCTION(Runtime_SetDisableBreak) {
1905 HandleScope scope(isolate);
1906 DCHECK(args.length() == 1);
1907 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
1908 isolate->debug()->set_disable_break(disable_break);
1909 return isolate->heap()->undefined_value();
1910}
1911
1912
1913static bool IsPositionAlignmentCodeCorrect(int alignment) {
1914 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
1915}
1916
1917
1918RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
1919 HandleScope scope(isolate);
1920 DCHECK(args.length() == 2);
1921
1922 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1923 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
1924
1925 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1926 return isolate->ThrowIllegalOperation();
1927 }
1928 BreakPositionAlignment alignment =
1929 static_cast<BreakPositionAlignment>(statement_aligned_code);
1930
1931 Handle<SharedFunctionInfo> shared(fun->shared());
1932 // Find the number of break points
1933 Handle<Object> break_locations =
1934 Debug::GetSourceBreakLocations(shared, alignment);
1935 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
1936 // Return array as JS array
1937 return *isolate->factory()->NewJSArrayWithElements(
1938 Handle<FixedArray>::cast(break_locations));
1939}
1940
1941
1942// Set a break point in a function.
1943// args[0]: function
1944// args[1]: number: break source position (within the function source)
1945// args[2]: number: break point object
1946RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
1947 HandleScope scope(isolate);
1948 DCHECK(args.length() == 3);
1949 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1950 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1951 RUNTIME_ASSERT(source_position >= function->shared()->start_position() &&
1952 source_position <= function->shared()->end_position());
1953 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
1954
1955 // Set break point.
1956 RUNTIME_ASSERT(isolate->debug()->SetBreakPoint(
1957 function, break_point_object_arg, &source_position));
1958
1959 return Smi::FromInt(source_position);
1960}
1961
1962
1963// Changes the state of a break point in a script and returns source position
1964// where break point was set. NOTE: Regarding performance see the NOTE for
1965// GetScriptFromScriptData.
1966// args[0]: script to set break point in
1967// args[1]: number: break source position (within the script source)
1968// args[2]: number, breakpoint position alignment
1969// args[3]: number: break point object
1970RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
1971 HandleScope scope(isolate);
1972 DCHECK(args.length() == 4);
1973 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
1974 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1975 RUNTIME_ASSERT(source_position >= 0);
1976 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
1977 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
1978
1979 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1980 return isolate->ThrowIllegalOperation();
1981 }
1982 BreakPositionAlignment alignment =
1983 static_cast<BreakPositionAlignment>(statement_aligned_code);
1984
1985 // Get the script from the script wrapper.
1986 RUNTIME_ASSERT(wrapper->value()->IsScript());
1987 Handle<Script> script(Script::cast(wrapper->value()));
1988
1989 // Set break point.
1990 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
1991 &source_position, alignment)) {
1992 return isolate->heap()->undefined_value();
1993 }
1994
1995 return Smi::FromInt(source_position);
1996}
1997
1998
1999// Clear a break point
2000// args[0]: number: break point object
2001RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
2002 HandleScope scope(isolate);
2003 DCHECK(args.length() == 1);
2004 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
2005
2006 // Clear break point.
2007 isolate->debug()->ClearBreakPoint(break_point_object_arg);
2008
2009 return isolate->heap()->undefined_value();
2010}
2011
2012
2013// Change the state of break on exceptions.
2014// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
2015// args[1]: Boolean indicating on/off.
2016RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) {
2017 HandleScope scope(isolate);
2018 DCHECK(args.length() == 2);
2019 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
2020 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
2021
2022 // If the number doesn't match an enum value, the ChangeBreakOnException
2023 // function will default to affecting caught exceptions.
2024 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
2025 // Update break point state.
2026 isolate->debug()->ChangeBreakOnException(type, enable);
2027 return isolate->heap()->undefined_value();
2028}
2029
2030
2031// Returns the state of break on exceptions
2032// args[0]: boolean indicating uncaught exceptions
2033RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
2034 HandleScope scope(isolate);
2035 DCHECK(args.length() == 1);
2036 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
2037
2038 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
2039 bool result = isolate->debug()->IsBreakOnException(type);
2040 return Smi::FromInt(result);
2041}
2042
2043
2044// Prepare for stepping
2045// args[0]: break id for checking execution state
2046// args[1]: step action from the enumeration StepAction
2047// args[2]: number of times to perform the step, for step out it is the number
2048// of frames to step down.
2049RUNTIME_FUNCTION(Runtime_PrepareStep) {
2050 HandleScope scope(isolate);
2051 DCHECK(args.length() == 4);
2052 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
2053 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
2054
2055 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
2056 return isolate->Throw(isolate->heap()->illegal_argument_string());
2057 }
2058
2059 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
2060
2061 StackFrame::Id frame_id;
2062 if (wrapped_frame_id == 0) {
2063 frame_id = StackFrame::NO_ID;
2064 } else {
2065 frame_id = UnwrapFrameId(wrapped_frame_id);
2066 }
2067
2068 // Get the step action and check validity.
2069 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
2070 if (step_action != StepIn && step_action != StepNext &&
2071 step_action != StepOut && step_action != StepInMin &&
2072 step_action != StepMin && step_action != StepFrame) {
2073 return isolate->Throw(isolate->heap()->illegal_argument_string());
2074 }
2075
2076 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
2077 step_action != StepMin && step_action != StepOut) {
2078 return isolate->ThrowIllegalOperation();
2079 }
2080
2081 // Get the number of steps.
2082 int step_count = NumberToInt32(args[2]);
2083 if (step_count < 1) {
2084 return isolate->Throw(isolate->heap()->illegal_argument_string());
2085 }
2086
2087 // Clear all current stepping setup.
2088 isolate->debug()->ClearStepping();
2089
2090 // Prepare step.
2091 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
2092 step_count, frame_id);
2093 return isolate->heap()->undefined_value();
2094}
2095
2096
2097// Clear all stepping set by PrepareStep.
2098RUNTIME_FUNCTION(Runtime_ClearStepping) {
2099 HandleScope scope(isolate);
2100 DCHECK(args.length() == 0);
2101 isolate->debug()->ClearStepping();
2102 return isolate->heap()->undefined_value();
2103}
2104
2105
2106// Helper function to find or create the arguments object for
2107// Runtime_DebugEvaluate.
2108MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
2109 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function) {
2110 // Do not materialize the arguments object for eval or top-level code.
2111 // Skip if "arguments" is already taken.
2112 if (!function->shared()->is_function()) return target;
2113 Maybe<bool> maybe = JSReceiver::HasOwnProperty(
2114 target, isolate->factory()->arguments_string());
2115 if (!maybe.has_value) return MaybeHandle<JSObject>();
2116 if (maybe.value) return target;
2117
2118 // FunctionGetArguments can't throw an exception.
2119 Handle<JSObject> arguments =
2120 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
2121 Handle<String> arguments_str = isolate->factory()->arguments_string();
2122 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
2123 target, arguments_str, arguments, NONE),
2124 JSObject);
2125 return target;
2126}
2127
2128
2129// Compile and evaluate source for the given context.
2130static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
2131 Handle<SharedFunctionInfo> outer_info,
2132 Handle<Context> context,
2133 Handle<Object> context_extension,
2134 Handle<Object> receiver,
2135 Handle<String> source) {
2136 if (context_extension->IsJSObject()) {
2137 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
2138 Handle<JSFunction> closure(context->closure(), isolate);
2139 context = isolate->factory()->NewWithContext(closure, context, extension);
2140 }
2141
2142 Handle<JSFunction> eval_fun;
2143 ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
2144 Compiler::GetFunctionFromEval(
2145 source, outer_info, context, SLOPPY,
2146 NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
2147 Object);
2148
2149 Handle<Object> result;
2150 ASSIGN_RETURN_ON_EXCEPTION(
2151 isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
2152 Object);
2153
2154 // Skip the global proxy as it has no properties and always delegates to the
2155 // real global object.
2156 if (result->IsJSGlobalProxy()) {
2157 PrototypeIterator iter(isolate, result);
2158 // TODO(verwaest): This will crash when the global proxy is detached.
2159 result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
2160 }
2161
2162 // Clear the oneshot breakpoints so that the debugger does not step further.
2163 isolate->debug()->ClearStepping();
2164 return result;
2165}
2166
2167
2168static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
2169 Handle<JSObject> result =
2170 isolate->factory()->NewJSObject(isolate->object_function());
2171 Handle<Map> new_map =
2172 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto");
2173 new_map->SetPrototype(isolate->factory()->null_value());
2174 JSObject::MigrateToMap(result, new_map);
2175 return result;
2176}
2177
2178
2179// Evaluate a piece of JavaScript in the context of a stack frame for
2180// debugging. Things that need special attention are:
2181// - Parameters and stack-allocated locals need to be materialized. Altered
2182// values need to be written back to the stack afterwards.
2183// - The arguments object needs to materialized.
2184RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
2185 HandleScope scope(isolate);
2186
2187 // Check the execution state and decode arguments frame and source to be
2188 // evaluated.
2189 DCHECK(args.length() == 6);
2190 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
2191 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
2192
2193 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
2194 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
2195 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
2196 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
2197 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
2198
2199 // Handle the processing of break.
2200 DisableBreak disable_break_scope(isolate->debug(), disable_break);
2201
2202 // Get the frame where the debugging is performed.
2203 StackFrame::Id id = UnwrapFrameId(wrapped_id);
2204 JavaScriptFrameIterator it(isolate, id);
2205 JavaScriptFrame* frame = it.frame();
2206 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
2207 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
2208 Handle<SharedFunctionInfo> outer_info(function->shared());
2209
2210 // Traverse the saved contexts chain to find the active context for the
2211 // selected frame.
2212 SaveContext* save = FindSavedContextForFrame(isolate, frame);
2213
2214 SaveContext savex(isolate);
2215 isolate->set_context(*(save->context()));
2216
2217 // Materialize stack locals and the arguments object.
2218 Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate);
2219
2220 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2221 isolate, materialized,
2222 MaterializeStackLocalsWithFrameInspector(isolate, materialized, function,
2223 &frame_inspector));
2224
2225 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2226 isolate, materialized,
2227 MaterializeArgumentsObject(isolate, materialized, function));
2228
2229 // At this point, the lookup chain may look like this:
2230 // [inner context] -> [function stack]+[function context] -> [outer context]
2231 // The function stack is not an actual context, it complements the function
2232 // context. In order to have the same lookup chain when debug-evaluating,
2233 // we materialize the stack and insert it into the context chain as a
2234 // with-context before the function context.
2235 // [inner context] -> [with context] -> [function context] -> [outer context]
2236 // Ordering the with-context before the function context forces a dynamic
2237 // lookup instead of a static lookup that could fail as the scope info is
2238 // outdated and may expect variables to still be stack-allocated.
2239 // Afterwards, we write changes to the with-context back to the stack
2240 // and remove it from the context chain.
2241 // This could cause lookup failures if debug-evaluate creates a closure that
2242 // uses this temporary context chain.
2243
2244 Handle<Context> eval_context(Context::cast(frame_inspector.GetContext()));
2245 DCHECK(!eval_context.is_null());
2246 Handle<Context> function_context = eval_context;
2247 Handle<Context> outer_context(function->context(), isolate);
2248 Handle<Context> inner_context;
2249 // We iterate to find the function's context. If the function has no
2250 // context-allocated variables, we iterate until we hit the outer context.
2251 while (!function_context->IsFunctionContext() &&
2252 !function_context->IsScriptContext() &&
2253 !function_context.is_identical_to(outer_context)) {
2254 inner_context = function_context;
2255 function_context = Handle<Context>(function_context->previous(), isolate);
2256 }
2257
2258 Handle<Context> materialized_context = isolate->factory()->NewWithContext(
2259 function, function_context, materialized);
2260
2261 if (inner_context.is_null()) {
2262 // No inner context. The with-context is now inner-most.
2263 eval_context = materialized_context;
2264 } else {
2265 inner_context->set_previous(*materialized_context);
2266 }
2267
2268 Handle<Object> receiver(frame->receiver(), isolate);
2269 MaybeHandle<Object> maybe_result = DebugEvaluate(
2270 isolate, outer_info, eval_context, context_extension, receiver, source);
2271
2272 // Remove with-context if it was inserted in between.
2273 if (!inner_context.is_null()) inner_context->set_previous(*function_context);
2274
2275 Handle<Object> result;
2276 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
2277
2278 // Write back potential changes to materialized stack locals to the stack.
2279 UpdateStackLocalsFromMaterializedObject(isolate, materialized, function,
2280 frame, inlined_jsframe_index);
2281
2282 return *result;
2283}
2284
2285
2286RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
2287 HandleScope scope(isolate);
2288
2289 // Check the execution state and decode arguments frame and source to be
2290 // evaluated.
2291 DCHECK(args.length() == 4);
2292 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
2293 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
2294
2295 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2296 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
2297 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
2298
2299 // Handle the processing of break.
2300 DisableBreak disable_break_scope(isolate->debug(), disable_break);
2301
2302 // Enter the top context from before the debugger was invoked.
2303 SaveContext save(isolate);
2304 SaveContext* top = &save;
2305 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
2306 top = top->prev();
2307 }
2308 if (top != NULL) {
2309 isolate->set_context(*top->context());
2310 }
2311
2312 // Get the native context now set to the top context from before the
2313 // debugger was invoked.
2314 Handle<Context> context = isolate->native_context();
2315 Handle<JSObject> receiver(context->global_proxy());
2316 Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
2317 Handle<Object> result;
2318 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2319 isolate, result, DebugEvaluate(isolate, outer_info, context,
2320 context_extension, receiver, source));
2321 return *result;
2322}
2323
2324
2325RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
2326 HandleScope scope(isolate);
2327 DCHECK(args.length() == 0);
2328
2329 // Fill the script objects.
2330 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
2331
2332 // Convert the script objects to proper JS objects.
2333 for (int i = 0; i < instances->length(); i++) {
2334 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
2335 // Get the script wrapper in a local handle before calling GetScriptWrapper,
2336 // because using
2337 // instances->set(i, *GetScriptWrapper(script))
2338 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
2339 // already have dereferenced the instances handle.
2340 Handle<JSObject> wrapper = Script::GetWrapper(script);
2341 instances->set(i, *wrapper);
2342 }
2343
2344 // Return result as a JS array.
2345 Handle<JSObject> result =
2346 isolate->factory()->NewJSObject(isolate->array_function());
2347 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
2348 return *result;
2349}
2350
2351
2352// Helper function used by Runtime_DebugReferencedBy below.
2353static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
2354 Object* instance_filter, int max_references,
2355 FixedArray* instances, int instances_size,
2356 JSFunction* arguments_function) {
2357 Isolate* isolate = target->GetIsolate();
2358 SealHandleScope shs(isolate);
2359 DisallowHeapAllocation no_allocation;
2360
2361 // Iterate the heap.
2362 int count = 0;
2363 JSObject* last = NULL;
2364 HeapObject* heap_obj = NULL;
2365 while (((heap_obj = iterator->next()) != NULL) &&
2366 (max_references == 0 || count < max_references)) {
2367 // Only look at all JSObjects.
2368 if (heap_obj->IsJSObject()) {
2369 // Skip context extension objects and argument arrays as these are
2370 // checked in the context of functions using them.
2371 JSObject* obj = JSObject::cast(heap_obj);
2372 if (obj->IsJSContextExtensionObject() ||
2373 obj->map()->constructor() == arguments_function) {
2374 continue;
2375 }
2376
2377 // Check if the JS object has a reference to the object looked for.
2378 if (obj->ReferencesObject(target)) {
2379 // Check instance filter if supplied. This is normally used to avoid
2380 // references from mirror objects (see Runtime_IsInPrototypeChain).
2381 if (!instance_filter->IsUndefined()) {
2382 for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
2383 iter.Advance()) {
2384 if (iter.GetCurrent() == instance_filter) {
2385 obj = NULL; // Don't add this object.
2386 break;
2387 }
2388 }
2389 }
2390
2391 if (obj != NULL) {
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 last = obj;
2398 count++;
2399 }
2400 }
2401 }
2402 }
2403
2404 // Check for circular reference only. This can happen when the object is only
2405 // referenced from mirrors and has a circular reference in which case the
2406 // object is not really alive and would have been garbage collected if not
2407 // referenced from the mirror.
2408 if (count == 1 && last == target) {
2409 count = 0;
2410 }
2411
2412 // Return the number of referencing objects found.
2413 return count;
2414}
2415
2416
2417// Scan the heap for objects with direct references to an object
2418// args[0]: the object to find references to
2419// args[1]: constructor function for instances to exclude (Mirror)
2420// args[2]: the the maximum number of objects to return
2421RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
2422 HandleScope scope(isolate);
2423 DCHECK(args.length() == 3);
2424
2425 // Check parameters.
2426 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
2427 CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
2428 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
2429 instance_filter->IsJSObject());
2430 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
2431 RUNTIME_ASSERT(max_references >= 0);
2432
2433
2434 // Get the constructor function for context extension and arguments array.
2435 Handle<JSFunction> arguments_function(
2436 JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
2437
2438 // Get the number of referencing objects.
2439 int count;
2440 // First perform a full GC in order to avoid dead objects and to make the heap
2441 // iterable.
2442 Heap* heap = isolate->heap();
2443 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
2444 {
2445 HeapIterator heap_iterator(heap);
2446 count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
2447 max_references, NULL, 0, *arguments_function);
2448 }
2449
2450 // Allocate an array to hold the result.
2451 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
2452
2453 // Fill the referencing objects.
2454 {
2455 HeapIterator heap_iterator(heap);
2456 count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
2457 max_references, *instances, count,
2458 *arguments_function);
2459 }
2460
2461 // Return result as JS array.
2462 Handle<JSFunction> constructor = isolate->array_function();
2463
2464 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
2465 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
2466 return *result;
2467}
2468
2469
2470// Helper function used by Runtime_DebugConstructedBy below.
2471static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
2472 int max_references, FixedArray* instances,
2473 int instances_size) {
2474 DisallowHeapAllocation no_allocation;
2475
2476 // Iterate the heap.
2477 int count = 0;
2478 HeapObject* heap_obj = NULL;
2479 while (((heap_obj = iterator->next()) != NULL) &&
2480 (max_references == 0 || count < max_references)) {
2481 // Only look at all JSObjects.
2482 if (heap_obj->IsJSObject()) {
2483 JSObject* obj = JSObject::cast(heap_obj);
2484 if (obj->map()->constructor() == constructor) {
2485 // Valid reference found add to instance array if supplied an update
2486 // count.
2487 if (instances != NULL && count < instances_size) {
2488 instances->set(count, obj);
2489 }
2490 count++;
2491 }
2492 }
2493 }
2494
2495 // Return the number of referencing objects found.
2496 return count;
2497}
2498
2499
2500// Scan the heap for objects constructed by a specific function.
2501// args[0]: the constructor to find instances of
2502// args[1]: the the maximum number of objects to return
2503RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
2504 HandleScope scope(isolate);
2505 DCHECK(args.length() == 2);
2506
2507
2508 // Check parameters.
2509 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
2510 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
2511 RUNTIME_ASSERT(max_references >= 0);
2512
2513 // Get the number of referencing objects.
2514 int count;
2515 // First perform a full GC in order to avoid dead objects and to make the heap
2516 // iterable.
2517 Heap* heap = isolate->heap();
2518 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
2519 {
2520 HeapIterator heap_iterator(heap);
2521 count = DebugConstructedBy(&heap_iterator, *constructor, max_references,
2522 NULL, 0);
2523 }
2524
2525 // Allocate an array to hold the result.
2526 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
2527
2528 // Fill the referencing objects.
2529 {
2530 HeapIterator heap_iterator2(heap);
2531 count = DebugConstructedBy(&heap_iterator2, *constructor, max_references,
2532 *instances, count);
2533 }
2534
2535 // Return result as JS array.
2536 Handle<JSFunction> array_function = isolate->array_function();
2537 Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
2538 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
2539 return *result;
2540}
2541
2542
2543// Find the effective prototype object as returned by __proto__.
2544// args[0]: the object to find the prototype for.
2545RUNTIME_FUNCTION(Runtime_DebugGetPrototype) {
2546 HandleScope shs(isolate);
2547 DCHECK(args.length() == 1);
2548 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
2549 return *Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
2550}
2551
2552
2553// Patches script source (should be called upon BeforeCompile event).
2554RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
2555 HandleScope scope(isolate);
2556 DCHECK(args.length() == 2);
2557
2558 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
2559 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
2560
2561 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
2562 Handle<Script> script(Script::cast(script_wrapper->value()));
2563
2564 int compilation_state = script->compilation_state();
2565 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
2566 script->set_source(*source);
2567
2568 return isolate->heap()->undefined_value();
2569}
2570
2571
2572RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
2573 HandleScope scope(isolate);
2574#ifdef DEBUG
2575 DCHECK(args.length() == 1);
2576 // Get the function and make sure it is compiled.
2577 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
2578 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
2579 return isolate->heap()->exception();
2580 }
2581 OFStream os(stdout);
2582 func->code()->Print(os);
2583 os << std::endl;
2584#endif // DEBUG
2585 return isolate->heap()->undefined_value();
2586}
2587
2588
2589RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) {
2590 HandleScope scope(isolate);
2591#ifdef DEBUG
2592 DCHECK(args.length() == 1);
2593 // Get the function and make sure it is compiled.
2594 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
2595 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
2596 return isolate->heap()->exception();
2597 }
2598 OFStream os(stdout);
2599 func->shared()->construct_stub()->Print(os);
2600 os << std::endl;
2601#endif // DEBUG
2602 return isolate->heap()->undefined_value();
2603}
2604
2605
2606RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
2607 SealHandleScope shs(isolate);
2608 DCHECK(args.length() == 1);
2609
2610 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2611 return f->shared()->inferred_name();
2612}
2613
2614
2615// A testing entry. Returns statement position which is the closest to
2616// source_position.
2617RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
2618 HandleScope scope(isolate);
2619 CHECK(isolate->debug()->live_edit_enabled());
2620 DCHECK(args.length() == 2);
2621 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
2622 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
2623
2624 Handle<Code> code(function->code(), isolate);
2625
2626 if (code->kind() != Code::FUNCTION &&
2627 code->kind() != Code::OPTIMIZED_FUNCTION) {
2628 return isolate->heap()->undefined_value();
2629 }
2630
2631 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
2632 int closest_pc = 0;
2633 int distance = kMaxInt;
2634 while (!it.done()) {
2635 int statement_position = static_cast<int>(it.rinfo()->data());
2636 // Check if this break point is closer that what was previously found.
2637 if (source_position <= statement_position &&
2638 statement_position - source_position < distance) {
2639 closest_pc =
2640 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
2641 distance = statement_position - source_position;
2642 // Check whether we can't get any closer.
2643 if (distance == 0) break;
2644 }
2645 it.next();
2646 }
2647
2648 return Smi::FromInt(closest_pc);
2649}
2650
2651
2652// Calls specified function with or without entering the debugger.
2653// This is used in unit tests to run code as if debugger is entered or simply
2654// to have a stack with C++ frame in the middle.
2655RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
2656 HandleScope scope(isolate);
2657 DCHECK(args.length() == 2);
2658 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
2659 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
2660
2661 MaybeHandle<Object> maybe_result;
2662 if (without_debugger) {
2663 maybe_result = Execution::Call(isolate, function,
2664 handle(function->global_proxy()), 0, NULL);
2665 } else {
2666 DebugScope debug_scope(isolate->debug());
2667 maybe_result = Execution::Call(isolate, function,
2668 handle(function->global_proxy()), 0, NULL);
2669 }
2670 Handle<Object> result;
2671 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
2672 return *result;
2673}
2674
2675
2676// Performs a GC.
2677// Presently, it only does a full GC.
2678RUNTIME_FUNCTION(Runtime_CollectGarbage) {
2679 SealHandleScope shs(isolate);
2680 DCHECK(args.length() == 1);
2681 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
2682 return isolate->heap()->undefined_value();
2683}
2684
2685
2686// Gets the current heap usage.
2687RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
2688 SealHandleScope shs(isolate);
2689 DCHECK(args.length() == 0);
2690 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
2691 if (!Smi::IsValid(usage)) {
2692 return *isolate->factory()->NewNumberFromInt(usage);
2693 }
2694 return Smi::FromInt(usage);
2695}
2696
2697
2698// Finds the script object from the script data. NOTE: This operation uses
2699// heap traversal to find the function generated for the source position
2700// for the requested break point. For lazily compiled functions several heap
2701// traversals might be required rendering this operation as a rather slow
2702// operation. However for setting break points which is normally done through
2703// some kind of user interaction the performance is not crucial.
2704RUNTIME_FUNCTION(Runtime_GetScript) {
2705 HandleScope scope(isolate);
2706 DCHECK(args.length() == 1);
2707 CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0);
2708
2709 Handle<Script> found;
2710 Heap* heap = isolate->heap();
2711 {
2712 HeapIterator iterator(heap);
2713 HeapObject* obj = NULL;
2714 while ((obj = iterator.next()) != NULL) {
2715 if (!obj->IsScript()) continue;
2716 Script* script = Script::cast(obj);
2717 if (!script->name()->IsString()) continue;
2718 String* name = String::cast(script->name());
2719 if (name->Equals(*script_name)) {
2720 found = Handle<Script>(script, isolate);
2721 break;
2722 }
2723 }
2724 }
2725
2726 if (found.is_null()) return heap->undefined_value();
2727 return *Script::GetWrapper(found);
2728}
2729
2730
2731// Check whether debugger and is about to step into the callback that is passed
2732// to a built-in function such as Array.forEach.
2733RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
2734 DCHECK(args.length() == 1);
2735 Debug* debug = isolate->debug();
2736 if (!debug->is_active() || !debug->IsStepping() ||
2737 debug->last_step_action() != StepIn) {
2738 return isolate->heap()->false_value();
2739 }
2740 CONVERT_ARG_CHECKED(Object, callback, 0);
2741 // We do not step into the callback if it's a builtin or not even a function.
2742 return isolate->heap()->ToBoolean(callback->IsJSFunction() &&
2743 !JSFunction::cast(callback)->IsBuiltin());
2744}
2745
2746
2747// Set one shot breakpoints for the callback function that is passed to a
2748// built-in function such as Array.forEach to enable stepping into the callback.
2749RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
2750 DCHECK(args.length() == 1);
2751 Debug* debug = isolate->debug();
2752 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
2753
2754 HandleScope scope(isolate);
2755 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
2756 RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject());
2757 Handle<JSFunction> fun;
2758 if (object->IsJSFunction()) {
2759 fun = Handle<JSFunction>::cast(object);
2760 } else {
2761 fun = Handle<JSFunction>(
2762 Handle<JSGeneratorObject>::cast(object)->function(), isolate);
2763 }
2764 // When leaving the function, step out has been activated, but not performed
2765 // if we do not leave the builtin. To be able to step into the function
2766 // again, we need to clear the step out at this point.
2767 debug->ClearStepOut();
2768 debug->FloodWithOneShot(fun);
2769 return isolate->heap()->undefined_value();
2770}
2771
2772
2773RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
2774 DCHECK(args.length() == 1);
2775 HandleScope scope(isolate);
2776 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
2777 isolate->PushPromise(promise);
2778 return isolate->heap()->undefined_value();
2779}
2780
2781
2782RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
2783 DCHECK(args.length() == 0);
2784 SealHandleScope shs(isolate);
2785 isolate->PopPromise();
2786 return isolate->heap()->undefined_value();
2787}
2788
2789
2790RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
2791 DCHECK(args.length() == 1);
2792 HandleScope scope(isolate);
2793 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
2794 isolate->debug()->OnPromiseEvent(data);
2795 return isolate->heap()->undefined_value();
2796}
2797
2798
2799RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
2800 DCHECK(args.length() == 1);
2801 HandleScope scope(isolate);
2802 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
2803 isolate->debug()->OnAsyncTaskEvent(data);
2804 return isolate->heap()->undefined_value();
2805}
2806
2807
2808RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) {
2809 SealHandleScope shs(isolate);
2810 return Smi::FromInt(isolate->debug()->is_active());
2811}
2812
2813
2814RUNTIME_FUNCTION(RuntimeReference_DebugBreakInOptimizedCode) {
2815 UNIMPLEMENTED();
2816 return NULL;
2817}
2818}
2819} // namespace v8::internal