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