blob: c29ea9a35d5e7379fff5b567cce19d1167f614a8 [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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005#include "src/runtime/runtime-utils.h"
6
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/arguments.h"
8#include "src/debug/debug.h"
9#include "src/debug/debug-evaluate.h"
10#include "src/debug/debug-frames.h"
11#include "src/debug/debug-scopes.h"
12#include "src/frames-inl.h"
13#include "src/isolate-inl.h"
14#include "src/runtime/runtime.h"
15
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016namespace v8 {
17namespace internal {
18
19RUNTIME_FUNCTION(Runtime_DebugBreak) {
20 SealHandleScope shs(isolate);
21 DCHECK(args.length() == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022 // Get the top-most JavaScript frame.
23 JavaScriptFrameIterator it(isolate);
24 isolate->debug()->Break(args, it.frame());
Ben Murdoch097c5b22016-05-18 11:27:45 +010025 return isolate->debug()->SetAfterBreakTarget(it.frame());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040026}
27
28
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
30 SealHandleScope shs(isolate);
31 DCHECK(args.length() == 0);
32 if (isolate->debug()->break_points_active()) {
33 isolate->debug()->HandleDebugBreak();
34 }
35 return isolate->heap()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036}
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056RUNTIME_FUNCTION(Runtime_ScheduleBreak) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040057 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;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 case LookupIterator::INTEGER_INDEXED_EXOTIC:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040075 case LookupIterator::INTERCEPTOR:
76 case LookupIterator::JSPROXY:
77 return it->isolate()->factory()->undefined_value();
78 case LookupIterator::ACCESSOR: {
79 Handle<Object> accessors = it->GetAccessors();
80 if (!accessors->IsAccessorInfo()) {
81 return it->isolate()->factory()->undefined_value();
82 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 MaybeHandle<Object> maybe_result =
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 JSObject::GetPropertyWithAccessor(it);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103static Handle<Object> DebugGetProperty(Handle<Object> object,
104 Handle<Name> name) {
105 LookupIterator it(object, name);
106 return DebugGetProperty(&it);
107}
108
109
110template <class IteratorType>
111static MaybeHandle<JSArray> GetIteratorInternalProperties(
112 Isolate* isolate, Handle<IteratorType> object) {
113 Factory* factory = isolate->factory();
114 Handle<IteratorType> iterator = Handle<IteratorType>::cast(object);
115 RUNTIME_ASSERT_HANDLIFIED(iterator->kind()->IsSmi(), JSArray);
116 const char* kind = NULL;
117 switch (Smi::cast(iterator->kind())->value()) {
118 case IteratorType::kKindKeys:
119 kind = "keys";
120 break;
121 case IteratorType::kKindValues:
122 kind = "values";
123 break;
124 case IteratorType::kKindEntries:
125 kind = "entries";
126 break;
127 default:
128 RUNTIME_ASSERT_HANDLIFIED(false, JSArray);
129 }
130
131 Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
132 Handle<String> has_more =
133 factory->NewStringFromAsciiChecked("[[IteratorHasMore]]");
134 result->set(0, *has_more);
135 result->set(1, isolate->heap()->ToBoolean(iterator->HasMore()));
136
137 Handle<String> index =
138 factory->NewStringFromAsciiChecked("[[IteratorIndex]]");
139 result->set(2, *index);
140 result->set(3, iterator->index());
141
142 Handle<String> iterator_kind =
143 factory->NewStringFromAsciiChecked("[[IteratorKind]]");
144 result->set(4, *iterator_kind);
145 Handle<String> kind_str = factory->NewStringFromAsciiChecked(kind);
146 result->set(5, *kind_str);
147 return factory->NewJSArrayWithElements(result);
148}
149
150
151MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
152 Handle<Object> object) {
153 Factory* factory = isolate->factory();
154 if (object->IsJSBoundFunction()) {
155 Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object);
156
157 Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
158 Handle<String> target =
159 factory->NewStringFromAsciiChecked("[[TargetFunction]]");
160 result->set(0, *target);
161 result->set(1, function->bound_target_function());
162
163 Handle<String> bound_this =
164 factory->NewStringFromAsciiChecked("[[BoundThis]]");
165 result->set(2, *bound_this);
166 result->set(3, function->bound_this());
167
168 Handle<String> bound_args =
169 factory->NewStringFromAsciiChecked("[[BoundArgs]]");
170 result->set(4, *bound_args);
171 Handle<FixedArray> bound_arguments =
172 factory->CopyFixedArray(handle(function->bound_arguments(), isolate));
173 Handle<JSArray> arguments_array =
174 factory->NewJSArrayWithElements(bound_arguments);
175 result->set(5, *arguments_array);
176 return factory->NewJSArrayWithElements(result);
177 } else if (object->IsJSMapIterator()) {
178 Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object);
179 return GetIteratorInternalProperties(isolate, iterator);
180 } else if (object->IsJSSetIterator()) {
181 Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object);
182 return GetIteratorInternalProperties(isolate, iterator);
183 } else if (object->IsJSGeneratorObject()) {
184 Handle<JSGeneratorObject> generator =
185 Handle<JSGeneratorObject>::cast(object);
186
187 const char* status = "suspended";
188 if (generator->is_closed()) {
189 status = "closed";
190 } else if (generator->is_executing()) {
191 status = "running";
192 } else {
193 DCHECK(generator->is_suspended());
194 }
195
196 Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
197 Handle<String> generator_status =
198 factory->NewStringFromAsciiChecked("[[GeneratorStatus]]");
199 result->set(0, *generator_status);
200 Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
201 result->set(1, *status_str);
202
203 Handle<String> function =
204 factory->NewStringFromAsciiChecked("[[GeneratorFunction]]");
205 result->set(2, *function);
206 result->set(3, generator->function());
207
208 Handle<String> receiver =
209 factory->NewStringFromAsciiChecked("[[GeneratorReceiver]]");
210 result->set(4, *receiver);
211 result->set(5, generator->receiver());
212 return factory->NewJSArrayWithElements(result);
213 } else if (Object::IsPromise(object)) {
214 Handle<JSObject> promise = Handle<JSObject>::cast(object);
215
216 Handle<Object> status_obj =
217 DebugGetProperty(promise, isolate->factory()->promise_status_symbol());
218 RUNTIME_ASSERT_HANDLIFIED(status_obj->IsSmi(), JSArray);
219 const char* status = "rejected";
220 int status_val = Handle<Smi>::cast(status_obj)->value();
221 switch (status_val) {
222 case +1:
223 status = "resolved";
224 break;
225 case 0:
226 status = "pending";
227 break;
228 default:
229 DCHECK_EQ(-1, status_val);
230 }
231
232 Handle<FixedArray> result = factory->NewFixedArray(2 * 2);
233 Handle<String> promise_status =
234 factory->NewStringFromAsciiChecked("[[PromiseStatus]]");
235 result->set(0, *promise_status);
236 Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
237 result->set(1, *status_str);
238
239 Handle<Object> value_obj =
240 DebugGetProperty(promise, isolate->factory()->promise_value_symbol());
241 Handle<String> promise_value =
242 factory->NewStringFromAsciiChecked("[[PromiseValue]]");
243 result->set(2, *promise_value);
244 result->set(3, *value_obj);
245 return factory->NewJSArrayWithElements(result);
246 } else if (object->IsJSValue()) {
247 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
248
249 Handle<FixedArray> result = factory->NewFixedArray(2);
250 Handle<String> primitive_value =
251 factory->NewStringFromAsciiChecked("[[PrimitiveValue]]");
252 result->set(0, *primitive_value);
253 result->set(1, js_value->value());
254 return factory->NewJSArrayWithElements(result);
255 }
256 return factory->NewJSArray(0);
257}
258
259
260RUNTIME_FUNCTION(Runtime_DebugGetInternalProperties) {
261 HandleScope scope(isolate);
262 DCHECK(args.length() == 1);
263 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
264 Handle<JSArray> result;
265 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
266 isolate, result, Runtime::GetInternalProperties(isolate, obj));
267 return *result;
268}
269
270
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400271// Get debugger related details for an object property, in the following format:
272// 0: Property value
273// 1: Property details
274// 2: Property value is exception
275// 3: Getter function if defined
276// 4: Setter function if defined
277// Items 2-4 are only filled if the property has either a getter or a setter.
278RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
279 HandleScope scope(isolate);
280
281 DCHECK(args.length() == 2);
282
283 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
284 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
285
286 // Make sure to set the current context to the context before the debugger was
287 // entered (if the debugger is entered). The reason for switching context here
288 // is that for some property lookups (accessors and interceptors) callbacks
289 // into the embedding application can occour, and the embedding application
290 // could have the assumption that its own native context is the current
291 // context and not some internal debugger context.
292 SaveContext save(isolate);
293 if (isolate->debug()->in_debug_scope()) {
294 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
295 }
296
297 // Check if the name is trivially convertible to an index and get the element
298 // if so.
299 uint32_t index;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 // TODO(verwaest): Make sure DebugGetProperty can handle arrays, and remove
301 // this special case.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400302 if (name->AsArrayIndex(&index)) {
303 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
304 Handle<Object> element_or_char;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_or_char,
306 Object::GetElement(isolate, obj, index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307 details->set(0, *element_or_char);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308 details->set(1, PropertyDetails::Empty().AsSmi());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400309 return *isolate->factory()->NewJSArrayWithElements(details);
310 }
311
312 LookupIterator it(obj, name, LookupIterator::HIDDEN);
313 bool has_caught = false;
314 Handle<Object> value = DebugGetProperty(&it, &has_caught);
315 if (!it.IsFound()) return isolate->heap()->undefined_value();
316
317 Handle<Object> maybe_pair;
318 if (it.state() == LookupIterator::ACCESSOR) {
319 maybe_pair = it.GetAccessors();
320 }
321
322 // If the callback object is a fixed array then it contains JavaScript
323 // getter and/or setter.
324 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair();
325 Handle<FixedArray> details =
326 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3);
327 details->set(0, *value);
328 // TODO(verwaest): Get rid of this random way of handling interceptors.
329 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000330 ? PropertyDetails::Empty()
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400331 : it.property_details();
332 details->set(1, d.AsSmi());
333 details->set(
334 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
335 if (has_js_accessors) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100336 Handle<AccessorPair> accessors = Handle<AccessorPair>::cast(maybe_pair);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400337 details->set(3, isolate->heap()->ToBoolean(has_caught));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100338 Handle<Object> getter =
339 AccessorPair::GetComponent(accessors, ACCESSOR_GETTER);
340 Handle<Object> setter =
341 AccessorPair::GetComponent(accessors, ACCESSOR_SETTER);
342 details->set(4, *getter);
343 details->set(5, *setter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 }
345
346 return *isolate->factory()->NewJSArrayWithElements(details);
347}
348
349
350RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
351 HandleScope scope(isolate);
352
353 DCHECK(args.length() == 2);
354
355 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
356 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
357
358 LookupIterator it(obj, name);
359 return *DebugGetProperty(&it);
360}
361
362
363// Return the property type calculated from the property details.
364// args[0]: smi with property details.
365RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
366 SealHandleScope shs(isolate);
367 DCHECK(args.length() == 1);
368 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
369 return Smi::FromInt(static_cast<int>(details.type()));
370}
371
372
373// Return the property attribute calculated from the property details.
374// args[0]: smi with property details.
375RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
376 SealHandleScope shs(isolate);
377 DCHECK(args.length() == 1);
378 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
379 return Smi::FromInt(static_cast<int>(details.attributes()));
380}
381
382
383// Return the property insertion index calculated from the property details.
384// args[0]: smi with property details.
385RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
386 SealHandleScope shs(isolate);
387 DCHECK(args.length() == 1);
388 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
389 // TODO(verwaest): Works only for dictionary mode holders.
390 return Smi::FromInt(details.dictionary_index());
391}
392
393
394// Return property value from named interceptor.
395// args[0]: object
396// args[1]: property name
397RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
398 HandleScope scope(isolate);
399 DCHECK(args.length() == 2);
400 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
401 RUNTIME_ASSERT(obj->HasNamedInterceptor());
402 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
403
404 Handle<Object> result;
405 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
406 JSObject::GetProperty(obj, name));
407 return *result;
408}
409
410
411// Return element value from indexed interceptor.
412// args[0]: object
413// args[1]: index
414RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
415 HandleScope scope(isolate);
416 DCHECK(args.length() == 2);
417 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
418 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
419 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
420 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
422 Object::GetElement(isolate, obj, index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400423 return *result;
424}
425
426
427RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
428 SealHandleScope shs(isolate);
429 DCHECK(args.length() == 1);
430 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
431 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
432 return isolate->heap()->true_value();
433}
434
435
436RUNTIME_FUNCTION(Runtime_GetFrameCount) {
437 HandleScope scope(isolate);
438 DCHECK(args.length() == 1);
439 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
440 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
441
442 // Count all frames which are relevant to debugging stack trace.
443 int n = 0;
444 StackFrame::Id id = isolate->debug()->break_frame_id();
445 if (id == StackFrame::NO_ID) {
446 // If there is no JavaScript stack frame count is 0.
447 return Smi::FromInt(0);
448 }
449
450 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
451 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
452 it.frame()->Summarize(&frames);
453 for (int i = frames.length() - 1; i >= 0; i--) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454 // Omit functions from native and extension scripts.
455 if (frames[i].function()->shared()->IsSubjectToDebugging()) n++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400456 }
457 }
458 return Smi::FromInt(n);
459}
460
461
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400462static const int kFrameDetailsFrameIdIndex = 0;
463static const int kFrameDetailsReceiverIndex = 1;
464static const int kFrameDetailsFunctionIndex = 2;
465static const int kFrameDetailsArgumentCountIndex = 3;
466static const int kFrameDetailsLocalCountIndex = 4;
467static const int kFrameDetailsSourcePositionIndex = 5;
468static const int kFrameDetailsConstructCallIndex = 6;
469static const int kFrameDetailsAtReturnIndex = 7;
470static const int kFrameDetailsFlagsIndex = 8;
471static const int kFrameDetailsFirstDynamicIndex = 9;
472
473
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400474// Return an array with frame details
475// args[0]: number: break id
476// args[1]: number: frame index
477//
478// The array returned contains the following information:
479// 0: Frame id
480// 1: Receiver
481// 2: Function
482// 3: Argument count
483// 4: Local count
484// 5: Source position
485// 6: Constructor call
486// 7: Is at return
487// 8: Flags
488// Arguments name, value
489// Locals name, value
490// Return value if any
491RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
492 HandleScope scope(isolate);
493 DCHECK(args.length() == 2);
494 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
495 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
496
497 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
498 Heap* heap = isolate->heap();
499
500 // Find the relevant frame with the requested index.
501 StackFrame::Id id = isolate->debug()->break_frame_id();
502 if (id == StackFrame::NO_ID) {
503 // If there are no JavaScript stack frames return undefined.
504 return heap->undefined_value();
505 }
506
507 JavaScriptFrameIterator it(isolate, id);
508 // Inlined frame index in optimized frame, starting from outer function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000509 int inlined_jsframe_index =
510 DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400511 if (inlined_jsframe_index == -1) return heap->undefined_value();
512
513 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
514 bool is_optimized = it.frame()->is_optimized();
515
516 // Traverse the saved contexts chain to find the active context for the
517 // selected frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000518 SaveContext* save =
519 DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400520
521 // Get the frame id.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522 Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()),
523 isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400524
525 // Find source position in unoptimized code.
526 int position = frame_inspector.GetSourcePosition();
527
528 // Check for constructor frame.
529 bool constructor = frame_inspector.IsConstructor();
530
531 // Get scope info and read from it for local variable information.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100532 Handle<JSFunction> function =
533 Handle<JSFunction>::cast(frame_inspector.GetFunction());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 RUNTIME_ASSERT(function->shared()->IsSubjectToDebugging());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400535 Handle<SharedFunctionInfo> shared(function->shared());
536 Handle<ScopeInfo> scope_info(shared->scope_info());
537 DCHECK(*scope_info != ScopeInfo::Empty(isolate));
538
539 // Get the locals names and values into a temporary array.
540 int local_count = scope_info->LocalCount();
541 for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
542 // Hide compiler-introduced temporary variables, whether on the stack or on
543 // the context.
544 if (scope_info->LocalIsSynthetic(slot)) local_count--;
545 }
546
547 Handle<FixedArray> locals =
548 isolate->factory()->NewFixedArray(local_count * 2);
549
550 // Fill in the values of the locals.
551 int local = 0;
552 int i = 0;
553 for (; i < scope_info->StackLocalCount(); ++i) {
554 // Use the value from the stack.
555 if (scope_info->LocalIsSynthetic(i)) continue;
556 locals->set(local * 2, scope_info->LocalName(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100557 locals->set(local * 2 + 1, *(frame_inspector.GetExpression(i)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400558 local++;
559 }
560 if (local < local_count) {
561 // Get the context containing declarations.
562 Handle<Context> context(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563 Handle<Context>::cast(frame_inspector.GetContext())->closure_context());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400564 for (; i < scope_info->LocalCount(); ++i) {
565 if (scope_info->LocalIsSynthetic(i)) continue;
566 Handle<String> name(scope_info->LocalName(i));
567 VariableMode mode;
568 InitializationFlag init_flag;
569 MaybeAssignedFlag maybe_assigned_flag;
570 locals->set(local * 2, *name);
571 int context_slot_index = ScopeInfo::ContextSlotIndex(
572 scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
573 Object* value = context->get(context_slot_index);
574 locals->set(local * 2 + 1, value);
575 local++;
576 }
577 }
578
579 // Check whether this frame is positioned at return. If not top
580 // frame or if the frame is optimized it cannot be at a return.
581 bool at_return = false;
582 if (!is_optimized && index == 0) {
583 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
584 }
585
586 // If positioned just before return find the value to be returned and add it
587 // to the frame information.
588 Handle<Object> return_value = isolate->factory()->undefined_value();
589 if (at_return) {
590 StackFrameIterator it2(isolate);
591 Address internal_frame_sp = NULL;
592 while (!it2.done()) {
593 if (it2.frame()->is_internal()) {
594 internal_frame_sp = it2.frame()->sp();
595 } else {
596 if (it2.frame()->is_java_script()) {
597 if (it2.frame()->id() == it.frame()->id()) {
598 // The internal frame just before the JavaScript frame contains the
599 // value to return on top. A debug break at return will create an
600 // internal frame to store the return value (eax/rax/r0) before
601 // entering the debug break exit frame.
602 if (internal_frame_sp != NULL) {
603 return_value =
604 Handle<Object>(Memory::Object_at(internal_frame_sp), isolate);
605 break;
606 }
607 }
608 }
609
610 // Indicate that the previous frame was not an internal frame.
611 internal_frame_sp = NULL;
612 }
613 it2.Advance();
614 }
615 }
616
617 // Now advance to the arguments adapter frame (if any). It contains all
618 // the provided parameters whereas the function frame always have the number
619 // of arguments matching the functions parameters. The rest of the
620 // information (except for what is collected above) is the same.
621 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
622 it.AdvanceToArgumentsFrame();
623 frame_inspector.SetArgumentsFrame(it.frame());
624 }
625
626 // Find the number of arguments to fill. At least fill the number of
627 // parameters for the function and fill more if more parameters are provided.
628 int argument_count = scope_info->ParameterCount();
629 if (argument_count < frame_inspector.GetParametersCount()) {
630 argument_count = frame_inspector.GetParametersCount();
631 }
632
633 // Calculate the size of the result.
634 int details_size = kFrameDetailsFirstDynamicIndex +
635 2 * (argument_count + local_count) + (at_return ? 1 : 0);
636 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
637
638 // Add the frame id.
639 details->set(kFrameDetailsFrameIdIndex, *frame_id);
640
641 // Add the function (same as in function frame).
Ben Murdoch097c5b22016-05-18 11:27:45 +0100642 details->set(kFrameDetailsFunctionIndex, *(frame_inspector.GetFunction()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400643
644 // Add the arguments count.
645 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
646
647 // Add the locals count
648 details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count));
649
650 // Add the source position.
651 if (position != RelocInfo::kNoPosition) {
652 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
653 } else {
654 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
655 }
656
657 // Add the constructor information.
658 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
659
660 // Add the at return information.
661 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
662
663 // Add flags to indicate information on whether this frame is
664 // bit 0: invoked in the debugger context.
665 // bit 1: optimized frame.
666 // bit 2: inlined in optimized frame
667 int flags = 0;
668 if (*save->context() == *isolate->debug()->debug_context()) {
669 flags |= 1 << 0;
670 }
671 if (is_optimized) {
672 flags |= 1 << 1;
673 flags |= inlined_jsframe_index << 2;
674 }
675 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
676
677 // Fill the dynamic part.
678 int details_index = kFrameDetailsFirstDynamicIndex;
679
680 // Add arguments name and value.
681 for (int i = 0; i < argument_count; i++) {
682 // Name of the argument.
683 if (i < scope_info->ParameterCount()) {
684 details->set(details_index++, scope_info->ParameterName(i));
685 } else {
686 details->set(details_index++, heap->undefined_value());
687 }
688
689 // Parameter value.
690 if (i < frame_inspector.GetParametersCount()) {
691 // Get the value from the stack.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100692 details->set(details_index++, *(frame_inspector.GetParameter(i)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400693 } else {
694 details->set(details_index++, heap->undefined_value());
695 }
696 }
697
698 // Add locals name and value from the temporary copy from the function frame.
699 for (int i = 0; i < local_count * 2; i++) {
700 details->set(details_index++, locals->get(i));
701 }
702
703 // Add the value being returned.
704 if (at_return) {
705 details->set(details_index++, *return_value);
706 }
707
708 // Add the receiver (same as in function frame).
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400709 Handle<Object> receiver(it.frame()->receiver(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000710 DCHECK(!function->shared()->IsBuiltin());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100711 DCHECK_IMPLIES(is_sloppy(shared->language_mode()), receiver->IsJSReceiver());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400712 details->set(kFrameDetailsReceiverIndex, *receiver);
713
714 DCHECK_EQ(details_size, details_index);
715 return *isolate->factory()->NewJSArrayWithElements(details);
716}
717
718
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400719RUNTIME_FUNCTION(Runtime_GetScopeCount) {
720 HandleScope scope(isolate);
721 DCHECK(args.length() == 2);
722 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
723 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
724
725 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
726
727 // Get the frame where the debugging is performed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400729 JavaScriptFrameIterator it(isolate, id);
730 JavaScriptFrame* frame = it.frame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 FrameInspector frame_inspector(frame, 0, isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400732
733 // Count the visible scopes.
734 int n = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400736 n++;
737 }
738
739 return Smi::FromInt(n);
740}
741
742
743// Returns the list of step-in positions (text offset) in a function of the
744// stack frame in a range from the current debug break position to the end
745// of the corresponding statement.
746RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
747 HandleScope scope(isolate);
748 DCHECK(args.length() == 2);
749 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
750 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
751
752 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
753
754 // Get the frame where the debugging is performed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000755 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400756 JavaScriptFrameIterator frame_it(isolate, id);
757 RUNTIME_ASSERT(!frame_it.done());
758
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000759 List<int> positions;
760 isolate->debug()->GetStepinPositions(frame_it.frame(), id, &positions);
761 Factory* factory = isolate->factory();
762 Handle<FixedArray> array = factory->NewFixedArray(positions.length());
763 for (int i = 0; i < positions.length(); ++i) {
764 array->set(i, Smi::FromInt(positions[i]));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400765 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000766 return *factory->NewJSArrayWithElements(array, FAST_SMI_ELEMENTS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400767}
768
769
770// Return an array with scope details
771// args[0]: number: break id
772// args[1]: number: frame index
773// args[2]: number: inlined frame index
774// args[3]: number: scope index
775//
776// The array returned contains the following information:
777// 0: Scope type
778// 1: Scope object
779RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
780 HandleScope scope(isolate);
781 DCHECK(args.length() == 4);
782 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
783 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
784
785 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
786 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
787 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
788
789 // Get the frame where the debugging is performed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400791 JavaScriptFrameIterator frame_it(isolate, id);
792 JavaScriptFrame* frame = frame_it.frame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400794
795 // Find the requested scope.
796 int n = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 ScopeIterator it(isolate, &frame_inspector);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400798 for (; !it.Done() && n < index; it.Next()) {
799 n++;
800 }
801 if (it.Done()) {
802 return isolate->heap()->undefined_value();
803 }
804 Handle<JSObject> details;
805 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 it.MaterializeScopeDetails());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400807 return *details;
808}
809
810
811// Return an array of scope details
812// args[0]: number: break id
813// args[1]: number: frame index
814// args[2]: number: inlined frame index
815// args[3]: boolean: ignore nested scopes
816//
817// The array returned contains arrays with the following information:
818// 0: Scope type
819// 1: Scope object
820RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
821 HandleScope scope(isolate);
822 DCHECK(args.length() == 3 || args.length() == 4);
823 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
824 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
825
826 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
827 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 ScopeIterator::Option option = ScopeIterator::DEFAULT;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400830 if (args.length() == 4) {
831 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832 if (flag) option = ScopeIterator::IGNORE_NESTED_SCOPES;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400833 }
834
835 // Get the frame where the debugging is performed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000836 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400837 JavaScriptFrameIterator frame_it(isolate, id);
838 JavaScriptFrame* frame = frame_it.frame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000839 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400840
841 List<Handle<JSObject> > result(4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000842 ScopeIterator it(isolate, &frame_inspector, option);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400843 for (; !it.Done(); it.Next()) {
844 Handle<JSObject> details;
845 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000846 it.MaterializeScopeDetails());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400847 result.Add(details);
848 }
849
850 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
851 for (int i = 0; i < result.length(); ++i) {
852 array->set(i, *result[i]);
853 }
854 return *isolate->factory()->NewJSArrayWithElements(array);
855}
856
857
858RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
859 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000860 DCHECK_EQ(1, args.length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400861
862 // Check arguments.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000863 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400864
865 // Count the visible scopes.
866 int n = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000867 if (function->IsJSFunction()) {
868 for (ScopeIterator it(isolate, Handle<JSFunction>::cast(function));
869 !it.Done(); it.Next()) {
870 n++;
871 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400872 }
873
874 return Smi::FromInt(n);
875}
876
877
878RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
879 HandleScope scope(isolate);
880 DCHECK(args.length() == 2);
881
882 // Check arguments.
883 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
884 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
885
886 // Find the requested scope.
887 int n = 0;
888 ScopeIterator it(isolate, fun);
889 for (; !it.Done() && n < index; it.Next()) {
890 n++;
891 }
892 if (it.Done()) {
893 return isolate->heap()->undefined_value();
894 }
895
896 Handle<JSObject> details;
897 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 it.MaterializeScopeDetails());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400899 return *details;
900}
901
902
903static bool SetScopeVariableValue(ScopeIterator* it, int index,
904 Handle<String> variable_name,
905 Handle<Object> new_value) {
906 for (int n = 0; !it->Done() && n < index; it->Next()) {
907 n++;
908 }
909 if (it->Done()) {
910 return false;
911 }
912 return it->SetVariableValue(variable_name, new_value);
913}
914
915
916// Change variable value in closure or local scope
917// args[0]: number or JsFunction: break id or function
918// args[1]: number: frame index (when arg[0] is break id)
919// args[2]: number: inlined frame index (when arg[0] is break id)
920// args[3]: number: scope index
921// args[4]: string: variable name
922// args[5]: object: new value
923//
924// Return true if success and false otherwise
925RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
926 HandleScope scope(isolate);
927 DCHECK(args.length() == 6);
928
929 // Check arguments.
930 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
931 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
932 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5);
933
934 bool res;
935 if (args[0]->IsNumber()) {
936 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
937 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
938
939 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
940 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
941
942 // Get the frame where the debugging is performed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000943 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400944 JavaScriptFrameIterator frame_it(isolate, id);
945 JavaScriptFrame* frame = frame_it.frame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000946 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400947
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000948 ScopeIterator it(isolate, &frame_inspector);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400949 res = SetScopeVariableValue(&it, index, variable_name, new_value);
950 } else {
951 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
952 ScopeIterator it(isolate, fun);
953 res = SetScopeVariableValue(&it, index, variable_name, new_value);
954 }
955
956 return isolate->heap()->ToBoolean(res);
957}
958
959
960RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
961 HandleScope scope(isolate);
962 DCHECK(args.length() == 0);
963
964#ifdef DEBUG
965 // Print the scopes for the top frame.
966 StackFrameLocator locator(isolate);
967 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000968 FrameInspector frame_inspector(frame, 0, isolate);
969
970 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400971 it.DebugPrint();
972 }
973#endif
974 return isolate->heap()->undefined_value();
975}
976
977
978RUNTIME_FUNCTION(Runtime_GetThreadCount) {
979 HandleScope scope(isolate);
980 DCHECK(args.length() == 1);
981 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
982 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
983
984 // Count all archived V8 threads.
985 int n = 0;
986 for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
987 thread != NULL; thread = thread->Next()) {
988 n++;
989 }
990
991 // Total number of threads is current thread and archived threads.
992 return Smi::FromInt(n + 1);
993}
994
995
996static const int kThreadDetailsCurrentThreadIndex = 0;
997static const int kThreadDetailsThreadIdIndex = 1;
998static const int kThreadDetailsSize = 2;
999
1000// Return an array with thread details
1001// args[0]: number: break id
1002// args[1]: number: thread index
1003//
1004// The array returned contains the following information:
1005// 0: Is current thread?
1006// 1: Thread id
1007RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
1008 HandleScope scope(isolate);
1009 DCHECK(args.length() == 2);
1010 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1011 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1012
1013 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
1014
1015 // Allocate array for result.
1016 Handle<FixedArray> details =
1017 isolate->factory()->NewFixedArray(kThreadDetailsSize);
1018
1019 // Thread index 0 is current thread.
1020 if (index == 0) {
1021 // Fill the details.
1022 details->set(kThreadDetailsCurrentThreadIndex,
1023 isolate->heap()->true_value());
1024 details->set(kThreadDetailsThreadIdIndex,
1025 Smi::FromInt(ThreadId::Current().ToInteger()));
1026 } else {
1027 // Find the thread with the requested index.
1028 int n = 1;
1029 ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
1030 while (index != n && thread != NULL) {
1031 thread = thread->Next();
1032 n++;
1033 }
1034 if (thread == NULL) {
1035 return isolate->heap()->undefined_value();
1036 }
1037
1038 // Fill the details.
1039 details->set(kThreadDetailsCurrentThreadIndex,
1040 isolate->heap()->false_value());
1041 details->set(kThreadDetailsThreadIdIndex,
1042 Smi::FromInt(thread->id().ToInteger()));
1043 }
1044
1045 // Convert to JS array and return.
1046 return *isolate->factory()->NewJSArrayWithElements(details);
1047}
1048
1049
1050// Sets the disable break state
1051// args[0]: disable break state
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001052RUNTIME_FUNCTION(Runtime_SetBreakPointsActive) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001053 HandleScope scope(isolate);
1054 DCHECK(args.length() == 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001055 CONVERT_BOOLEAN_ARG_CHECKED(active, 0);
1056 isolate->debug()->set_break_points_active(active);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001057 return isolate->heap()->undefined_value();
1058}
1059
1060
1061static bool IsPositionAlignmentCodeCorrect(int alignment) {
1062 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
1063}
1064
1065
1066RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
1067 HandleScope scope(isolate);
1068 DCHECK(args.length() == 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001069 RUNTIME_ASSERT(isolate->debug()->is_active());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001070 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1071 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
1072
1073 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1074 return isolate->ThrowIllegalOperation();
1075 }
1076 BreakPositionAlignment alignment =
1077 static_cast<BreakPositionAlignment>(statement_aligned_code);
1078
1079 Handle<SharedFunctionInfo> shared(fun->shared());
1080 // Find the number of break points
1081 Handle<Object> break_locations =
1082 Debug::GetSourceBreakLocations(shared, alignment);
1083 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
1084 // Return array as JS array
1085 return *isolate->factory()->NewJSArrayWithElements(
1086 Handle<FixedArray>::cast(break_locations));
1087}
1088
1089
1090// Set a break point in a function.
1091// args[0]: function
1092// args[1]: number: break source position (within the function source)
1093// args[2]: number: break point object
1094RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
1095 HandleScope scope(isolate);
1096 DCHECK(args.length() == 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001097 RUNTIME_ASSERT(isolate->debug()->is_active());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001098 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1099 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1100 RUNTIME_ASSERT(source_position >= function->shared()->start_position() &&
1101 source_position <= function->shared()->end_position());
1102 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
1103
1104 // Set break point.
1105 RUNTIME_ASSERT(isolate->debug()->SetBreakPoint(
1106 function, break_point_object_arg, &source_position));
1107
1108 return Smi::FromInt(source_position);
1109}
1110
1111
1112// Changes the state of a break point in a script and returns source position
1113// where break point was set. NOTE: Regarding performance see the NOTE for
1114// GetScriptFromScriptData.
1115// args[0]: script to set break point in
1116// args[1]: number: break source position (within the script source)
1117// args[2]: number, breakpoint position alignment
1118// args[3]: number: break point object
1119RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
1120 HandleScope scope(isolate);
1121 DCHECK(args.length() == 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001122 RUNTIME_ASSERT(isolate->debug()->is_active());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001123 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
1124 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1125 RUNTIME_ASSERT(source_position >= 0);
1126 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
1127 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
1128
1129 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1130 return isolate->ThrowIllegalOperation();
1131 }
1132 BreakPositionAlignment alignment =
1133 static_cast<BreakPositionAlignment>(statement_aligned_code);
1134
1135 // Get the script from the script wrapper.
1136 RUNTIME_ASSERT(wrapper->value()->IsScript());
1137 Handle<Script> script(Script::cast(wrapper->value()));
1138
1139 // Set break point.
1140 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
1141 &source_position, alignment)) {
1142 return isolate->heap()->undefined_value();
1143 }
1144
1145 return Smi::FromInt(source_position);
1146}
1147
1148
1149// Clear a break point
1150// args[0]: number: break point object
1151RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
1152 HandleScope scope(isolate);
1153 DCHECK(args.length() == 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154 RUNTIME_ASSERT(isolate->debug()->is_active());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001155 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
1156
1157 // Clear break point.
1158 isolate->debug()->ClearBreakPoint(break_point_object_arg);
1159
1160 return isolate->heap()->undefined_value();
1161}
1162
1163
1164// Change the state of break on exceptions.
1165// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
1166// args[1]: Boolean indicating on/off.
1167RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) {
1168 HandleScope scope(isolate);
1169 DCHECK(args.length() == 2);
1170 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
1171 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
1172
1173 // If the number doesn't match an enum value, the ChangeBreakOnException
1174 // function will default to affecting caught exceptions.
1175 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
1176 // Update break point state.
1177 isolate->debug()->ChangeBreakOnException(type, enable);
1178 return isolate->heap()->undefined_value();
1179}
1180
1181
1182// Returns the state of break on exceptions
1183// args[0]: boolean indicating uncaught exceptions
1184RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
1185 HandleScope scope(isolate);
1186 DCHECK(args.length() == 1);
1187 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
1188
1189 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
1190 bool result = isolate->debug()->IsBreakOnException(type);
1191 return Smi::FromInt(result);
1192}
1193
1194
1195// Prepare for stepping
1196// args[0]: break id for checking execution state
1197// args[1]: step action from the enumeration StepAction
1198// args[2]: number of times to perform the step, for step out it is the number
1199// of frames to step down.
1200RUNTIME_FUNCTION(Runtime_PrepareStep) {
1201 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 DCHECK(args.length() == 2);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001203 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1204 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1205
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001206 if (!args[1]->IsNumber()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001207 return isolate->Throw(isolate->heap()->illegal_argument_string());
1208 }
1209
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001210 // Get the step action and check validity.
1211 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
1212 if (step_action != StepIn && step_action != StepNext &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001213 step_action != StepOut && step_action != StepFrame) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001214 return isolate->Throw(isolate->heap()->illegal_argument_string());
1215 }
1216
1217 // Clear all current stepping setup.
1218 isolate->debug()->ClearStepping();
1219
1220 // Prepare step.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001221 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001222 return isolate->heap()->undefined_value();
1223}
1224
1225
1226// Clear all stepping set by PrepareStep.
1227RUNTIME_FUNCTION(Runtime_ClearStepping) {
1228 HandleScope scope(isolate);
1229 DCHECK(args.length() == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230 RUNTIME_ASSERT(isolate->debug()->is_active());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001231 isolate->debug()->ClearStepping();
1232 return isolate->heap()->undefined_value();
1233}
1234
1235
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001236RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
1237 HandleScope scope(isolate);
1238
1239 // Check the execution state and decode arguments frame and source to be
1240 // evaluated.
1241 DCHECK(args.length() == 6);
1242 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1243 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1244
1245 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1246 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1247 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
1248 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001249 CONVERT_ARG_HANDLE_CHECKED(HeapObject, context_extension, 5);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001250
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001251 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001252
1253 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001254 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1255 isolate, result,
1256 DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source,
1257 disable_break, context_extension));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001258 return *result;
1259}
1260
1261
1262RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
1263 HandleScope scope(isolate);
1264
1265 // Check the execution state and decode arguments frame and source to be
1266 // evaluated.
1267 DCHECK(args.length() == 4);
1268 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1269 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
1270
1271 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
1272 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 CONVERT_ARG_HANDLE_CHECKED(HeapObject, context_extension, 3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001274
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001275 Handle<Object> result;
1276 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001277 isolate, result,
1278 DebugEvaluate::Global(isolate, source, disable_break, context_extension));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001279 return *result;
1280}
1281
1282
1283RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
1284 HandleScope scope(isolate);
1285 DCHECK(args.length() == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286 RUNTIME_ASSERT(isolate->debug()->is_active());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001288 Handle<FixedArray> instances;
1289 {
1290 DebugScope debug_scope(isolate->debug());
1291 if (debug_scope.failed()) {
1292 DCHECK(isolate->has_pending_exception());
1293 return isolate->heap()->exception();
1294 }
1295 // Fill the script objects.
1296 instances = isolate->debug()->GetLoadedScripts();
1297 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001298
1299 // Convert the script objects to proper JS objects.
1300 for (int i = 0; i < instances->length(); i++) {
1301 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
1302 // Get the script wrapper in a local handle before calling GetScriptWrapper,
1303 // because using
1304 // instances->set(i, *GetScriptWrapper(script))
1305 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
1306 // already have dereferenced the instances handle.
1307 Handle<JSObject> wrapper = Script::GetWrapper(script);
1308 instances->set(i, *wrapper);
1309 }
1310
1311 // Return result as a JS array.
1312 Handle<JSObject> result =
1313 isolate->factory()->NewJSObject(isolate->array_function());
1314 JSArray::SetContent(Handle<JSArray>::cast(result), instances);
1315 return *result;
1316}
1317
Ben Murdoch097c5b22016-05-18 11:27:45 +01001318static bool HasInPrototypeChainIgnoringProxies(Isolate* isolate,
1319 JSObject* object,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320 Object* proto) {
1321 PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
1322 while (true) {
1323 iter.AdvanceIgnoringProxies();
1324 if (iter.IsAtEnd()) return false;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001325 if (iter.GetCurrent() == proto) return true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001326 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001327}
1328
1329
1330// Scan the heap for objects with direct references to an object
1331// args[0]: the object to find references to
1332// args[1]: constructor function for instances to exclude (Mirror)
1333// args[2]: the the maximum number of objects to return
1334RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
1335 HandleScope scope(isolate);
1336 DCHECK(args.length() == 3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001337 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001338 CONVERT_ARG_HANDLE_CHECKED(Object, filter, 1);
1339 RUNTIME_ASSERT(filter->IsUndefined() || filter->IsJSObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001340 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
1341 RUNTIME_ASSERT(max_references >= 0);
1342
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001343 List<Handle<JSObject> > instances;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001344 Heap* heap = isolate->heap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001345 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001346 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
1347 // Get the constructor function for context extension and arguments array.
1348 Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor();
1349 HeapObject* heap_obj;
1350 while ((heap_obj = iterator.next())) {
1351 if (!heap_obj->IsJSObject()) continue;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001352 JSObject* obj = JSObject::cast(heap_obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 if (obj->IsJSContextExtensionObject()) continue;
1354 if (obj->map()->GetConstructor() == arguments_fun) continue;
1355 if (!obj->ReferencesObject(*target)) continue;
1356 // Check filter if supplied. This is normally used to avoid
1357 // references from mirror objects.
1358 if (!filter->IsUndefined() &&
1359 HasInPrototypeChainIgnoringProxies(isolate, obj, *filter)) {
1360 continue;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001361 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001362 if (obj->IsJSGlobalObject()) {
1363 obj = JSGlobalObject::cast(obj)->global_proxy();
1364 }
1365 instances.Add(Handle<JSObject>(obj));
1366 if (instances.length() == max_references) break;
1367 }
1368 // Iterate the rest of the heap to satisfy HeapIterator constraints.
1369 while (iterator.next()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001370 }
1371 }
1372
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001373 Handle<FixedArray> result;
1374 if (instances.length() == 1 && instances.last().is_identical_to(target)) {
1375 // Check for circular reference only. This can happen when the object is
1376 // only referenced from mirrors and has a circular reference in which case
1377 // the object is not really alive and would have been garbage collected if
1378 // not referenced from the mirror.
1379 result = isolate->factory()->empty_fixed_array();
1380 } else {
1381 result = isolate->factory()->NewFixedArray(instances.length());
1382 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
1383 }
1384 return *isolate->factory()->NewJSArrayWithElements(result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001385}
1386
1387
1388// Scan the heap for objects constructed by a specific function.
1389// args[0]: the constructor to find instances of
1390// args[1]: the the maximum number of objects to return
1391RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
1392 HandleScope scope(isolate);
1393 DCHECK(args.length() == 2);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001394 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
1395 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
1396 RUNTIME_ASSERT(max_references >= 0);
1397
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001398 List<Handle<JSObject> > instances;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001399 Heap* heap = isolate->heap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001400 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001401 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
1402 HeapObject* heap_obj;
1403 while ((heap_obj = iterator.next())) {
1404 if (!heap_obj->IsJSObject()) continue;
1405 JSObject* obj = JSObject::cast(heap_obj);
1406 if (obj->map()->GetConstructor() != *constructor) continue;
1407 instances.Add(Handle<JSObject>(obj));
1408 if (instances.length() == max_references) break;
1409 }
1410 // Iterate the rest of the heap to satisfy HeapIterator constraints.
1411 while (iterator.next()) {
1412 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001413 }
1414
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001415 Handle<FixedArray> result =
1416 isolate->factory()->NewFixedArray(instances.length());
1417 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
1418 return *isolate->factory()->NewJSArrayWithElements(result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001419}
1420
1421
1422// Find the effective prototype object as returned by __proto__.
1423// args[0]: the object to find the prototype for.
1424RUNTIME_FUNCTION(Runtime_DebugGetPrototype) {
1425 HandleScope shs(isolate);
1426 DCHECK(args.length() == 1);
1427 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428 Handle<Object> prototype;
1429 // TODO(1543): Come up with a solution for clients to handle potential errors
1430 // thrown by an intermediate proxy.
1431 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, prototype,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001432 JSReceiver::GetPrototype(isolate, obj));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001433 return *prototype;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001434}
1435
1436
1437// Patches script source (should be called upon BeforeCompile event).
1438RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
1439 HandleScope scope(isolate);
1440 DCHECK(args.length() == 2);
1441
1442 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
1443 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
1444
1445 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
1446 Handle<Script> script(Script::cast(script_wrapper->value()));
1447
1448 int compilation_state = script->compilation_state();
1449 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
1450 script->set_source(*source);
1451
1452 return isolate->heap()->undefined_value();
1453}
1454
1455
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001456RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
1457 SealHandleScope shs(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001458 DCHECK_EQ(1, args.length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001459
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001460 CONVERT_ARG_CHECKED(Object, f, 0);
1461 if (f->IsJSFunction()) {
1462 return JSFunction::cast(f)->shared()->inferred_name();
1463 }
1464 return isolate->heap()->empty_string();
1465}
1466
1467
1468RUNTIME_FUNCTION(Runtime_FunctionGetDebugName) {
1469 HandleScope scope(isolate);
1470 DCHECK_EQ(1, args.length());
1471
1472 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
1473
1474 if (function->IsJSBoundFunction()) {
1475 return Handle<JSBoundFunction>::cast(function)->name();
1476 }
1477 Handle<Object> name =
1478 JSFunction::GetDebugName(Handle<JSFunction>::cast(function));
1479 return *name;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001480}
1481
1482
1483// A testing entry. Returns statement position which is the closest to
1484// source_position.
1485RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
1486 HandleScope scope(isolate);
1487 CHECK(isolate->debug()->live_edit_enabled());
1488 DCHECK(args.length() == 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 RUNTIME_ASSERT(isolate->debug()->is_active());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001490 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1491 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1492
1493 Handle<Code> code(function->code(), isolate);
1494
1495 if (code->kind() != Code::FUNCTION &&
1496 code->kind() != Code::OPTIMIZED_FUNCTION) {
1497 return isolate->heap()->undefined_value();
1498 }
1499
1500 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
1501 int closest_pc = 0;
1502 int distance = kMaxInt;
1503 while (!it.done()) {
1504 int statement_position = static_cast<int>(it.rinfo()->data());
1505 // Check if this break point is closer that what was previously found.
1506 if (source_position <= statement_position &&
1507 statement_position - source_position < distance) {
1508 closest_pc =
1509 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
1510 distance = statement_position - source_position;
1511 // Check whether we can't get any closer.
1512 if (distance == 0) break;
1513 }
1514 it.next();
1515 }
1516
1517 return Smi::FromInt(closest_pc);
1518}
1519
1520
1521// Calls specified function with or without entering the debugger.
1522// This is used in unit tests to run code as if debugger is entered or simply
1523// to have a stack with C++ frame in the middle.
1524RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
1525 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 DCHECK(args.length() == 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001527 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001528
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001529 DebugScope debug_scope(isolate->debug());
1530 if (debug_scope.failed()) {
1531 DCHECK(isolate->has_pending_exception());
1532 return isolate->heap()->exception();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001533 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001534
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001535 Handle<Object> result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1537 isolate, result,
1538 Execution::Call(isolate, function, handle(function->global_proxy()), 0,
1539 NULL));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001540 return *result;
1541}
1542
1543
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001544RUNTIME_FUNCTION(Runtime_GetDebugContext) {
1545 HandleScope scope(isolate);
1546 DCHECK(args.length() == 0);
1547 Handle<Context> context;
1548 {
1549 DebugScope debug_scope(isolate->debug());
1550 if (debug_scope.failed()) {
1551 DCHECK(isolate->has_pending_exception());
1552 return isolate->heap()->exception();
1553 }
1554 context = isolate->debug()->GetDebugContext();
1555 }
1556 if (context.is_null()) return isolate->heap()->undefined_value();
1557 context->set_security_token(isolate->native_context()->security_token());
1558 return context->global_proxy();
1559}
1560
1561
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001562// Performs a GC.
1563// Presently, it only does a full GC.
1564RUNTIME_FUNCTION(Runtime_CollectGarbage) {
1565 SealHandleScope shs(isolate);
1566 DCHECK(args.length() == 1);
1567 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
1568 return isolate->heap()->undefined_value();
1569}
1570
1571
1572// Gets the current heap usage.
1573RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
1574 SealHandleScope shs(isolate);
1575 DCHECK(args.length() == 0);
1576 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
1577 if (!Smi::IsValid(usage)) {
1578 return *isolate->factory()->NewNumberFromInt(usage);
1579 }
1580 return Smi::FromInt(usage);
1581}
1582
1583
1584// Finds the script object from the script data. NOTE: This operation uses
1585// heap traversal to find the function generated for the source position
1586// for the requested break point. For lazily compiled functions several heap
1587// traversals might be required rendering this operation as a rather slow
1588// operation. However for setting break points which is normally done through
1589// some kind of user interaction the performance is not crucial.
1590RUNTIME_FUNCTION(Runtime_GetScript) {
1591 HandleScope scope(isolate);
1592 DCHECK(args.length() == 1);
1593 CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0);
1594
1595 Handle<Script> found;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001596 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001597 Script::Iterator iterator(isolate);
1598 Script* script = NULL;
1599 while ((script = iterator.Next()) != NULL) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001600 if (!script->name()->IsString()) continue;
1601 String* name = String::cast(script->name());
1602 if (name->Equals(*script_name)) {
1603 found = Handle<Script>(script, isolate);
1604 break;
1605 }
1606 }
1607 }
1608
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001609 if (found.is_null()) return isolate->heap()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001610 return *Script::GetWrapper(found);
1611}
1612
1613
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001614// Set one shot breakpoints for the callback function that is passed to a
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001615// built-in function such as Array.forEach to enable stepping into the callback,
1616// if we are indeed stepping and the callback is subject to debugging.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001617RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
1618 DCHECK(args.length() == 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001619 HandleScope scope(isolate);
1620 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
1621 RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject());
1622 Handle<JSFunction> fun;
1623 if (object->IsJSFunction()) {
1624 fun = Handle<JSFunction>::cast(object);
1625 } else {
1626 fun = Handle<JSFunction>(
1627 Handle<JSGeneratorObject>::cast(object)->function(), isolate);
1628 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001629
1630 isolate->debug()->PrepareStepIn(fun);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001631 return isolate->heap()->undefined_value();
1632}
1633
1634
1635RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001636 DCHECK(args.length() == 2);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001637 HandleScope scope(isolate);
1638 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001639 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
1640 isolate->PushPromise(promise, function);
1641 // If we are in step-in mode, flood the handler.
1642 isolate->debug()->EnableStepIn();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001643 return isolate->heap()->undefined_value();
1644}
1645
1646
1647RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
1648 DCHECK(args.length() == 0);
1649 SealHandleScope shs(isolate);
1650 isolate->PopPromise();
1651 return isolate->heap()->undefined_value();
1652}
1653
1654
1655RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
1656 DCHECK(args.length() == 1);
1657 HandleScope scope(isolate);
1658 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
1659 isolate->debug()->OnPromiseEvent(data);
1660 return isolate->heap()->undefined_value();
1661}
1662
1663
1664RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
1665 DCHECK(args.length() == 1);
1666 HandleScope scope(isolate);
1667 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
1668 isolate->debug()->OnAsyncTaskEvent(data);
1669 return isolate->heap()->undefined_value();
1670}
1671
1672
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001673RUNTIME_FUNCTION(Runtime_DebugIsActive) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001674 SealHandleScope shs(isolate);
1675 return Smi::FromInt(isolate->debug()->is_active());
1676}
1677
1678
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001679RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001680 UNIMPLEMENTED();
1681 return NULL;
1682}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001683} // namespace internal
1684} // namespace v8