1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/runtime/runtime-utils.h"
6
7 #include "src/arguments.h"
8 #include "src/debug/debug-evaluate.h"
9 #include "src/debug/debug-frames.h"
10 #include "src/debug/debug-scopes.h"
11 #include "src/debug/debug.h"
12 #include "src/debug/liveedit.h"
13 #include "src/frames-inl.h"
14 #include "src/globals.h"
15 #include "src/interpreter/bytecodes.h"
16 #include "src/interpreter/interpreter.h"
17 #include "src/isolate-inl.h"
18 #include "src/runtime/runtime.h"
19 #include "src/wasm/wasm-module.h"
20 #include "src/wasm/wasm-objects.h"
21
22 namespace v8 {
23 namespace internal {
24
RUNTIME_FUNCTION(Runtime_DebugBreak)25 RUNTIME_FUNCTION(Runtime_DebugBreak) {
26 SealHandleScope shs(isolate);
27 DCHECK(args.length() == 1);
28 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
29 isolate->debug()->set_return_value(value);
30
31 // Get the top-most JavaScript frame.
32 JavaScriptFrameIterator it(isolate);
33 isolate->debug()->Break(it.frame());
34
35 isolate->debug()->SetAfterBreakTarget(it.frame());
36 return *isolate->debug()->return_value();
37 }
38
RUNTIME_FUNCTION(Runtime_DebugBreakOnBytecode)39 RUNTIME_FUNCTION(Runtime_DebugBreakOnBytecode) {
40 SealHandleScope shs(isolate);
41 DCHECK(args.length() == 1);
42 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
43 isolate->debug()->set_return_value(value);
44
45 // Get the top-most JavaScript frame.
46 JavaScriptFrameIterator it(isolate);
47 isolate->debug()->Break(it.frame());
48
49 // If live-edit has dropped frames, we are not going back to dispatch.
50 if (LiveEdit::SetAfterBreakTarget(isolate->debug())) return Smi::kZero;
51
52 // Return the handler from the original bytecode array.
53 DCHECK(it.frame()->is_interpreted());
54 InterpretedFrame* interpreted_frame =
55 reinterpret_cast<InterpretedFrame*>(it.frame());
56 SharedFunctionInfo* shared = interpreted_frame->function()->shared();
57 BytecodeArray* bytecode_array = shared->bytecode_array();
58 int bytecode_offset = interpreted_frame->GetBytecodeOffset();
59 interpreter::Bytecode bytecode =
60 interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset));
61 return isolate->interpreter()->GetBytecodeHandler(
62 bytecode, interpreter::OperandScale::kSingle);
63 }
64
65
RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement)66 RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
67 SealHandleScope shs(isolate);
68 DCHECK(args.length() == 0);
69 if (isolate->debug()->break_points_active()) {
70 isolate->debug()->HandleDebugBreak();
71 }
72 return isolate->heap()->undefined_value();
73 }
74
75
76 // Adds a JavaScript function as a debug event listener.
77 // args[0]: debug event listener function to set or null or undefined for
78 // clearing the event listener function
79 // args[1]: object supplied during callback
RUNTIME_FUNCTION(Runtime_SetDebugEventListener)80 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
81 SealHandleScope shs(isolate);
82 DCHECK(args.length() == 2);
83 CHECK(args[0]->IsJSFunction() || args[0]->IsUndefined(isolate) ||
84 args[0]->IsNull(isolate));
85 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
86 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
87 isolate->debug()->SetEventListener(callback, data);
88
89 return isolate->heap()->undefined_value();
90 }
91
92
RUNTIME_FUNCTION(Runtime_ScheduleBreak)93 RUNTIME_FUNCTION(Runtime_ScheduleBreak) {
94 SealHandleScope shs(isolate);
95 DCHECK(args.length() == 0);
96 isolate->stack_guard()->RequestDebugBreak();
97 return isolate->heap()->undefined_value();
98 }
99
100
DebugGetProperty(LookupIterator * it,bool * has_caught=NULL)101 static Handle<Object> DebugGetProperty(LookupIterator* it,
102 bool* has_caught = NULL) {
103 for (; it->IsFound(); it->Next()) {
104 switch (it->state()) {
105 case LookupIterator::NOT_FOUND:
106 case LookupIterator::TRANSITION:
107 UNREACHABLE();
108 case LookupIterator::ACCESS_CHECK:
109 // Ignore access checks.
110 break;
111 case LookupIterator::INTEGER_INDEXED_EXOTIC:
112 case LookupIterator::INTERCEPTOR:
113 case LookupIterator::JSPROXY:
114 return it->isolate()->factory()->undefined_value();
115 case LookupIterator::ACCESSOR: {
116 Handle<Object> accessors = it->GetAccessors();
117 if (!accessors->IsAccessorInfo()) {
118 return it->isolate()->factory()->undefined_value();
119 }
120 MaybeHandle<Object> maybe_result =
121 JSObject::GetPropertyWithAccessor(it);
122 Handle<Object> result;
123 if (!maybe_result.ToHandle(&result)) {
124 result = handle(it->isolate()->pending_exception(), it->isolate());
125 it->isolate()->clear_pending_exception();
126 if (has_caught != NULL) *has_caught = true;
127 }
128 return result;
129 }
130
131 case LookupIterator::DATA:
132 return it->GetDataValue();
133 }
134 }
135
136 return it->isolate()->factory()->undefined_value();
137 }
138
139
DebugGetProperty(Handle<Object> object,Handle<Name> name)140 static Handle<Object> DebugGetProperty(Handle<Object> object,
141 Handle<Name> name) {
142 LookupIterator it(object, name);
143 return DebugGetProperty(&it);
144 }
145
146
147 template <class IteratorType>
GetIteratorInternalProperties(Isolate * isolate,Handle<IteratorType> object)148 static MaybeHandle<JSArray> GetIteratorInternalProperties(
149 Isolate* isolate, Handle<IteratorType> object) {
150 Factory* factory = isolate->factory();
151 Handle<IteratorType> iterator = Handle<IteratorType>::cast(object);
152 CHECK(iterator->kind()->IsSmi());
153 const char* kind = NULL;
154 switch (Smi::cast(iterator->kind())->value()) {
155 case IteratorType::kKindKeys:
156 kind = "keys";
157 break;
158 case IteratorType::kKindValues:
159 kind = "values";
160 break;
161 case IteratorType::kKindEntries:
162 kind = "entries";
163 break;
164 default:
165 UNREACHABLE();
166 }
167
168 Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
169 Handle<String> has_more =
170 factory->NewStringFromAsciiChecked("[[IteratorHasMore]]");
171 result->set(0, *has_more);
172 result->set(1, isolate->heap()->ToBoolean(iterator->HasMore()));
173
174 Handle<String> index =
175 factory->NewStringFromAsciiChecked("[[IteratorIndex]]");
176 result->set(2, *index);
177 result->set(3, iterator->index());
178
179 Handle<String> iterator_kind =
180 factory->NewStringFromAsciiChecked("[[IteratorKind]]");
181 result->set(4, *iterator_kind);
182 Handle<String> kind_str = factory->NewStringFromAsciiChecked(kind);
183 result->set(5, *kind_str);
184 return factory->NewJSArrayWithElements(result);
185 }
186
187
GetInternalProperties(Isolate * isolate,Handle<Object> object)188 MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
189 Handle<Object> object) {
190 Factory* factory = isolate->factory();
191 if (object->IsJSBoundFunction()) {
192 Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object);
193
194 Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
195 Handle<String> target =
196 factory->NewStringFromAsciiChecked("[[TargetFunction]]");
197 result->set(0, *target);
198 result->set(1, function->bound_target_function());
199
200 Handle<String> bound_this =
201 factory->NewStringFromAsciiChecked("[[BoundThis]]");
202 result->set(2, *bound_this);
203 result->set(3, function->bound_this());
204
205 Handle<String> bound_args =
206 factory->NewStringFromAsciiChecked("[[BoundArgs]]");
207 result->set(4, *bound_args);
208 Handle<FixedArray> bound_arguments =
209 factory->CopyFixedArray(handle(function->bound_arguments(), isolate));
210 Handle<JSArray> arguments_array =
211 factory->NewJSArrayWithElements(bound_arguments);
212 result->set(5, *arguments_array);
213 return factory->NewJSArrayWithElements(result);
214 } else if (object->IsJSMapIterator()) {
215 Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object);
216 return GetIteratorInternalProperties(isolate, iterator);
217 } else if (object->IsJSSetIterator()) {
218 Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object);
219 return GetIteratorInternalProperties(isolate, iterator);
220 } else if (object->IsJSGeneratorObject()) {
221 Handle<JSGeneratorObject> generator =
222 Handle<JSGeneratorObject>::cast(object);
223
224 const char* status = "suspended";
225 if (generator->is_closed()) {
226 status = "closed";
227 } else if (generator->is_executing()) {
228 status = "running";
229 } else {
230 DCHECK(generator->is_suspended());
231 }
232
233 Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
234 Handle<String> generator_status =
235 factory->NewStringFromAsciiChecked("[[GeneratorStatus]]");
236 result->set(0, *generator_status);
237 Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
238 result->set(1, *status_str);
239
240 Handle<String> function =
241 factory->NewStringFromAsciiChecked("[[GeneratorFunction]]");
242 result->set(2, *function);
243 result->set(3, generator->function());
244
245 Handle<String> receiver =
246 factory->NewStringFromAsciiChecked("[[GeneratorReceiver]]");
247 result->set(4, *receiver);
248 result->set(5, generator->receiver());
249 return factory->NewJSArrayWithElements(result);
250 } else if (object->IsJSPromise()) {
251 Handle<JSObject> promise = Handle<JSObject>::cast(object);
252
253 Handle<Object> status_obj =
254 DebugGetProperty(promise, isolate->factory()->promise_state_symbol());
255 CHECK(status_obj->IsSmi());
256 const char* status = "rejected";
257 int status_val = Handle<Smi>::cast(status_obj)->value();
258 switch (status_val) {
259 case kPromiseFulfilled:
260 status = "resolved";
261 break;
262 case kPromisePending:
263 status = "pending";
264 break;
265 default:
266 DCHECK_EQ(kPromiseRejected, status_val);
267 }
268
269 Handle<FixedArray> result = factory->NewFixedArray(2 * 2);
270 Handle<String> promise_status =
271 factory->NewStringFromAsciiChecked("[[PromiseStatus]]");
272 result->set(0, *promise_status);
273 Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
274 result->set(1, *status_str);
275
276 Handle<Object> value_obj =
277 DebugGetProperty(promise, isolate->factory()->promise_result_symbol());
278 Handle<String> promise_value =
279 factory->NewStringFromAsciiChecked("[[PromiseValue]]");
280 result->set(2, *promise_value);
281 result->set(3, *value_obj);
282 return factory->NewJSArrayWithElements(result);
283 } else if (object->IsJSProxy()) {
284 Handle<JSProxy> js_proxy = Handle<JSProxy>::cast(object);
285 Handle<FixedArray> result = factory->NewFixedArray(3 * 2);
286
287 Handle<String> handler_str =
288 factory->NewStringFromAsciiChecked("[[Handler]]");
289 result->set(0, *handler_str);
290 result->set(1, js_proxy->handler());
291
292 Handle<String> target_str =
293 factory->NewStringFromAsciiChecked("[[Target]]");
294 result->set(2, *target_str);
295 result->set(3, js_proxy->target());
296
297 Handle<String> is_revoked_str =
298 factory->NewStringFromAsciiChecked("[[IsRevoked]]");
299 result->set(4, *is_revoked_str);
300 result->set(5, isolate->heap()->ToBoolean(js_proxy->IsRevoked()));
301 return factory->NewJSArrayWithElements(result);
302 } else if (object->IsJSValue()) {
303 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
304
305 Handle<FixedArray> result = factory->NewFixedArray(2);
306 Handle<String> primitive_value =
307 factory->NewStringFromAsciiChecked("[[PrimitiveValue]]");
308 result->set(0, *primitive_value);
309 result->set(1, js_value->value());
310 return factory->NewJSArrayWithElements(result);
311 }
312 return factory->NewJSArray(0);
313 }
314
315
RUNTIME_FUNCTION(Runtime_DebugGetInternalProperties)316 RUNTIME_FUNCTION(Runtime_DebugGetInternalProperties) {
317 HandleScope scope(isolate);
318 DCHECK(args.length() == 1);
319 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
320 RETURN_RESULT_OR_FAILURE(isolate,
321 Runtime::GetInternalProperties(isolate, obj));
322 }
323
324
325 // Get debugger related details for an object property, in the following format:
326 // 0: Property value
327 // 1: Property details
328 // 2: Property value is exception
329 // 3: Getter function if defined
330 // 4: Setter function if defined
331 // Items 2-4 are only filled if the property has either a getter or a setter.
RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails)332 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
333 HandleScope scope(isolate);
334 DCHECK_EQ(2, args.length());
335 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
336 CONVERT_ARG_HANDLE_CHECKED(Object, name_obj, 1);
337
338 // Convert the {name_obj} to a Name.
339 Handle<Name> name;
340 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
341 Object::ToName(isolate, name_obj));
342
343 // Make sure to set the current context to the context before the debugger was
344 // entered (if the debugger is entered). The reason for switching context here
345 // is that for some property lookups (accessors and interceptors) callbacks
346 // into the embedding application can occour, and the embedding application
347 // could have the assumption that its own native context is the current
348 // context and not some internal debugger context.
349 SaveContext save(isolate);
350 if (isolate->debug()->in_debug_scope()) {
351 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
352 }
353
354 // Check if the name is trivially convertible to an index and get the element
355 // if so.
356 uint32_t index;
357 // TODO(verwaest): Make sure DebugGetProperty can handle arrays, and remove
358 // this special case.
359 if (name->AsArrayIndex(&index)) {
360 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
361 Handle<Object> element_or_char;
362 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
363 isolate, element_or_char, JSReceiver::GetElement(isolate, obj, index));
364 details->set(0, *element_or_char);
365 details->set(1, PropertyDetails::Empty().AsSmi());
366 return *isolate->factory()->NewJSArrayWithElements(details);
367 }
368
369 LookupIterator it(obj, name, LookupIterator::OWN);
370 bool has_caught = false;
371 Handle<Object> value = DebugGetProperty(&it, &has_caught);
372 if (!it.IsFound()) return isolate->heap()->undefined_value();
373
374 Handle<Object> maybe_pair;
375 if (it.state() == LookupIterator::ACCESSOR) {
376 maybe_pair = it.GetAccessors();
377 }
378
379 // If the callback object is a fixed array then it contains JavaScript
380 // getter and/or setter.
381 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair();
382 Handle<FixedArray> details =
383 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3);
384 details->set(0, *value);
385 // TODO(verwaest): Get rid of this random way of handling interceptors.
386 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR
387 ? PropertyDetails::Empty()
388 : it.property_details();
389 details->set(1, d.AsSmi());
390 details->set(
391 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
392 if (has_js_accessors) {
393 Handle<AccessorPair> accessors = Handle<AccessorPair>::cast(maybe_pair);
394 details->set(3, isolate->heap()->ToBoolean(has_caught));
395 Handle<Object> getter =
396 AccessorPair::GetComponent(accessors, ACCESSOR_GETTER);
397 Handle<Object> setter =
398 AccessorPair::GetComponent(accessors, ACCESSOR_SETTER);
399 details->set(4, *getter);
400 details->set(5, *setter);
401 }
402
403 return *isolate->factory()->NewJSArrayWithElements(details);
404 }
405
406
RUNTIME_FUNCTION(Runtime_DebugGetProperty)407 RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
408 HandleScope scope(isolate);
409
410 DCHECK(args.length() == 2);
411
412 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
413 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
414
415 LookupIterator it(obj, name);
416 return *DebugGetProperty(&it);
417 }
418
419
420 // Return the property type calculated from the property details.
421 // args[0]: smi with property details.
RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails)422 RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
423 SealHandleScope shs(isolate);
424 DCHECK(args.length() == 1);
425 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
426 return Smi::FromInt(static_cast<int>(details.type()));
427 }
428
429
430 // Return the property attribute calculated from the property details.
431 // args[0]: smi with property details.
RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails)432 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
433 SealHandleScope shs(isolate);
434 DCHECK(args.length() == 1);
435 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
436 return Smi::FromInt(static_cast<int>(details.attributes()));
437 }
438
439
RUNTIME_FUNCTION(Runtime_CheckExecutionState)440 RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
441 SealHandleScope shs(isolate);
442 DCHECK(args.length() == 1);
443 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
444 CHECK(isolate->debug()->CheckExecutionState(break_id));
445 return isolate->heap()->true_value();
446 }
447
448
RUNTIME_FUNCTION(Runtime_GetFrameCount)449 RUNTIME_FUNCTION(Runtime_GetFrameCount) {
450 HandleScope scope(isolate);
451 DCHECK(args.length() == 1);
452 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
453 CHECK(isolate->debug()->CheckExecutionState(break_id));
454
455 // Count all frames which are relevant to debugging stack trace.
456 int n = 0;
457 StackFrame::Id id = isolate->debug()->break_frame_id();
458 if (id == StackFrame::NO_ID) {
459 // If there is no JavaScript stack frame count is 0.
460 return Smi::kZero;
461 }
462
463 for (StackTraceFrameIterator it(isolate, id); !it.done(); it.Advance()) {
464 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
465 if (it.is_wasm()) {
466 n++;
467 } else {
468 it.javascript_frame()->Summarize(&frames);
469 for (int i = frames.length() - 1; i >= 0; i--) {
470 // Omit functions from native and extension scripts.
471 if (frames[i].function()->shared()->IsSubjectToDebugging()) n++;
472 }
473 }
474 }
475 return Smi::FromInt(n);
476 }
477
478
479 static const int kFrameDetailsFrameIdIndex = 0;
480 static const int kFrameDetailsReceiverIndex = 1;
481 static const int kFrameDetailsFunctionIndex = 2;
482 static const int kFrameDetailsScriptIndex = 3;
483 static const int kFrameDetailsArgumentCountIndex = 4;
484 static const int kFrameDetailsLocalCountIndex = 5;
485 static const int kFrameDetailsSourcePositionIndex = 6;
486 static const int kFrameDetailsConstructCallIndex = 7;
487 static const int kFrameDetailsAtReturnIndex = 8;
488 static const int kFrameDetailsFlagsIndex = 9;
489 static const int kFrameDetailsFirstDynamicIndex = 10;
490
491 // Return an array with frame details
492 // args[0]: number: break id
493 // args[1]: number: frame index
494 //
495 // The array returned contains the following information:
496 // 0: Frame id
497 // 1: Receiver
498 // 2: Function
499 // 3: Script
500 // 4: Argument count
501 // 5: Local count
502 // 6: Source position
503 // 7: Constructor call
504 // 8: Is at return
505 // 9: Flags
506 // Arguments name, value
507 // Locals name, value
508 // Return value if any
RUNTIME_FUNCTION(Runtime_GetFrameDetails)509 RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
510 HandleScope scope(isolate);
511 DCHECK(args.length() == 2);
512 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
513 CHECK(isolate->debug()->CheckExecutionState(break_id));
514
515 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
516 Heap* heap = isolate->heap();
517
518 // Find the relevant frame with the requested index.
519 StackFrame::Id id = isolate->debug()->break_frame_id();
520 if (id == StackFrame::NO_ID) {
521 // If there are no JavaScript stack frames return undefined.
522 return heap->undefined_value();
523 }
524
525 StackTraceFrameIterator it(isolate, id);
526 // Inlined frame index in optimized frame, starting from outer function.
527 int inlined_jsframe_index =
528 DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
529 if (inlined_jsframe_index == -1) return heap->undefined_value();
530
531 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
532
533 // Traverse the saved contexts chain to find the active context for the
534 // selected frame.
535 SaveContext* save =
536 DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame());
537
538 // Get the frame id.
539 Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()),
540 isolate);
541
542 // Find source position in unoptimized code.
543 int position = frame_inspector.GetSourcePosition();
544
545 if (it.is_wasm()) {
546 // Create the details array (no dynamic information for wasm).
547 Handle<FixedArray> details =
548 isolate->factory()->NewFixedArray(kFrameDetailsFirstDynamicIndex);
549
550 // Add the frame id.
551 details->set(kFrameDetailsFrameIdIndex, *frame_id);
552
553 // Add the function name.
554 Handle<Object> wasm_instance(it.wasm_frame()->wasm_instance(), isolate);
555 int func_index = it.wasm_frame()->function_index();
556 Handle<String> func_name =
557 wasm::GetWasmFunctionName(isolate, wasm_instance, func_index);
558 details->set(kFrameDetailsFunctionIndex, *func_name);
559
560 // Add the script wrapper
561 Handle<Object> script_wrapper =
562 Script::GetWrapper(frame_inspector.GetScript());
563 details->set(kFrameDetailsScriptIndex, *script_wrapper);
564
565 // Add the arguments count.
566 details->set(kFrameDetailsArgumentCountIndex, Smi::kZero);
567
568 // Add the locals count
569 details->set(kFrameDetailsLocalCountIndex, Smi::kZero);
570
571 // Add the source position.
572 // For wasm, it is function-local, so translate it to a module-relative
573 // position, such that together with the script it uniquely identifies the
574 // position.
575 Handle<Object> positionValue;
576 if (position != kNoSourcePosition) {
577 int translated_position = position;
578 if (!wasm::WasmIsAsmJs(*wasm_instance, isolate)) {
579 Handle<WasmCompiledModule> compiled_module(
580 wasm::GetCompiledModule(JSObject::cast(*wasm_instance)), isolate);
581 translated_position +=
582 wasm::GetFunctionCodeOffset(compiled_module, func_index);
583 }
584 details->set(kFrameDetailsSourcePositionIndex,
585 Smi::FromInt(translated_position));
586 }
587
588 // Add the constructor information.
589 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(false));
590
591 // Add the at return information.
592 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(false));
593
594 // Add flags to indicate information on whether this frame is
595 // bit 0: invoked in the debugger context.
596 // bit 1: optimized frame.
597 // bit 2: inlined in optimized frame
598 int flags = 0;
599 if (*save->context() == *isolate->debug()->debug_context()) {
600 flags |= 1 << 0;
601 }
602 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
603
604 return *isolate->factory()->NewJSArrayWithElements(details);
605 }
606
607 // Handle JavaScript frames.
608 bool is_optimized = it.frame()->is_optimized();
609
610 // Check for constructor frame.
611 bool constructor = frame_inspector.IsConstructor();
612
613 // Get scope info and read from it for local variable information.
614 Handle<JSFunction> function =
615 Handle<JSFunction>::cast(frame_inspector.GetFunction());
616 CHECK(function->shared()->IsSubjectToDebugging());
617 Handle<SharedFunctionInfo> shared(function->shared());
618 Handle<ScopeInfo> scope_info(shared->scope_info());
619 DCHECK(*scope_info != ScopeInfo::Empty(isolate));
620
621 // Get the locals names and values into a temporary array.
622 Handle<Object> maybe_context = frame_inspector.GetContext();
623 const int local_count_with_synthetic = maybe_context->IsContext()
624 ? scope_info->LocalCount()
625 : scope_info->StackLocalCount();
626 int local_count = local_count_with_synthetic;
627 for (int slot = 0; slot < local_count_with_synthetic; ++slot) {
628 // Hide compiler-introduced temporary variables, whether on the stack or on
629 // the context.
630 if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(slot))) {
631 local_count--;
632 }
633 }
634
635 List<Handle<Object>> locals;
636 // Fill in the values of the locals.
637 int i = 0;
638 for (; i < scope_info->StackLocalCount(); ++i) {
639 // Use the value from the stack.
640 if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(i))) continue;
641 locals.Add(Handle<String>(scope_info->LocalName(i), isolate));
642 Handle<Object> value =
643 frame_inspector.GetExpression(scope_info->StackLocalIndex(i));
644 // TODO(yangguo): We convert optimized out values to {undefined} when they
645 // are passed to the debugger. Eventually we should handle them somehow.
646 if (value->IsOptimizedOut(isolate)) {
647 value = isolate->factory()->undefined_value();
648 }
649 locals.Add(value);
650 }
651 if (locals.length() < local_count * 2) {
652 // Get the context containing declarations.
653 DCHECK(maybe_context->IsContext());
654 Handle<Context> context(Context::cast(*maybe_context)->closure_context());
655
656 for (; i < scope_info->LocalCount(); ++i) {
657 Handle<String> name(scope_info->LocalName(i));
658 if (ScopeInfo::VariableIsSynthetic(*name)) continue;
659 VariableMode mode;
660 InitializationFlag init_flag;
661 MaybeAssignedFlag maybe_assigned_flag;
662 locals.Add(name);
663 int context_slot_index = ScopeInfo::ContextSlotIndex(
664 scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
665 Object* value = context->get(context_slot_index);
666 locals.Add(Handle<Object>(value, isolate));
667 }
668 }
669
670 // Check whether this frame is positioned at return. If not top
671 // frame or if the frame is optimized it cannot be at a return.
672 bool at_return = false;
673 if (!is_optimized && index == 0) {
674 at_return = isolate->debug()->IsBreakAtReturn(it.javascript_frame());
675 }
676
677 // If positioned just before return find the value to be returned and add it
678 // to the frame information.
679 Handle<Object> return_value = isolate->factory()->undefined_value();
680 if (at_return) {
681 return_value = isolate->debug()->return_value();
682 }
683
684 // Now advance to the arguments adapter frame (if any). It contains all
685 // the provided parameters whereas the function frame always have the number
686 // of arguments matching the functions parameters. The rest of the
687 // information (except for what is collected above) is the same.
688 if ((inlined_jsframe_index == 0) &&
689 it.javascript_frame()->has_adapted_arguments()) {
690 it.AdvanceToArgumentsFrame();
691 frame_inspector.SetArgumentsFrame(it.frame());
692 }
693
694 // Find the number of arguments to fill. At least fill the number of
695 // parameters for the function and fill more if more parameters are provided.
696 int argument_count = scope_info->ParameterCount();
697 if (argument_count < frame_inspector.GetParametersCount()) {
698 argument_count = frame_inspector.GetParametersCount();
699 }
700
701 // Calculate the size of the result.
702 int details_size = kFrameDetailsFirstDynamicIndex +
703 2 * (argument_count + local_count) + (at_return ? 1 : 0);
704 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
705
706 // Add the frame id.
707 details->set(kFrameDetailsFrameIdIndex, *frame_id);
708
709 // Add the function (same as in function frame).
710 details->set(kFrameDetailsFunctionIndex, *(frame_inspector.GetFunction()));
711
712 // Add the script wrapper
713 Handle<Object> script_wrapper =
714 Script::GetWrapper(frame_inspector.GetScript());
715 details->set(kFrameDetailsScriptIndex, *script_wrapper);
716
717 // Add the arguments count.
718 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
719
720 // Add the locals count
721 details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count));
722
723 // Add the source position.
724 if (position != kNoSourcePosition) {
725 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
726 } else {
727 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
728 }
729
730 // Add the constructor information.
731 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
732
733 // Add the at return information.
734 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
735
736 // Add flags to indicate information on whether this frame is
737 // bit 0: invoked in the debugger context.
738 // bit 1: optimized frame.
739 // bit 2: inlined in optimized frame
740 int flags = 0;
741 if (*save->context() == *isolate->debug()->debug_context()) {
742 flags |= 1 << 0;
743 }
744 if (is_optimized) {
745 flags |= 1 << 1;
746 flags |= inlined_jsframe_index << 2;
747 }
748 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
749
750 // Fill the dynamic part.
751 int details_index = kFrameDetailsFirstDynamicIndex;
752
753 // Add arguments name and value.
754 for (int i = 0; i < argument_count; i++) {
755 // Name of the argument.
756 if (i < scope_info->ParameterCount()) {
757 details->set(details_index++, scope_info->ParameterName(i));
758 } else {
759 details->set(details_index++, heap->undefined_value());
760 }
761
762 // Parameter value.
763 if (i < frame_inspector.GetParametersCount()) {
764 // Get the value from the stack.
765 details->set(details_index++, *(frame_inspector.GetParameter(i)));
766 } else {
767 details->set(details_index++, heap->undefined_value());
768 }
769 }
770
771 // Add locals name and value from the temporary copy from the function frame.
772 for (const auto& local : locals) details->set(details_index++, *local);
773
774 // Add the value being returned.
775 if (at_return) {
776 details->set(details_index++, *return_value);
777 }
778
779 // Add the receiver (same as in function frame).
780 Handle<Object> receiver(it.frame()->receiver(), isolate);
781 DCHECK(!function->shared()->IsBuiltin());
782 DCHECK_IMPLIES(is_sloppy(shared->language_mode()), receiver->IsJSReceiver());
783 details->set(kFrameDetailsReceiverIndex, *receiver);
784
785 DCHECK_EQ(details_size, details_index);
786 return *isolate->factory()->NewJSArrayWithElements(details);
787 }
788
789
RUNTIME_FUNCTION(Runtime_GetScopeCount)790 RUNTIME_FUNCTION(Runtime_GetScopeCount) {
791 HandleScope scope(isolate);
792 DCHECK(args.length() == 2);
793 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
794 CHECK(isolate->debug()->CheckExecutionState(break_id));
795
796 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
797
798 // Get the frame where the debugging is performed.
799 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
800 JavaScriptFrameIterator it(isolate, id);
801 JavaScriptFrame* frame = it.frame();
802 FrameInspector frame_inspector(frame, 0, isolate);
803
804 // Count the visible scopes.
805 int n = 0;
806 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) {
807 n++;
808 }
809
810 return Smi::FromInt(n);
811 }
812
813
814 // Return an array with scope details
815 // args[0]: number: break id
816 // args[1]: number: frame index
817 // args[2]: number: inlined frame index
818 // args[3]: number: scope index
819 //
820 // The array returned contains the following information:
821 // 0: Scope type
822 // 1: Scope object
RUNTIME_FUNCTION(Runtime_GetScopeDetails)823 RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
824 HandleScope scope(isolate);
825 DCHECK(args.length() == 4);
826 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
827 CHECK(isolate->debug()->CheckExecutionState(break_id));
828
829 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
830 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
831 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
832
833 // Get the frame where the debugging is performed.
834 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
835 JavaScriptFrameIterator frame_it(isolate, id);
836 JavaScriptFrame* frame = frame_it.frame();
837 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
838
839 // Find the requested scope.
840 int n = 0;
841 ScopeIterator it(isolate, &frame_inspector);
842 for (; !it.Done() && n < index; it.Next()) {
843 n++;
844 }
845 if (it.Done()) {
846 return isolate->heap()->undefined_value();
847 }
848 RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails());
849 }
850
851
852 // Return an array of scope details
853 // args[0]: number: break id
854 // args[1]: number: frame index
855 // args[2]: number: inlined frame index
856 // args[3]: boolean: ignore nested scopes
857 //
858 // The array returned contains arrays with the following information:
859 // 0: Scope type
860 // 1: Scope object
RUNTIME_FUNCTION(Runtime_GetAllScopesDetails)861 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
862 HandleScope scope(isolate);
863 DCHECK(args.length() == 3 || args.length() == 4);
864 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
865 CHECK(isolate->debug()->CheckExecutionState(break_id));
866
867 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
868 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
869
870 ScopeIterator::Option option = ScopeIterator::DEFAULT;
871 if (args.length() == 4) {
872 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
873 if (flag) option = ScopeIterator::IGNORE_NESTED_SCOPES;
874 }
875
876 // Get the frame where the debugging is performed.
877 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
878 StackTraceFrameIterator frame_it(isolate, id);
879 StandardFrame* frame = frame_it.frame();
880 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
881
882 List<Handle<JSObject> > result(4);
883 ScopeIterator it(isolate, &frame_inspector, option);
884 for (; !it.Done(); it.Next()) {
885 Handle<JSObject> details;
886 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
887 it.MaterializeScopeDetails());
888 result.Add(details);
889 }
890
891 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
892 for (int i = 0; i < result.length(); ++i) {
893 array->set(i, *result[i]);
894 }
895 return *isolate->factory()->NewJSArrayWithElements(array);
896 }
897
898
RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount)899 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
900 HandleScope scope(isolate);
901 DCHECK_EQ(1, args.length());
902
903 // Check arguments.
904 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
905
906 // Count the visible scopes.
907 int n = 0;
908 if (function->IsJSFunction()) {
909 for (ScopeIterator it(isolate, Handle<JSFunction>::cast(function));
910 !it.Done(); it.Next()) {
911 n++;
912 }
913 }
914
915 return Smi::FromInt(n);
916 }
917
918
RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails)919 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
920 HandleScope scope(isolate);
921 DCHECK(args.length() == 2);
922
923 // Check arguments.
924 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
925 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
926
927 // Find the requested scope.
928 int n = 0;
929 ScopeIterator it(isolate, fun);
930 for (; !it.Done() && n < index; it.Next()) {
931 n++;
932 }
933 if (it.Done()) {
934 return isolate->heap()->undefined_value();
935 }
936
937 RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails());
938 }
939
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount)940 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) {
941 HandleScope scope(isolate);
942 DCHECK_EQ(1, args.length());
943
944 if (!args[0]->IsJSGeneratorObject()) return Smi::kZero;
945
946 // Check arguments.
947 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
948
949 // Count the visible scopes.
950 int n = 0;
951 for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) {
952 n++;
953 }
954
955 return Smi::FromInt(n);
956 }
957
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails)958 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) {
959 HandleScope scope(isolate);
960 DCHECK(args.length() == 2);
961
962 if (!args[0]->IsJSGeneratorObject()) {
963 return isolate->heap()->undefined_value();
964 }
965
966 // Check arguments.
967 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
968 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
969
970 // Find the requested scope.
971 int n = 0;
972 ScopeIterator it(isolate, gen);
973 for (; !it.Done() && n < index; it.Next()) {
974 n++;
975 }
976 if (it.Done()) {
977 return isolate->heap()->undefined_value();
978 }
979
980 RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails());
981 }
982
SetScopeVariableValue(ScopeIterator * it,int index,Handle<String> variable_name,Handle<Object> new_value)983 static bool SetScopeVariableValue(ScopeIterator* it, int index,
984 Handle<String> variable_name,
985 Handle<Object> new_value) {
986 for (int n = 0; !it->Done() && n < index; it->Next()) {
987 n++;
988 }
989 if (it->Done()) {
990 return false;
991 }
992 return it->SetVariableValue(variable_name, new_value);
993 }
994
995
996 // Change variable value in closure or local scope
997 // args[0]: number or JsFunction: break id or function
998 // args[1]: number: frame index (when arg[0] is break id)
999 // args[2]: number: inlined frame index (when arg[0] is break id)
1000 // args[3]: number: scope index
1001 // args[4]: string: variable name
1002 // args[5]: object: new value
1003 //
1004 // Return true if success and false otherwise
RUNTIME_FUNCTION(Runtime_SetScopeVariableValue)1005 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
1006 HandleScope scope(isolate);
1007 DCHECK(args.length() == 6);
1008
1009 // Check arguments.
1010 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
1011 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
1012 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5);
1013
1014 bool res;
1015 if (args[0]->IsNumber()) {
1016 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1017 CHECK(isolate->debug()->CheckExecutionState(break_id));
1018
1019 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1020 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1021
1022 // Get the frame where the debugging is performed.
1023 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
1024 JavaScriptFrameIterator frame_it(isolate, id);
1025 JavaScriptFrame* frame = frame_it.frame();
1026 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
1027
1028 ScopeIterator it(isolate, &frame_inspector);
1029 res = SetScopeVariableValue(&it, index, variable_name, new_value);
1030 } else if (args[0]->IsJSFunction()) {
1031 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1032 ScopeIterator it(isolate, fun);
1033 res = SetScopeVariableValue(&it, index, variable_name, new_value);
1034 } else {
1035 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
1036 ScopeIterator it(isolate, gen);
1037 res = SetScopeVariableValue(&it, index, variable_name, new_value);
1038 }
1039
1040 return isolate->heap()->ToBoolean(res);
1041 }
1042
1043
RUNTIME_FUNCTION(Runtime_DebugPrintScopes)1044 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
1045 HandleScope scope(isolate);
1046 DCHECK(args.length() == 0);
1047
1048 #ifdef DEBUG
1049 // Print the scopes for the top frame.
1050 StackFrameLocator locator(isolate);
1051 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
1052 FrameInspector frame_inspector(frame, 0, isolate);
1053
1054 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) {
1055 it.DebugPrint();
1056 }
1057 #endif
1058 return isolate->heap()->undefined_value();
1059 }
1060
1061
1062 // Sets the disable break state
1063 // args[0]: disable break state
RUNTIME_FUNCTION(Runtime_SetBreakPointsActive)1064 RUNTIME_FUNCTION(Runtime_SetBreakPointsActive) {
1065 HandleScope scope(isolate);
1066 DCHECK(args.length() == 1);
1067 CONVERT_BOOLEAN_ARG_CHECKED(active, 0);
1068 isolate->debug()->set_break_points_active(active);
1069 return isolate->heap()->undefined_value();
1070 }
1071
1072
IsPositionAlignmentCodeCorrect(int alignment)1073 static bool IsPositionAlignmentCodeCorrect(int alignment) {
1074 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
1075 }
1076
1077
RUNTIME_FUNCTION(Runtime_GetBreakLocations)1078 RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
1079 HandleScope scope(isolate);
1080 DCHECK(args.length() == 2);
1081 CHECK(isolate->debug()->is_active());
1082 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1083 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
1084
1085 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1086 return isolate->ThrowIllegalOperation();
1087 }
1088 BreakPositionAlignment alignment =
1089 static_cast<BreakPositionAlignment>(statement_aligned_code);
1090
1091 Handle<SharedFunctionInfo> shared(fun->shared());
1092 // Find the number of break points
1093 Handle<Object> break_locations =
1094 Debug::GetSourceBreakLocations(shared, alignment);
1095 if (break_locations->IsUndefined(isolate)) {
1096 return isolate->heap()->undefined_value();
1097 }
1098 // Return array as JS array
1099 return *isolate->factory()->NewJSArrayWithElements(
1100 Handle<FixedArray>::cast(break_locations));
1101 }
1102
1103
1104 // Set a break point in a function.
1105 // args[0]: function
1106 // args[1]: number: break source position (within the function source)
1107 // args[2]: number: break point object
RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint)1108 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
1109 HandleScope scope(isolate);
1110 DCHECK(args.length() == 3);
1111 CHECK(isolate->debug()->is_active());
1112 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1113 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1114 CHECK(source_position >= function->shared()->start_position() &&
1115 source_position <= function->shared()->end_position());
1116 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
1117
1118 // Set break point.
1119 CHECK(isolate->debug()->SetBreakPoint(function, break_point_object_arg,
1120 &source_position));
1121
1122 return Smi::FromInt(source_position);
1123 }
1124
1125
1126 // Changes the state of a break point in a script and returns source position
1127 // where break point was set. NOTE: Regarding performance see the NOTE for
1128 // GetScriptFromScriptData.
1129 // args[0]: script to set break point in
1130 // args[1]: number: break source position (within the script source)
1131 // args[2]: number, breakpoint position alignment
1132 // args[3]: number: break point object
RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint)1133 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
1134 HandleScope scope(isolate);
1135 DCHECK(args.length() == 4);
1136 CHECK(isolate->debug()->is_active());
1137 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
1138 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
1139 CHECK(source_position >= 0);
1140 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
1141 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
1142
1143 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
1144 return isolate->ThrowIllegalOperation();
1145 }
1146 BreakPositionAlignment alignment =
1147 static_cast<BreakPositionAlignment>(statement_aligned_code);
1148
1149 // Get the script from the script wrapper.
1150 CHECK(wrapper->value()->IsScript());
1151 Handle<Script> script(Script::cast(wrapper->value()));
1152
1153 // Set break point.
1154 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
1155 &source_position, alignment)) {
1156 return isolate->heap()->undefined_value();
1157 }
1158
1159 return Smi::FromInt(source_position);
1160 }
1161
1162
1163 // Clear a break point
1164 // args[0]: number: break point object
RUNTIME_FUNCTION(Runtime_ClearBreakPoint)1165 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
1166 HandleScope scope(isolate);
1167 DCHECK(args.length() == 1);
1168 CHECK(isolate->debug()->is_active());
1169 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
1170
1171 // Clear break point.
1172 isolate->debug()->ClearBreakPoint(break_point_object_arg);
1173
1174 return isolate->heap()->undefined_value();
1175 }
1176
1177
1178 // Change the state of break on exceptions.
1179 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
1180 // args[1]: Boolean indicating on/off.
RUNTIME_FUNCTION(Runtime_ChangeBreakOnException)1181 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) {
1182 HandleScope scope(isolate);
1183 DCHECK(args.length() == 2);
1184 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
1185 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
1186
1187 // If the number doesn't match an enum value, the ChangeBreakOnException
1188 // function will default to affecting caught exceptions.
1189 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
1190 // Update break point state.
1191 isolate->debug()->ChangeBreakOnException(type, enable);
1192 return isolate->heap()->undefined_value();
1193 }
1194
1195
1196 // Returns the state of break on exceptions
1197 // args[0]: boolean indicating uncaught exceptions
RUNTIME_FUNCTION(Runtime_IsBreakOnException)1198 RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
1199 HandleScope scope(isolate);
1200 DCHECK(args.length() == 1);
1201 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
1202
1203 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
1204 bool result = isolate->debug()->IsBreakOnException(type);
1205 return Smi::FromInt(result);
1206 }
1207
1208
1209 // Prepare for stepping
1210 // args[0]: break id for checking execution state
1211 // args[1]: step action from the enumeration StepAction
1212 // args[2]: number of times to perform the step, for step out it is the number
1213 // of frames to step down.
RUNTIME_FUNCTION(Runtime_PrepareStep)1214 RUNTIME_FUNCTION(Runtime_PrepareStep) {
1215 HandleScope scope(isolate);
1216 DCHECK(args.length() == 2);
1217 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1218 CHECK(isolate->debug()->CheckExecutionState(break_id));
1219
1220 if (!args[1]->IsNumber()) {
1221 return isolate->Throw(isolate->heap()->illegal_argument_string());
1222 }
1223
1224 // Get the step action and check validity.
1225 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
1226 if (step_action != StepIn && step_action != StepNext &&
1227 step_action != StepOut && step_action != StepFrame) {
1228 return isolate->Throw(isolate->heap()->illegal_argument_string());
1229 }
1230
1231 // Clear all current stepping setup.
1232 isolate->debug()->ClearStepping();
1233
1234 // Prepare step.
1235 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action));
1236 return isolate->heap()->undefined_value();
1237 }
1238
1239
1240 // Clear all stepping set by PrepareStep.
RUNTIME_FUNCTION(Runtime_ClearStepping)1241 RUNTIME_FUNCTION(Runtime_ClearStepping) {
1242 HandleScope scope(isolate);
1243 DCHECK(args.length() == 0);
1244 CHECK(isolate->debug()->is_active());
1245 isolate->debug()->ClearStepping();
1246 return isolate->heap()->undefined_value();
1247 }
1248
1249
RUNTIME_FUNCTION(Runtime_DebugEvaluate)1250 RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
1251 HandleScope scope(isolate);
1252
1253 // Check the execution state and decode arguments frame and source to be
1254 // evaluated.
1255 DCHECK(args.length() == 6);
1256 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1257 CHECK(isolate->debug()->CheckExecutionState(break_id));
1258
1259 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
1260 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
1261 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
1262 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
1263 CONVERT_ARG_HANDLE_CHECKED(HeapObject, context_extension, 5);
1264
1265 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
1266
1267 RETURN_RESULT_OR_FAILURE(
1268 isolate, DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source,
1269 disable_break, context_extension));
1270 }
1271
1272
RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal)1273 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
1274 HandleScope scope(isolate);
1275
1276 // Check the execution state and decode arguments frame and source to be
1277 // evaluated.
1278 DCHECK(args.length() == 4);
1279 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
1280 CHECK(isolate->debug()->CheckExecutionState(break_id));
1281
1282 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
1283 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
1284 CONVERT_ARG_HANDLE_CHECKED(HeapObject, context_extension, 3);
1285
1286 RETURN_RESULT_OR_FAILURE(
1287 isolate,
1288 DebugEvaluate::Global(isolate, source, disable_break, context_extension));
1289 }
1290
1291
RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts)1292 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
1293 HandleScope scope(isolate);
1294 DCHECK(args.length() == 0);
1295
1296 // This runtime function is used by the debugger to determine whether the
1297 // debugger is active or not. Hence we fail gracefully here and don't crash.
1298 if (!isolate->debug()->is_active()) return isolate->ThrowIllegalOperation();
1299
1300 Handle<FixedArray> instances;
1301 {
1302 DebugScope debug_scope(isolate->debug());
1303 if (debug_scope.failed()) {
1304 DCHECK(isolate->has_pending_exception());
1305 return isolate->heap()->exception();
1306 }
1307 // Fill the script objects.
1308 instances = isolate->debug()->GetLoadedScripts();
1309 }
1310
1311 // Convert the script objects to proper JS objects.
1312 for (int i = 0; i < instances->length(); i++) {
1313 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
1314 // Get the script wrapper in a local handle before calling GetScriptWrapper,
1315 // because using
1316 // instances->set(i, *GetScriptWrapper(script))
1317 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
1318 // already have dereferenced the instances handle.
1319 Handle<JSObject> wrapper = Script::GetWrapper(script);
1320 instances->set(i, *wrapper);
1321 }
1322
1323 // Return result as a JS array.
1324 return *isolate->factory()->NewJSArrayWithElements(instances);
1325 }
1326
HasInPrototypeChainIgnoringProxies(Isolate * isolate,JSObject * object,Object * proto)1327 static bool HasInPrototypeChainIgnoringProxies(Isolate* isolate,
1328 JSObject* object,
1329 Object* proto) {
1330 PrototypeIterator iter(isolate, object, kStartAtReceiver);
1331 while (true) {
1332 iter.AdvanceIgnoringProxies();
1333 if (iter.IsAtEnd()) return false;
1334 if (iter.GetCurrent() == proto) return true;
1335 }
1336 }
1337
1338
1339 // Scan the heap for objects with direct references to an object
1340 // args[0]: the object to find references to
1341 // args[1]: constructor function for instances to exclude (Mirror)
1342 // args[2]: the the maximum number of objects to return
RUNTIME_FUNCTION(Runtime_DebugReferencedBy)1343 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
1344 HandleScope scope(isolate);
1345 DCHECK(args.length() == 3);
1346 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
1347 CONVERT_ARG_HANDLE_CHECKED(Object, filter, 1);
1348 CHECK(filter->IsUndefined(isolate) || filter->IsJSObject());
1349 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
1350 CHECK(max_references >= 0);
1351
1352 List<Handle<JSObject> > instances;
1353 Heap* heap = isolate->heap();
1354 {
1355 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
1356 // Get the constructor function for context extension and arguments array.
1357 Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor();
1358 HeapObject* heap_obj;
1359 while ((heap_obj = iterator.next())) {
1360 if (!heap_obj->IsJSObject()) continue;
1361 JSObject* obj = JSObject::cast(heap_obj);
1362 if (obj->IsJSContextExtensionObject()) continue;
1363 if (obj->map()->GetConstructor() == arguments_fun) continue;
1364 if (!obj->ReferencesObject(*target)) continue;
1365 // Check filter if supplied. This is normally used to avoid
1366 // references from mirror objects.
1367 if (!filter->IsUndefined(isolate) &&
1368 HasInPrototypeChainIgnoringProxies(isolate, obj, *filter)) {
1369 continue;
1370 }
1371 if (obj->IsJSGlobalObject()) {
1372 obj = JSGlobalObject::cast(obj)->global_proxy();
1373 }
1374 instances.Add(Handle<JSObject>(obj));
1375 if (instances.length() == max_references) break;
1376 }
1377 // Iterate the rest of the heap to satisfy HeapIterator constraints.
1378 while (iterator.next()) {
1379 }
1380 }
1381
1382 Handle<FixedArray> result;
1383 if (instances.length() == 1 && instances.last().is_identical_to(target)) {
1384 // Check for circular reference only. This can happen when the object is
1385 // only referenced from mirrors and has a circular reference in which case
1386 // the object is not really alive and would have been garbage collected if
1387 // not referenced from the mirror.
1388 result = isolate->factory()->empty_fixed_array();
1389 } else {
1390 result = isolate->factory()->NewFixedArray(instances.length());
1391 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
1392 }
1393 return *isolate->factory()->NewJSArrayWithElements(result);
1394 }
1395
1396
1397 // Scan the heap for objects constructed by a specific function.
1398 // args[0]: the constructor to find instances of
1399 // args[1]: the the maximum number of objects to return
RUNTIME_FUNCTION(Runtime_DebugConstructedBy)1400 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
1401 HandleScope scope(isolate);
1402 DCHECK(args.length() == 2);
1403 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
1404 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
1405 CHECK(max_references >= 0);
1406
1407 List<Handle<JSObject> > instances;
1408 Heap* heap = isolate->heap();
1409 {
1410 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
1411 HeapObject* heap_obj;
1412 while ((heap_obj = iterator.next())) {
1413 if (!heap_obj->IsJSObject()) continue;
1414 JSObject* obj = JSObject::cast(heap_obj);
1415 if (obj->map()->GetConstructor() != *constructor) continue;
1416 instances.Add(Handle<JSObject>(obj));
1417 if (instances.length() == max_references) break;
1418 }
1419 // Iterate the rest of the heap to satisfy HeapIterator constraints.
1420 while (iterator.next()) {
1421 }
1422 }
1423
1424 Handle<FixedArray> result =
1425 isolate->factory()->NewFixedArray(instances.length());
1426 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
1427 return *isolate->factory()->NewJSArrayWithElements(result);
1428 }
1429
1430
1431 // Find the effective prototype object as returned by __proto__.
1432 // args[0]: the object to find the prototype for.
RUNTIME_FUNCTION(Runtime_DebugGetPrototype)1433 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) {
1434 HandleScope shs(isolate);
1435 DCHECK(args.length() == 1);
1436 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1437 // TODO(1543): Come up with a solution for clients to handle potential errors
1438 // thrown by an intermediate proxy.
1439 RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj));
1440 }
1441
1442
1443 // Patches script source (should be called upon BeforeCompile event).
1444 // TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_DebugSetScriptSource)1445 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
1446 HandleScope scope(isolate);
1447 DCHECK(args.length() == 2);
1448
1449 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
1450 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
1451
1452 CHECK(script_wrapper->value()->IsScript());
1453 Handle<Script> script(Script::cast(script_wrapper->value()));
1454
1455 // The following condition is not guaranteed to hold and a failure is also
1456 // propagated to callers. Hence we fail gracefully here and don't crash.
1457 if (script->compilation_state() != Script::COMPILATION_STATE_INITIAL) {
1458 return isolate->ThrowIllegalOperation();
1459 }
1460
1461 script->set_source(*source);
1462
1463 return isolate->heap()->undefined_value();
1464 }
1465
1466
RUNTIME_FUNCTION(Runtime_FunctionGetInferredName)1467 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
1468 SealHandleScope shs(isolate);
1469 DCHECK_EQ(1, args.length());
1470
1471 CONVERT_ARG_CHECKED(Object, f, 0);
1472 if (f->IsJSFunction()) {
1473 return JSFunction::cast(f)->shared()->inferred_name();
1474 }
1475 return isolate->heap()->empty_string();
1476 }
1477
1478
RUNTIME_FUNCTION(Runtime_FunctionGetDebugName)1479 RUNTIME_FUNCTION(Runtime_FunctionGetDebugName) {
1480 HandleScope scope(isolate);
1481 DCHECK_EQ(1, args.length());
1482
1483 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
1484
1485 if (function->IsJSBoundFunction()) {
1486 RETURN_RESULT_OR_FAILURE(
1487 isolate, JSBoundFunction::GetName(
1488 isolate, Handle<JSBoundFunction>::cast(function)));
1489 } else {
1490 return *JSFunction::GetDebugName(Handle<JSFunction>::cast(function));
1491 }
1492 }
1493
1494
1495 // Calls specified function with or without entering the debugger.
1496 // This is used in unit tests to run code as if debugger is entered or simply
1497 // to have a stack with C++ frame in the middle.
RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext)1498 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
1499 HandleScope scope(isolate);
1500 DCHECK(args.length() == 1);
1501 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1502
1503 DebugScope debug_scope(isolate->debug());
1504 if (debug_scope.failed()) {
1505 DCHECK(isolate->has_pending_exception());
1506 return isolate->heap()->exception();
1507 }
1508
1509 RETURN_RESULT_OR_FAILURE(
1510 isolate, Execution::Call(isolate, function,
1511 handle(function->global_proxy()), 0, NULL));
1512 }
1513
1514
RUNTIME_FUNCTION(Runtime_GetDebugContext)1515 RUNTIME_FUNCTION(Runtime_GetDebugContext) {
1516 HandleScope scope(isolate);
1517 DCHECK(args.length() == 0);
1518 Handle<Context> context;
1519 {
1520 DebugScope debug_scope(isolate->debug());
1521 if (debug_scope.failed()) {
1522 DCHECK(isolate->has_pending_exception());
1523 return isolate->heap()->exception();
1524 }
1525 context = isolate->debug()->GetDebugContext();
1526 }
1527 if (context.is_null()) return isolate->heap()->undefined_value();
1528 context->set_security_token(isolate->native_context()->security_token());
1529 return context->global_proxy();
1530 }
1531
1532
1533 // Performs a GC.
1534 // Presently, it only does a full GC.
RUNTIME_FUNCTION(Runtime_CollectGarbage)1535 RUNTIME_FUNCTION(Runtime_CollectGarbage) {
1536 SealHandleScope shs(isolate);
1537 DCHECK(args.length() == 1);
1538 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
1539 GarbageCollectionReason::kRuntime);
1540 return isolate->heap()->undefined_value();
1541 }
1542
1543
1544 // Gets the current heap usage.
RUNTIME_FUNCTION(Runtime_GetHeapUsage)1545 RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
1546 SealHandleScope shs(isolate);
1547 DCHECK(args.length() == 0);
1548 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
1549 if (!Smi::IsValid(usage)) {
1550 return *isolate->factory()->NewNumberFromInt(usage);
1551 }
1552 return Smi::FromInt(usage);
1553 }
1554
1555
1556 // Finds the script object from the script data. NOTE: This operation uses
1557 // heap traversal to find the function generated for the source position
1558 // for the requested break point. For lazily compiled functions several heap
1559 // traversals might be required rendering this operation as a rather slow
1560 // operation. However for setting break points which is normally done through
1561 // some kind of user interaction the performance is not crucial.
RUNTIME_FUNCTION(Runtime_GetScript)1562 RUNTIME_FUNCTION(Runtime_GetScript) {
1563 HandleScope scope(isolate);
1564 DCHECK(args.length() == 1);
1565 CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0);
1566
1567 Handle<Script> found;
1568 {
1569 Script::Iterator iterator(isolate);
1570 Script* script = NULL;
1571 while ((script = iterator.Next()) != NULL) {
1572 if (!script->name()->IsString()) continue;
1573 String* name = String::cast(script->name());
1574 if (name->Equals(*script_name)) {
1575 found = Handle<Script>(script, isolate);
1576 break;
1577 }
1578 }
1579 }
1580
1581 if (found.is_null()) return isolate->heap()->undefined_value();
1582 return *Script::GetWrapper(found);
1583 }
1584
1585 // TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_ScriptLineCount)1586 RUNTIME_FUNCTION(Runtime_ScriptLineCount) {
1587 HandleScope scope(isolate);
1588 DCHECK(args.length() == 1);
1589 CONVERT_ARG_CHECKED(JSValue, script, 0);
1590
1591 CHECK(script->value()->IsScript());
1592 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
1593
1594 Script::InitLineEnds(script_handle);
1595
1596 FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends());
1597 return Smi::FromInt(line_ends_array->length());
1598 }
1599
1600 // TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_ScriptLineStartPosition)1601 RUNTIME_FUNCTION(Runtime_ScriptLineStartPosition) {
1602 HandleScope scope(isolate);
1603 DCHECK(args.length() == 2);
1604 CONVERT_ARG_CHECKED(JSValue, script, 0);
1605 CONVERT_NUMBER_CHECKED(int32_t, line, Int32, args[1]);
1606
1607 CHECK(script->value()->IsScript());
1608 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
1609
1610 Script::InitLineEnds(script_handle);
1611
1612 FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends());
1613 const int line_count = line_ends_array->length();
1614
1615 // If line == line_count, we return the first position beyond the last line.
1616 if (line < 0 || line > line_count) {
1617 return Smi::FromInt(-1);
1618 } else if (line == 0) {
1619 return Smi::kZero;
1620 } else {
1621 DCHECK(0 < line && line <= line_count);
1622 const int pos = Smi::cast(line_ends_array->get(line - 1))->value() + 1;
1623 return Smi::FromInt(pos);
1624 }
1625 }
1626
1627 // TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_ScriptLineEndPosition)1628 RUNTIME_FUNCTION(Runtime_ScriptLineEndPosition) {
1629 HandleScope scope(isolate);
1630 DCHECK(args.length() == 2);
1631 CONVERT_ARG_CHECKED(JSValue, script, 0);
1632 CONVERT_NUMBER_CHECKED(int32_t, line, Int32, args[1]);
1633
1634 CHECK(script->value()->IsScript());
1635 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
1636
1637 Script::InitLineEnds(script_handle);
1638
1639 FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends());
1640 const int line_count = line_ends_array->length();
1641
1642 if (line < 0 || line >= line_count) {
1643 return Smi::FromInt(-1);
1644 } else {
1645 return Smi::cast(line_ends_array->get(line));
1646 }
1647 }
1648
GetJSPositionInfo(Handle<Script> script,int position,Script::OffsetFlag offset_flag,Isolate * isolate)1649 static Handle<Object> GetJSPositionInfo(Handle<Script> script, int position,
1650 Script::OffsetFlag offset_flag,
1651 Isolate* isolate) {
1652 Script::PositionInfo info;
1653 if (!Script::GetPositionInfo(script, position, &info, offset_flag)) {
1654 return isolate->factory()->null_value();
1655 }
1656
1657 Handle<String> source = handle(String::cast(script->source()), isolate);
1658 Handle<String> sourceText = script->type() == Script::TYPE_WASM
1659 ? isolate->factory()->empty_string()
1660 : isolate->factory()->NewSubString(
1661 source, info.line_start, info.line_end);
1662
1663 Handle<JSObject> jsinfo =
1664 isolate->factory()->NewJSObject(isolate->object_function());
1665
1666 JSObject::AddProperty(jsinfo, isolate->factory()->script_string(), script,
1667 NONE);
1668 JSObject::AddProperty(jsinfo, isolate->factory()->position_string(),
1669 handle(Smi::FromInt(position), isolate), NONE);
1670 JSObject::AddProperty(jsinfo, isolate->factory()->line_string(),
1671 handle(Smi::FromInt(info.line), isolate), NONE);
1672 JSObject::AddProperty(jsinfo, isolate->factory()->column_string(),
1673 handle(Smi::FromInt(info.column), isolate), NONE);
1674 JSObject::AddProperty(jsinfo, isolate->factory()->sourceText_string(),
1675 sourceText, NONE);
1676
1677 return jsinfo;
1678 }
1679
1680 namespace {
1681
ScriptLocationFromLine(Isolate * isolate,Handle<Script> script,Handle<Object> opt_line,Handle<Object> opt_column,int32_t offset)1682 Handle<Object> ScriptLocationFromLine(Isolate* isolate, Handle<Script> script,
1683 Handle<Object> opt_line,
1684 Handle<Object> opt_column,
1685 int32_t offset) {
1686 // Line and column are possibly undefined and we need to handle these cases,
1687 // additionally subtracting corresponding offsets.
1688
1689 int32_t line;
1690 if (opt_line->IsNull(isolate) || opt_line->IsUndefined(isolate)) {
1691 line = 0;
1692 } else {
1693 CHECK(opt_line->IsNumber());
1694 line = NumberToInt32(*opt_line) - script->line_offset();
1695 }
1696
1697 int32_t column;
1698 if (opt_column->IsNull(isolate) || opt_column->IsUndefined(isolate)) {
1699 column = 0;
1700 } else {
1701 CHECK(opt_column->IsNumber());
1702 column = NumberToInt32(*opt_column);
1703 if (line == 0) column -= script->column_offset();
1704 }
1705
1706 if (line < 0 || column < 0 || offset < 0) {
1707 return isolate->factory()->null_value();
1708 }
1709
1710 Script::InitLineEnds(script);
1711
1712 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
1713 const int line_count = line_ends_array->length();
1714
1715 int position;
1716 if (line == 0) {
1717 position = offset + column;
1718 } else {
1719 Script::PositionInfo info;
1720 if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET) ||
1721 info.line + line >= line_count) {
1722 return isolate->factory()->null_value();
1723 }
1724
1725 const int offset_line = info.line + line;
1726 const int offset_line_position =
1727 (offset_line == 0)
1728 ? 0
1729 : Smi::cast(line_ends_array->get(offset_line - 1))->value() + 1;
1730 position = offset_line_position + column;
1731 }
1732
1733 return GetJSPositionInfo(script, position, Script::NO_OFFSET, isolate);
1734 }
1735
1736 // Slow traversal over all scripts on the heap.
GetScriptById(Isolate * isolate,int needle,Handle<Script> * result)1737 bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) {
1738 Script::Iterator iterator(isolate);
1739 Script* script = NULL;
1740 while ((script = iterator.Next()) != NULL) {
1741 if (script->id() == needle) {
1742 *result = handle(script);
1743 return true;
1744 }
1745 }
1746
1747 return false;
1748 }
1749
1750 } // namespace
1751
1752 // Get information on a specific source line and column possibly offset by a
1753 // fixed source position. This function is used to find a source position from
1754 // a line and column position. The fixed source position offset is typically
1755 // used to find a source position in a function based on a line and column in
1756 // the source for the function alone. The offset passed will then be the
1757 // start position of the source for the function within the full script source.
1758 // Note that incoming line and column parameters may be undefined, and are
1759 // assumed to be passed *with* offsets.
1760 // TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine)1761 RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine) {
1762 HandleScope scope(isolate);
1763 DCHECK(args.length() == 4);
1764 CONVERT_ARG_HANDLE_CHECKED(JSValue, script, 0);
1765 CONVERT_ARG_HANDLE_CHECKED(Object, opt_line, 1);
1766 CONVERT_ARG_HANDLE_CHECKED(Object, opt_column, 2);
1767 CONVERT_NUMBER_CHECKED(int32_t, offset, Int32, args[3]);
1768
1769 CHECK(script->value()->IsScript());
1770 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
1771
1772 return *ScriptLocationFromLine(isolate, script_handle, opt_line, opt_column,
1773 offset);
1774 }
1775
1776 // TODO(5530): Rename once conflicting function has been deleted.
RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2)1777 RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) {
1778 HandleScope scope(isolate);
1779 DCHECK(args.length() == 4);
1780 CONVERT_NUMBER_CHECKED(int32_t, scriptid, Int32, args[0]);
1781 CONVERT_ARG_HANDLE_CHECKED(Object, opt_line, 1);
1782 CONVERT_ARG_HANDLE_CHECKED(Object, opt_column, 2);
1783 CONVERT_NUMBER_CHECKED(int32_t, offset, Int32, args[3]);
1784
1785 Handle<Script> script;
1786 CHECK(GetScriptById(isolate, scriptid, &script));
1787
1788 return *ScriptLocationFromLine(isolate, script, opt_line, opt_column, offset);
1789 }
1790
1791 // TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_ScriptPositionInfo)1792 RUNTIME_FUNCTION(Runtime_ScriptPositionInfo) {
1793 HandleScope scope(isolate);
1794 DCHECK(args.length() == 3);
1795 CONVERT_ARG_CHECKED(JSValue, script, 0);
1796 CONVERT_NUMBER_CHECKED(int32_t, position, Int32, args[1]);
1797 CONVERT_BOOLEAN_ARG_CHECKED(with_offset, 2);
1798
1799 CHECK(script->value()->IsScript());
1800 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
1801
1802 const Script::OffsetFlag offset_flag =
1803 with_offset ? Script::WITH_OFFSET : Script::NO_OFFSET;
1804 return *GetJSPositionInfo(script_handle, position, offset_flag, isolate);
1805 }
1806
1807 // Returns the given line as a string, or null if line is out of bounds.
1808 // The parameter line is expected to include the script's line offset.
1809 // TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_ScriptSourceLine)1810 RUNTIME_FUNCTION(Runtime_ScriptSourceLine) {
1811 HandleScope scope(isolate);
1812 DCHECK(args.length() == 2);
1813 CONVERT_ARG_CHECKED(JSValue, script, 0);
1814 CONVERT_NUMBER_CHECKED(int32_t, line, Int32, args[1]);
1815
1816 CHECK(script->value()->IsScript());
1817 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
1818
1819 Script::InitLineEnds(script_handle);
1820
1821 FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends());
1822 const int line_count = line_ends_array->length();
1823
1824 line -= script_handle->line_offset();
1825 if (line < 0 || line_count <= line) {
1826 return isolate->heap()->null_value();
1827 }
1828
1829 const int start =
1830 (line == 0) ? 0 : Smi::cast(line_ends_array->get(line - 1))->value() + 1;
1831 const int end = Smi::cast(line_ends_array->get(line))->value();
1832
1833 Handle<String> source =
1834 handle(String::cast(script_handle->source()), isolate);
1835 Handle<String> str = isolate->factory()->NewSubString(source, start, end);
1836
1837 return *str;
1838 }
1839
1840 // Set one shot breakpoints for the callback function that is passed to a
1841 // built-in function such as Array.forEach to enable stepping into the callback,
1842 // if we are indeed stepping and the callback is subject to debugging.
RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping)1843 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
1844 HandleScope scope(isolate);
1845 DCHECK_EQ(1, args.length());
1846 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
1847 isolate->debug()->PrepareStepIn(fun);
1848 return isolate->heap()->undefined_value();
1849 }
1850
1851 // Set one shot breakpoints for the suspended generator object.
RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator)1852 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator) {
1853 HandleScope scope(isolate);
1854 DCHECK_EQ(0, args.length());
1855 isolate->debug()->PrepareStepInSuspendedGenerator();
1856 return isolate->heap()->undefined_value();
1857 }
1858
RUNTIME_FUNCTION(Runtime_DebugRecordAsyncFunction)1859 RUNTIME_FUNCTION(Runtime_DebugRecordAsyncFunction) {
1860 HandleScope scope(isolate);
1861 DCHECK_EQ(1, args.length());
1862 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
1863 CHECK(isolate->debug()->last_step_action() >= StepNext);
1864 isolate->debug()->RecordAsyncFunction(generator);
1865 return isolate->heap()->undefined_value();
1866 }
1867
RUNTIME_FUNCTION(Runtime_DebugPushPromise)1868 RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
1869 DCHECK(args.length() == 1);
1870 HandleScope scope(isolate);
1871 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
1872 isolate->PushPromise(promise);
1873 return isolate->heap()->undefined_value();
1874 }
1875
1876
RUNTIME_FUNCTION(Runtime_DebugPopPromise)1877 RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
1878 DCHECK(args.length() == 0);
1879 SealHandleScope shs(isolate);
1880 isolate->PopPromise();
1881 return isolate->heap()->undefined_value();
1882 }
1883
RUNTIME_FUNCTION(Runtime_DebugNextMicrotaskId)1884 RUNTIME_FUNCTION(Runtime_DebugNextMicrotaskId) {
1885 HandleScope scope(isolate);
1886 DCHECK(args.length() == 0);
1887 return Smi::FromInt(isolate->GetNextDebugMicrotaskId());
1888 }
1889
RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent)1890 RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
1891 DCHECK(args.length() == 3);
1892 HandleScope scope(isolate);
1893 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
1894 CONVERT_ARG_HANDLE_CHECKED(Object, id, 1);
1895 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
1896 isolate->debug()->OnAsyncTaskEvent(type, id, name);
1897 return isolate->heap()->undefined_value();
1898 }
1899
1900
RUNTIME_FUNCTION(Runtime_DebugIsActive)1901 RUNTIME_FUNCTION(Runtime_DebugIsActive) {
1902 SealHandleScope shs(isolate);
1903 return Smi::FromInt(isolate->debug()->is_active());
1904 }
1905
1906
RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode)1907 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) {
1908 UNIMPLEMENTED();
1909 return NULL;
1910 }
1911
1912 } // namespace internal
1913 } // namespace v8
1914