• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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