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