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