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