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 <vector>
6 :
7 : #include "src/arguments-inl.h"
8 : #include "src/compiler.h"
9 : #include "src/counters.h"
10 : #include "src/debug/debug-coverage.h"
11 : #include "src/debug/debug-evaluate.h"
12 : #include "src/debug/debug-frames.h"
13 : #include "src/debug/debug-scopes.h"
14 : #include "src/debug/debug.h"
15 : #include "src/debug/liveedit.h"
16 : #include "src/frames-inl.h"
17 : #include "src/globals.h"
18 : #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
19 : #include "src/interpreter/bytecode-array-accessor.h"
20 : #include "src/interpreter/bytecodes.h"
21 : #include "src/interpreter/interpreter.h"
22 : #include "src/isolate-inl.h"
23 : #include "src/objects/debug-objects-inl.h"
24 : #include "src/objects/heap-object-inl.h"
25 : #include "src/objects/js-collection-inl.h"
26 : #include "src/objects/js-generator-inl.h"
27 : #include "src/objects/js-promise-inl.h"
28 : #include "src/runtime/runtime-utils.h"
29 : #include "src/runtime/runtime.h"
30 : #include "src/snapshot/snapshot.h"
31 : #include "src/wasm/wasm-objects-inl.h"
32 :
33 : namespace v8 {
34 : namespace internal {
35 :
36 599752 : RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) {
37 : using interpreter::Bytecode;
38 : using interpreter::Bytecodes;
39 : using interpreter::OperandScale;
40 :
41 : SealHandleScope shs(isolate);
42 : DCHECK_EQ(1, args.length());
43 66666 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
44 66666 : HandleScope scope(isolate);
45 :
46 : // Return value can be changed by debugger. Last set value will be used as
47 : // return value.
48 133332 : ReturnValueScope result_scope(isolate->debug());
49 66666 : isolate->debug()->set_return_value(*value);
50 :
51 : // Get the top-most JavaScript frame.
52 133332 : JavaScriptFrameIterator it(isolate);
53 66666 : if (isolate->debug_execution_mode() == DebugInfo::kBreakpoints) {
54 : isolate->debug()->Break(it.frame(),
55 192999 : handle(it.frame()->function(), isolate));
56 : }
57 :
58 : // If we are dropping frames, there is no need to get a return value or
59 : // bytecode, since we will be restarting execution at a different frame.
60 66666 : if (isolate->debug()->will_restart()) {
61 : return MakePair(ReadOnlyRoots(isolate).undefined_value(),
62 46 : Smi::FromInt(static_cast<uint8_t>(Bytecode::kIllegal)));
63 : }
64 :
65 : // Return the handler from the original bytecode array.
66 : DCHECK(it.frame()->is_interpreted());
67 : InterpretedFrame* interpreted_frame =
68 66643 : reinterpret_cast<InterpretedFrame*>(it.frame());
69 66643 : SharedFunctionInfo shared = interpreted_frame->function()->shared();
70 66643 : BytecodeArray bytecode_array = shared->GetBytecodeArray();
71 66643 : int bytecode_offset = interpreted_frame->GetBytecodeOffset();
72 66643 : Bytecode bytecode = Bytecodes::FromByte(bytecode_array->get(bytecode_offset));
73 :
74 : bool side_effect_check_failed = false;
75 66643 : if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
76 : side_effect_check_failed =
77 2333 : !isolate->debug()->PerformSideEffectCheckAtBytecode(interpreted_frame);
78 : }
79 :
80 66643 : if (Bytecodes::Returns(bytecode)) {
81 : // If we are returning (or suspending), reset the bytecode array on the
82 : // interpreted stack frame to the non-debug variant so that the interpreter
83 : // entry trampoline sees the return/suspend bytecode rather than the
84 : // DebugBreak.
85 7247 : interpreted_frame->PatchBytecodeArray(bytecode_array);
86 : }
87 :
88 : // We do not have to deal with operand scale here. If the bytecode at the
89 : // break is prefixed by operand scaling, we would have patched over the
90 : // scaling prefix. We now simply dispatch to the handler for the prefix.
91 : // We need to deserialize now to ensure we don't hit the debug break again
92 : // after deserializing.
93 : OperandScale operand_scale = OperandScale::kSingle;
94 66643 : isolate->interpreter()->GetBytecodeHandler(bytecode, operand_scale);
95 :
96 66643 : if (side_effect_check_failed) {
97 : return MakePair(ReadOnlyRoots(isolate).exception(),
98 336 : Smi::FromInt(static_cast<uint8_t>(bytecode)));
99 : }
100 66475 : Object interrupt_object = isolate->stack_guard()->HandleInterrupts();
101 132950 : if (interrupt_object->IsException(isolate)) {
102 : return MakePair(interrupt_object,
103 5 : Smi::FromInt(static_cast<uint8_t>(bytecode)));
104 : }
105 : return MakePair(isolate->debug()->return_value(),
106 199606 : Smi::FromInt(static_cast<uint8_t>(bytecode)));
107 : }
108 :
109 940 : RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) {
110 470 : HandleScope scope(isolate);
111 : DCHECK_EQ(1, args.length());
112 940 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
113 470 : USE(function);
114 :
115 : DCHECK(function->shared()->HasDebugInfo());
116 : DCHECK(function->shared()->GetDebugInfo()->BreakAtEntry());
117 :
118 : // Get the top-most JavaScript frame.
119 940 : JavaScriptFrameIterator it(isolate);
120 : DCHECK_EQ(*function, it.frame()->function());
121 940 : isolate->debug()->Break(it.frame(), function);
122 :
123 470 : return ReadOnlyRoots(isolate).undefined_value();
124 : }
125 :
126 8493 : RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
127 : SealHandleScope shs(isolate);
128 : DCHECK_EQ(0, args.length());
129 8493 : if (isolate->debug()->break_points_active()) {
130 8435 : isolate->debug()->HandleDebugBreak(kIgnoreIfTopFrameBlackboxed);
131 : }
132 8493 : return isolate->stack_guard()->HandleInterrupts();
133 : }
134 :
135 126 : RUNTIME_FUNCTION(Runtime_ScheduleBreak) {
136 : SealHandleScope shs(isolate);
137 : DCHECK_EQ(0, args.length());
138 : isolate->RequestInterrupt(
139 247 : [](v8::Isolate* isolate, void*) { v8::debug::BreakRightNow(isolate); },
140 126 : nullptr);
141 : return ReadOnlyRoots(isolate).undefined_value();
142 : }
143 :
144 : template <class IteratorType>
145 159 : static MaybeHandle<JSArray> GetIteratorInternalProperties(
146 : Isolate* isolate, Handle<IteratorType> object) {
147 : Factory* factory = isolate->factory();
148 159 : Handle<IteratorType> iterator = Handle<IteratorType>::cast(object);
149 : const char* kind = nullptr;
150 159 : switch (iterator->map()->instance_type()) {
151 : case JS_MAP_KEY_ITERATOR_TYPE:
152 : kind = "keys";
153 : break;
154 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
155 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
156 : kind = "entries";
157 73 : break;
158 : case JS_MAP_VALUE_ITERATOR_TYPE:
159 : case JS_SET_VALUE_ITERATOR_TYPE:
160 : kind = "values";
161 72 : break;
162 : default:
163 0 : UNREACHABLE();
164 : }
165 :
166 159 : Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
167 : Handle<String> has_more =
168 159 : factory->NewStringFromAsciiChecked("[[IteratorHasMore]]");
169 318 : result->set(0, *has_more);
170 318 : result->set(1, isolate->heap()->ToBoolean(iterator->HasMore()));
171 :
172 : Handle<String> index =
173 159 : factory->NewStringFromAsciiChecked("[[IteratorIndex]]");
174 318 : result->set(2, *index);
175 159 : result->set(3, iterator->index());
176 :
177 : Handle<String> iterator_kind =
178 159 : factory->NewStringFromAsciiChecked("[[IteratorKind]]");
179 318 : result->set(4, *iterator_kind);
180 159 : Handle<String> kind_str = factory->NewStringFromAsciiChecked(kind);
181 318 : result->set(5, *kind_str);
182 159 : return factory->NewJSArrayWithElements(result);
183 : }
184 :
185 :
186 79153 : MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
187 : Handle<Object> object) {
188 : Factory* factory = isolate->factory();
189 158306 : if (object->IsJSBoundFunction()) {
190 5 : Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object);
191 :
192 5 : Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
193 : Handle<String> target =
194 5 : factory->NewStringFromAsciiChecked("[[TargetFunction]]");
195 10 : result->set(0, *target);
196 10 : result->set(1, function->bound_target_function());
197 :
198 : Handle<String> bound_this =
199 5 : factory->NewStringFromAsciiChecked("[[BoundThis]]");
200 10 : result->set(2, *bound_this);
201 5 : result->set(3, function->bound_this());
202 :
203 : Handle<String> bound_args =
204 5 : factory->NewStringFromAsciiChecked("[[BoundArgs]]");
205 10 : result->set(4, *bound_args);
206 : Handle<FixedArray> bound_arguments =
207 10 : factory->CopyFixedArray(handle(function->bound_arguments(), isolate));
208 : Handle<JSArray> arguments_array =
209 5 : factory->NewJSArrayWithElements(bound_arguments);
210 10 : result->set(5, *arguments_array);
211 5 : return factory->NewJSArrayWithElements(result);
212 158296 : } else if (object->IsJSMapIterator()) {
213 87 : Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object);
214 87 : return GetIteratorInternalProperties(isolate, iterator);
215 158122 : } else if (object->IsJSSetIterator()) {
216 72 : Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object);
217 72 : return GetIteratorInternalProperties(isolate, iterator);
218 157978 : } else if (object->IsJSGeneratorObject()) {
219 : Handle<JSGeneratorObject> generator =
220 50 : Handle<JSGeneratorObject>::cast(object);
221 :
222 : const char* status = "suspended";
223 50 : if (generator->is_closed()) {
224 : status = "closed";
225 40 : } else if (generator->is_executing()) {
226 : status = "running";
227 : } else {
228 : DCHECK(generator->is_suspended());
229 : }
230 :
231 50 : Handle<FixedArray> result = factory->NewFixedArray(2 * 3);
232 : Handle<String> generator_status =
233 50 : factory->NewStringFromAsciiChecked("[[GeneratorStatus]]");
234 100 : result->set(0, *generator_status);
235 50 : Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
236 100 : result->set(1, *status_str);
237 :
238 : Handle<String> function =
239 50 : factory->NewStringFromAsciiChecked("[[GeneratorFunction]]");
240 100 : result->set(2, *function);
241 100 : result->set(3, generator->function());
242 :
243 : Handle<String> receiver =
244 50 : factory->NewStringFromAsciiChecked("[[GeneratorReceiver]]");
245 100 : result->set(4, *receiver);
246 50 : result->set(5, generator->receiver());
247 50 : return factory->NewJSArrayWithElements(result);
248 157878 : } else if (object->IsJSPromise()) {
249 40 : Handle<JSPromise> promise = Handle<JSPromise>::cast(object);
250 40 : const char* status = JSPromise::Status(promise->status());
251 40 : Handle<FixedArray> result = factory->NewFixedArray(2 * 2);
252 : Handle<String> promise_status =
253 40 : factory->NewStringFromAsciiChecked("[[PromiseStatus]]");
254 80 : result->set(0, *promise_status);
255 40 : Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
256 80 : result->set(1, *status_str);
257 :
258 80 : Handle<Object> value_obj(promise->status() == Promise::kPending
259 : ? ReadOnlyRoots(isolate).undefined_value()
260 : : promise->result(),
261 40 : isolate);
262 : Handle<String> promise_value =
263 40 : factory->NewStringFromAsciiChecked("[[PromiseValue]]");
264 80 : result->set(2, *promise_value);
265 40 : result->set(3, *value_obj);
266 40 : return factory->NewJSArrayWithElements(result);
267 157798 : } else if (object->IsJSProxy()) {
268 15 : Handle<JSProxy> js_proxy = Handle<JSProxy>::cast(object);
269 15 : Handle<FixedArray> result = factory->NewFixedArray(3 * 2);
270 :
271 : Handle<String> handler_str =
272 15 : factory->NewStringFromAsciiChecked("[[Handler]]");
273 30 : result->set(0, *handler_str);
274 15 : result->set(1, js_proxy->handler());
275 :
276 : Handle<String> target_str =
277 15 : factory->NewStringFromAsciiChecked("[[Target]]");
278 30 : result->set(2, *target_str);
279 15 : result->set(3, js_proxy->target());
280 :
281 : Handle<String> is_revoked_str =
282 15 : factory->NewStringFromAsciiChecked("[[IsRevoked]]");
283 30 : result->set(4, *is_revoked_str);
284 45 : result->set(5, isolate->heap()->ToBoolean(js_proxy->IsRevoked()));
285 15 : return factory->NewJSArrayWithElements(result);
286 157768 : } else if (object->IsJSValue()) {
287 118 : Handle<JSValue> js_value = Handle<JSValue>::cast(object);
288 :
289 118 : Handle<FixedArray> result = factory->NewFixedArray(2);
290 : Handle<String> primitive_value =
291 118 : factory->NewStringFromAsciiChecked("[[PrimitiveValue]]");
292 236 : result->set(0, *primitive_value);
293 118 : result->set(1, js_value->value());
294 118 : return factory->NewJSArrayWithElements(result);
295 : }
296 78766 : return factory->NewJSArray(0);
297 : }
298 :
299 288 : RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) {
300 288 : HandleScope scope(isolate);
301 : DCHECK_EQ(1, args.length());
302 :
303 576 : if (!args[0]->IsJSGeneratorObject()) return Smi::kZero;
304 :
305 : // Check arguments.
306 576 : CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
307 :
308 : // Only inspect suspended generator scopes.
309 288 : if (!gen->is_suspended()) {
310 : return Smi::kZero;
311 : }
312 :
313 : // Count the visible scopes.
314 : int n = 0;
315 1368 : for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) {
316 1080 : n++;
317 288 : }
318 :
319 288 : return Smi::FromInt(n);
320 : }
321 :
322 945 : RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) {
323 945 : HandleScope scope(isolate);
324 : DCHECK_EQ(2, args.length());
325 :
326 1890 : if (!args[0]->IsJSGeneratorObject()) {
327 : return ReadOnlyRoots(isolate).undefined_value();
328 : }
329 :
330 : // Check arguments.
331 1890 : CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
332 1890 : CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
333 :
334 : // Only inspect suspended generator scopes.
335 945 : if (!gen->is_suspended()) {
336 : return ReadOnlyRoots(isolate).undefined_value();
337 : }
338 :
339 : // Find the requested scope.
340 : int n = 0;
341 1890 : ScopeIterator it(isolate, gen);
342 927 : for (; !it.Done() && n < index; it.Next()) {
343 927 : n++;
344 : }
345 945 : if (it.Done()) {
346 : return ReadOnlyRoots(isolate).undefined_value();
347 : }
348 :
349 2835 : return *it.MaterializeScopeDetails();
350 : }
351 :
352 117 : static bool SetScopeVariableValue(ScopeIterator* it, int index,
353 : Handle<String> variable_name,
354 : Handle<Object> new_value) {
355 378 : for (int n = 0; !it->Done() && n < index; it->Next()) {
356 72 : n++;
357 : }
358 117 : if (it->Done()) {
359 : return false;
360 : }
361 117 : return it->SetVariableValue(variable_name, new_value);
362 : }
363 :
364 : // Change variable value in closure or local scope
365 : // args[0]: number or JsFunction: break id or function
366 : // args[1]: number: scope index
367 : // args[2]: string: variable name
368 : // args[3]: object: new value
369 : //
370 : // Return true if success and false otherwise
371 117 : RUNTIME_FUNCTION(Runtime_SetGeneratorScopeVariableValue) {
372 117 : HandleScope scope(isolate);
373 : DCHECK_EQ(4, args.length());
374 234 : CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
375 234 : CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
376 234 : CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 2);
377 117 : CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 3);
378 234 : ScopeIterator it(isolate, gen);
379 117 : bool res = SetScopeVariableValue(&it, index, variable_name, new_value);
380 234 : return isolate->heap()->ToBoolean(res);
381 : }
382 :
383 :
384 1134 : RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
385 567 : HandleScope scope(isolate);
386 : DCHECK_EQ(1, args.length());
387 567 : CHECK(isolate->debug()->is_active());
388 1134 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
389 :
390 1134 : Handle<SharedFunctionInfo> shared(fun->shared(), isolate);
391 : // Find the number of break points
392 : Handle<Object> break_locations =
393 567 : Debug::GetSourceBreakLocations(isolate, shared);
394 1134 : if (break_locations->IsUndefined(isolate)) {
395 : return ReadOnlyRoots(isolate).undefined_value();
396 : }
397 : // Return array as JS array
398 : return *isolate->factory()->NewJSArrayWithElements(
399 1242 : Handle<FixedArray>::cast(break_locations));
400 : }
401 :
402 :
403 : // Returns the state of break on exceptions
404 : // args[0]: boolean indicating uncaught exceptions
405 6642 : RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
406 3321 : HandleScope scope(isolate);
407 : DCHECK_EQ(1, args.length());
408 6642 : CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
409 :
410 : ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
411 3321 : bool result = isolate->debug()->IsBreakOnException(type);
412 3321 : return Smi::FromInt(result);
413 : }
414 :
415 : // Clear all stepping set by PrepareStep.
416 54 : RUNTIME_FUNCTION(Runtime_ClearStepping) {
417 18 : HandleScope scope(isolate);
418 : DCHECK_EQ(0, args.length());
419 18 : CHECK(isolate->debug()->is_active());
420 18 : isolate->debug()->ClearStepping();
421 18 : return ReadOnlyRoots(isolate).undefined_value();
422 : }
423 :
424 339 : RUNTIME_FUNCTION(Runtime_DebugGetLoadedScriptIds) {
425 113 : HandleScope scope(isolate);
426 : DCHECK_EQ(0, args.length());
427 :
428 : Handle<FixedArray> instances;
429 : {
430 113 : DebugScope debug_scope(isolate->debug());
431 : // Fill the script objects.
432 113 : instances = isolate->debug()->GetLoadedScripts();
433 : }
434 :
435 : // Convert the script objects to proper JS objects.
436 1329 : for (int i = 0; i < instances->length(); i++) {
437 1216 : Handle<Script> script(Script::cast(instances->get(i)), isolate);
438 1216 : instances->set(i, Smi::FromInt(script->id()));
439 : }
440 :
441 : // Return result as a JS array.
442 226 : return *isolate->factory()->NewJSArrayWithElements(instances);
443 : }
444 :
445 :
446 69 : RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
447 : SealHandleScope shs(isolate);
448 : DCHECK_EQ(1, args.length());
449 :
450 69 : CONVERT_ARG_CHECKED(Object, f, 0);
451 138 : if (f->IsJSFunction()) {
452 60 : return JSFunction::cast(f)->shared()->inferred_name();
453 : }
454 : return ReadOnlyRoots(isolate).empty_string();
455 : }
456 :
457 :
458 : // Performs a GC.
459 : // Presently, it only does a full GC.
460 264 : RUNTIME_FUNCTION(Runtime_CollectGarbage) {
461 : SealHandleScope shs(isolate);
462 : DCHECK_EQ(1, args.length());
463 : isolate->heap()->PreciseCollectAllGarbage(Heap::kNoGCFlags,
464 264 : GarbageCollectionReason::kRuntime);
465 : return ReadOnlyRoots(isolate).undefined_value();
466 : }
467 :
468 :
469 : // Gets the current heap usage.
470 0 : RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
471 : SealHandleScope shs(isolate);
472 : DCHECK_EQ(0, args.length());
473 0 : int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
474 0 : if (!Smi::IsValid(usage)) {
475 0 : return *isolate->factory()->NewNumberFromInt(usage);
476 : }
477 0 : return Smi::FromInt(usage);
478 : }
479 :
480 : namespace {
481 :
482 131478 : int ScriptLinePosition(Handle<Script> script, int line) {
483 131478 : if (line < 0) return -1;
484 :
485 131478 : if (script->type() == Script::TYPE_WASM) {
486 : return WasmModuleObject::cast(script->wasm_module_object())
487 32 : ->GetFunctionOffset(line);
488 : }
489 :
490 131462 : Script::InitLineEnds(script);
491 :
492 : FixedArray line_ends_array = FixedArray::cast(script->line_ends());
493 : const int line_count = line_ends_array->length();
494 : DCHECK_LT(0, line_count);
495 :
496 131462 : if (line == 0) return 0;
497 : // If line == line_count, we return the first position beyond the last line.
498 109460 : if (line > line_count) return -1;
499 218920 : return Smi::ToInt(line_ends_array->get(line - 1)) + 1;
500 : }
501 :
502 131478 : int ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset) {
503 131478 : if (line < 0 || offset < 0) return -1;
504 :
505 131478 : if (line == 0 || offset == 0)
506 130817 : return ScriptLinePosition(script, line) + offset;
507 :
508 : Script::PositionInfo info;
509 661 : if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET)) {
510 : return -1;
511 : }
512 :
513 661 : const int total_line = info.line + line;
514 661 : return ScriptLinePosition(script, total_line);
515 : }
516 :
517 131478 : Handle<Object> GetJSPositionInfo(Handle<Script> script, int position,
518 : Script::OffsetFlag offset_flag,
519 : Isolate* isolate) {
520 : Script::PositionInfo info;
521 131478 : if (!Script::GetPositionInfo(script, position, &info, offset_flag)) {
522 0 : return isolate->factory()->null_value();
523 : }
524 :
525 131478 : Handle<String> source = handle(String::cast(script->source()), isolate);
526 : Handle<String> sourceText = script->type() == Script::TYPE_WASM
527 : ? isolate->factory()->empty_string()
528 : : isolate->factory()->NewSubString(
529 262940 : source, info.line_start, info.line_end);
530 :
531 : Handle<JSObject> jsinfo =
532 131478 : isolate->factory()->NewJSObject(isolate->object_function());
533 :
534 : JSObject::AddProperty(isolate, jsinfo, isolate->factory()->script_string(),
535 131478 : script, NONE);
536 : JSObject::AddProperty(isolate, jsinfo, isolate->factory()->position_string(),
537 131478 : handle(Smi::FromInt(position), isolate), NONE);
538 : JSObject::AddProperty(isolate, jsinfo, isolate->factory()->line_string(),
539 262956 : handle(Smi::FromInt(info.line), isolate), NONE);
540 : JSObject::AddProperty(isolate, jsinfo, isolate->factory()->column_string(),
541 262956 : handle(Smi::FromInt(info.column), isolate), NONE);
542 : JSObject::AddProperty(isolate, jsinfo,
543 : isolate->factory()->sourceText_string(), sourceText,
544 131478 : NONE);
545 :
546 131478 : return jsinfo;
547 : }
548 :
549 131478 : Handle<Object> ScriptLocationFromLine(Isolate* isolate, Handle<Script> script,
550 : Handle<Object> opt_line,
551 : Handle<Object> opt_column,
552 : int32_t offset) {
553 : // Line and column are possibly undefined and we need to handle these cases,
554 : // additionally subtracting corresponding offsets.
555 :
556 : int32_t line = 0;
557 262956 : if (!opt_line->IsNullOrUndefined(isolate)) {
558 262678 : CHECK(opt_line->IsNumber());
559 262678 : line = NumberToInt32(*opt_line) - script->line_offset();
560 : }
561 :
562 : int32_t column = 0;
563 262956 : if (!opt_column->IsNullOrUndefined(isolate)) {
564 261906 : CHECK(opt_column->IsNumber());
565 130953 : column = NumberToInt32(*opt_column);
566 152735 : if (line == 0) column -= script->column_offset();
567 : }
568 :
569 131478 : int line_position = ScriptLinePositionWithOffset(script, line, offset);
570 131478 : if (line_position < 0 || column < 0) return isolate->factory()->null_value();
571 :
572 : return GetJSPositionInfo(script, line_position + column, Script::NO_OFFSET,
573 131478 : isolate);
574 : }
575 :
576 : // Slow traversal over all scripts on the heap.
577 131478 : bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) {
578 131478 : Script::Iterator iterator(isolate);
579 5140715 : for (Script script = iterator.Next(); !script.is_null();
580 : script = iterator.Next()) {
581 5140715 : if (script->id() == needle) {
582 131478 : *result = handle(script, isolate);
583 : return true;
584 : }
585 : }
586 :
587 : return false;
588 : }
589 :
590 : } // namespace
591 :
592 : // TODO(5530): Rename once conflicting function has been deleted.
593 131478 : RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) {
594 131478 : HandleScope scope(isolate);
595 : DCHECK_EQ(4, args.length());
596 262956 : CONVERT_NUMBER_CHECKED(int32_t, scriptid, Int32, args[0]);
597 131478 : CONVERT_ARG_HANDLE_CHECKED(Object, opt_line, 1);
598 131478 : CONVERT_ARG_HANDLE_CHECKED(Object, opt_column, 2);
599 262956 : CONVERT_NUMBER_CHECKED(int32_t, offset, Int32, args[3]);
600 :
601 : Handle<Script> script;
602 131478 : CHECK(GetScriptById(isolate, scriptid, &script));
603 :
604 262956 : return *ScriptLocationFromLine(isolate, script, opt_line, opt_column, offset);
605 : }
606 :
607 : // On function call, depending on circumstances, prepare for stepping in,
608 : // or perform a side effect check.
609 2711637 : RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) {
610 538837 : HandleScope scope(isolate);
611 : DCHECK_EQ(2, args.length());
612 1077674 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
613 538837 : CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
614 538837 : if (isolate->debug()->needs_check_on_function_call()) {
615 : // Ensure that the callee will perform debug check on function call too.
616 1077674 : Deoptimizer::DeoptimizeFunction(*fun);
617 556289 : if (isolate->debug()->last_step_action() >= StepIn ||
618 17452 : isolate->debug()->break_on_next_function_call()) {
619 : DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kBreakpoints);
620 528275 : isolate->debug()->PrepareStepIn(fun);
621 : }
622 549399 : if (isolate->debug_execution_mode() == DebugInfo::kSideEffects &&
623 10562 : !isolate->debug()->PerformSideEffectCheck(fun, receiver)) {
624 : return ReadOnlyRoots(isolate).exception();
625 : }
626 : }
627 538837 : return ReadOnlyRoots(isolate).undefined_value();
628 : }
629 :
630 : // Set one shot breakpoints for the suspended generator object.
631 524 : RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator) {
632 262 : HandleScope scope(isolate);
633 : DCHECK_EQ(0, args.length());
634 262 : isolate->debug()->PrepareStepInSuspendedGenerator();
635 262 : return ReadOnlyRoots(isolate).undefined_value();
636 : }
637 :
638 1753 : RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
639 : DCHECK_EQ(1, args.length());
640 1753 : HandleScope scope(isolate);
641 3506 : CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
642 1753 : isolate->PushPromise(promise);
643 1753 : return ReadOnlyRoots(isolate).undefined_value();
644 : }
645 :
646 :
647 1744 : RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
648 : DCHECK_EQ(0, args.length());
649 : SealHandleScope shs(isolate);
650 1744 : isolate->PopPromise();
651 : return ReadOnlyRoots(isolate).undefined_value();
652 : }
653 :
654 : namespace {
655 7159 : Handle<JSObject> MakeRangeObject(Isolate* isolate, const CoverageBlock& range) {
656 : Factory* factory = isolate->factory();
657 :
658 7159 : Handle<String> start_string = factory->InternalizeUtf8String("start");
659 7159 : Handle<String> end_string = factory->InternalizeUtf8String("end");
660 7159 : Handle<String> count_string = factory->InternalizeUtf8String("count");
661 :
662 7159 : Handle<JSObject> range_obj = factory->NewJSObjectWithNullProto();
663 : JSObject::AddProperty(isolate, range_obj, start_string,
664 14318 : factory->NewNumberFromInt(range.start), NONE);
665 : JSObject::AddProperty(isolate, range_obj, end_string,
666 14318 : factory->NewNumberFromInt(range.end), NONE);
667 : JSObject::AddProperty(isolate, range_obj, count_string,
668 14318 : factory->NewNumberFromUint(range.count), NONE);
669 :
670 7159 : return range_obj;
671 : }
672 : } // namespace
673 :
674 292 : RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) {
675 292 : HandleScope scope(isolate);
676 : DCHECK_EQ(0, args.length());
677 : // Collect coverage data.
678 584 : std::unique_ptr<Coverage> coverage;
679 292 : if (isolate->is_best_effort_code_coverage()) {
680 28 : coverage = Coverage::CollectBestEffort(isolate);
681 : } else {
682 264 : coverage = Coverage::CollectPrecise(isolate);
683 : }
684 292 : Factory* factory = isolate->factory();
685 : // Turn the returned data structure into JavaScript.
686 : // Create an array of scripts.
687 292 : int num_scripts = static_cast<int>(coverage->size());
688 : // Prepare property keys.
689 292 : Handle<FixedArray> scripts_array = factory->NewFixedArray(num_scripts);
690 292 : Handle<String> script_string = factory->NewStringFromStaticChars("script");
691 908 : for (int i = 0; i < num_scripts; i++) {
692 908 : const auto& script_data = coverage->at(i);
693 908 : HandleScope inner_scope(isolate);
694 :
695 1816 : std::vector<CoverageBlock> ranges;
696 4643 : int num_functions = static_cast<int>(script_data.functions.size());
697 3735 : for (int j = 0; j < num_functions; j++) {
698 7470 : const auto& function_data = script_data.functions[j];
699 : ranges.emplace_back(function_data.start, function_data.end,
700 3735 : function_data.count);
701 10583 : for (size_t k = 0; k < function_data.blocks.size(); k++) {
702 10583 : const auto& block_data = function_data.blocks[k];
703 3424 : ranges.emplace_back(block_data.start, block_data.end, block_data.count);
704 : }
705 : }
706 :
707 908 : int num_ranges = static_cast<int>(ranges.size());
708 908 : Handle<FixedArray> ranges_array = factory->NewFixedArray(num_ranges);
709 7159 : for (int j = 0; j < num_ranges; j++) {
710 7159 : Handle<JSObject> range_object = MakeRangeObject(isolate, ranges[j]);
711 14318 : ranges_array->set(j, *range_object);
712 : }
713 :
714 : Handle<JSArray> script_obj =
715 908 : factory->NewJSArrayWithElements(ranges_array, PACKED_ELEMENTS);
716 : JSObject::AddProperty(isolate, script_obj, script_string,
717 1816 : handle(script_data.script->source(), isolate), NONE);
718 1816 : scripts_array->set(i, *script_obj);
719 908 : }
720 876 : return *factory->NewJSArrayWithElements(scripts_array, PACKED_ELEMENTS);
721 : }
722 :
723 8 : RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage) {
724 : SealHandleScope shs(isolate);
725 24 : CONVERT_BOOLEAN_ARG_CHECKED(enable, 0);
726 : Coverage::SelectMode(isolate, enable ? debug::Coverage::kPreciseCount
727 8 : : debug::Coverage::kBestEffort);
728 : return ReadOnlyRoots(isolate).undefined_value();
729 : }
730 :
731 37 : RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage) {
732 : SealHandleScope shs(isolate);
733 111 : CONVERT_BOOLEAN_ARG_CHECKED(enable, 0);
734 : Coverage::SelectMode(isolate, enable ? debug::Coverage::kBlockCount
735 37 : : debug::Coverage::kBestEffort);
736 : return ReadOnlyRoots(isolate).undefined_value();
737 : }
738 :
739 179448 : RUNTIME_FUNCTION(Runtime_IncBlockCounter) {
740 : SealHandleScope scope(isolate);
741 : DCHECK_EQ(2, args.length());
742 538344 : CONVERT_ARG_CHECKED(JSFunction, function, 0);
743 358896 : CONVERT_SMI_ARG_CHECKED(coverage_array_slot_index, 1);
744 :
745 : // It's quite possible that a function contains IncBlockCounter bytecodes, but
746 : // no coverage info exists. This happens e.g. by selecting the best-effort
747 : // coverage collection mode, which triggers deletion of all coverage infos in
748 : // order to avoid memory leaks.
749 :
750 179448 : SharedFunctionInfo shared = function->shared();
751 179448 : if (shared->HasCoverageInfo()) {
752 179448 : CoverageInfo coverage_info = shared->GetCoverageInfo();
753 179448 : coverage_info->IncrementBlockCount(coverage_array_slot_index);
754 : }
755 :
756 : return ReadOnlyRoots(isolate).undefined_value();
757 : }
758 :
759 9548 : RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionEntered) {
760 : DCHECK_EQ(1, args.length());
761 4774 : HandleScope scope(isolate);
762 9548 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
763 : isolate->RunPromiseHook(PromiseHookType::kInit, promise,
764 9548 : isolate->factory()->undefined_value());
765 9483 : if (isolate->debug()->is_active()) isolate->PushPromise(promise);
766 4774 : return ReadOnlyRoots(isolate).undefined_value();
767 : }
768 :
769 4709 : RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionFinished) {
770 : DCHECK_EQ(2, args.length());
771 4709 : HandleScope scope(isolate);
772 14127 : CONVERT_BOOLEAN_ARG_CHECKED(has_suspend, 0);
773 9418 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
774 4709 : isolate->PopPromise();
775 4709 : if (has_suspend) {
776 : isolate->OnAsyncFunctionStateChanged(promise,
777 3417 : debug::kAsyncFunctionFinished);
778 : }
779 4709 : return *promise;
780 : }
781 :
782 275 : RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended) {
783 : DCHECK_EQ(1, args.length());
784 275 : HandleScope scope(isolate);
785 550 : CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
786 275 : isolate->OnAsyncFunctionStateChanged(promise, debug::kAsyncFunctionSuspended);
787 275 : return ReadOnlyRoots(isolate).undefined_value();
788 : }
789 :
790 561 : RUNTIME_FUNCTION(Runtime_LiveEditPatchScript) {
791 561 : HandleScope scope(isolate);
792 : DCHECK_EQ(2, args.length());
793 1122 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, script_function, 0);
794 1122 : CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
795 :
796 1122 : Handle<Script> script(Script::cast(script_function->shared()->script()),
797 1122 : isolate);
798 561 : v8::debug::LiveEditResult result;
799 561 : LiveEdit::PatchScript(isolate, script, new_source, false, &result);
800 561 : switch (result.status) {
801 : case v8::debug::LiveEditResult::COMPILE_ERROR:
802 : return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
803 18 : "LiveEdit failed: COMPILE_ERROR"));
804 : case v8::debug::LiveEditResult::BLOCKED_BY_RUNNING_GENERATOR:
805 : return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
806 36 : "LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR"));
807 : case v8::debug::LiveEditResult::BLOCKED_BY_FUNCTION_ABOVE_BREAK_FRAME:
808 : return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
809 0 : "LiveEdit failed: BLOCKED_BY_FUNCTION_ABOVE_BREAK_FRAME"));
810 : case v8::debug::LiveEditResult::
811 : BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME:
812 : return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
813 108 : "LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME"));
814 : case v8::debug::LiveEditResult::BLOCKED_BY_ACTIVE_FUNCTION:
815 : return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
816 0 : "LiveEdit failed: BLOCKED_BY_ACTIVE_FUNCTION"));
817 : case v8::debug::LiveEditResult::BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME:
818 : return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
819 72 : "LiveEdit failed: BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME"));
820 : case v8::debug::LiveEditResult::FRAME_RESTART_IS_NOT_SUPPORTED:
821 : return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
822 0 : "LiveEdit failed: FRAME_RESTART_IS_NOT_SUPPORTED"));
823 : case v8::debug::LiveEditResult::OK:
824 : return ReadOnlyRoots(isolate).undefined_value();
825 : }
826 561 : return ReadOnlyRoots(isolate).undefined_value();
827 : }
828 :
829 0 : RUNTIME_FUNCTION(Runtime_PerformSideEffectCheckForObject) {
830 0 : HandleScope scope(isolate);
831 : DCHECK_EQ(1, args.length());
832 0 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
833 :
834 : DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kSideEffects);
835 0 : if (!isolate->debug()->PerformSideEffectCheckForObject(object)) {
836 : DCHECK(isolate->has_pending_exception());
837 : return ReadOnlyRoots(isolate).exception();
838 : }
839 0 : return ReadOnlyRoots(isolate).undefined_value();
840 : }
841 :
842 : } // namespace internal
843 178779 : } // namespace v8
|