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/codegen/compiler.h"
8 #include "src/common/globals.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/deoptimizer/deoptimizer.h"
16 #include "src/execution/arguments-inl.h"
17 #include "src/execution/frames-inl.h"
18 #include "src/execution/isolate-inl.h"
19 #include "src/heap/heap-inl.h"  // For ToBoolean. TODO(jkummerow): Drop.
20 #include "src/interpreter/bytecode-array-iterator.h"
21 #include "src/interpreter/bytecodes.h"
22 #include "src/interpreter/interpreter.h"
23 #include "src/logging/counters.h"
24 #include "src/objects/debug-objects-inl.h"
25 #include "src/objects/heap-object-inl.h"
26 #include "src/objects/js-array-buffer-inl.h"
27 #include "src/objects/js-collection-inl.h"
28 #include "src/objects/js-generator-inl.h"
29 #include "src/objects/js-promise-inl.h"
30 #include "src/runtime/runtime-utils.h"
31 #include "src/runtime/runtime.h"
32 #include "src/snapshot/embedded/embedded-data.h"
33 #include "src/snapshot/snapshot.h"
34 
35 #if V8_ENABLE_WEBASSEMBLY
36 #include "src/debug/debug-wasm-objects.h"
37 #include "src/wasm/wasm-objects-inl.h"
38 #endif  // V8_ENABLE_WEBASSEMBLY
39 
40 namespace v8 {
41 namespace internal {
42 
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode)43 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) {
44   using interpreter::Bytecode;
45   using interpreter::Bytecodes;
46   using interpreter::OperandScale;
47 
48   SealHandleScope shs(isolate);
49   DCHECK_EQ(1, args.length());
50   Handle<Object> value = args.at(0);
51   HandleScope scope(isolate);
52 
53   // Return value can be changed by debugger. Last set value will be used as
54   // return value.
55   ReturnValueScope result_scope(isolate->debug());
56   isolate->debug()->set_return_value(*value);
57 
58   // Get the top-most JavaScript frame.
59   JavaScriptFrameIterator it(isolate);
60   if (isolate->debug_execution_mode() == DebugInfo::kBreakpoints) {
61     isolate->debug()->Break(it.frame(),
62                             handle(it.frame()->function(), isolate));
63   }
64 
65   // Return the handler from the original bytecode array.
66   DCHECK(it.frame()->is_interpreted());
67   InterpretedFrame* interpreted_frame =
68       reinterpret_cast<InterpretedFrame*>(it.frame());
69 
70   bool side_effect_check_failed = false;
71   if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
72     side_effect_check_failed =
73         !isolate->debug()->PerformSideEffectCheckAtBytecode(interpreted_frame);
74   }
75 
76   // Make sure to only access these objects after the side effect check, as the
77   // check can allocate on failure.
78   SharedFunctionInfo shared = interpreted_frame->function().shared();
79   BytecodeArray bytecode_array = shared.GetBytecodeArray(isolate);
80   int bytecode_offset = interpreted_frame->GetBytecodeOffset();
81   Bytecode bytecode = Bytecodes::FromByte(bytecode_array.get(bytecode_offset));
82 
83   if (Bytecodes::Returns(bytecode)) {
84     // If we are returning (or suspending), reset the bytecode array on the
85     // interpreted stack frame to the non-debug variant so that the interpreter
86     // entry trampoline sees the return/suspend bytecode rather than the
87     // DebugBreak.
88     interpreted_frame->PatchBytecodeArray(bytecode_array);
89   }
90 
91   // We do not have to deal with operand scale here. If the bytecode at the
92   // break is prefixed by operand scaling, we would have patched over the
93   // scaling prefix. We now simply dispatch to the handler for the prefix.
94   // We need to deserialize now to ensure we don't hit the debug break again
95   // after deserializing.
96   OperandScale operand_scale = OperandScale::kSingle;
97   isolate->interpreter()->GetBytecodeHandler(bytecode, operand_scale);
98 
99   if (side_effect_check_failed) {
100     return MakePair(ReadOnlyRoots(isolate).exception(),
101                     Smi::FromInt(static_cast<uint8_t>(bytecode)));
102   }
103   Object interrupt_object = isolate->stack_guard()->HandleInterrupts();
104   if (interrupt_object.IsException(isolate)) {
105     return MakePair(interrupt_object,
106                     Smi::FromInt(static_cast<uint8_t>(bytecode)));
107   }
108   return MakePair(isolate->debug()->return_value(),
109                   Smi::FromInt(static_cast<uint8_t>(bytecode)));
110 }
111 
RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry)112 RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) {
113   HandleScope scope(isolate);
114   DCHECK_EQ(1, args.length());
115   Handle<JSFunction> function = args.at<JSFunction>(0);
116   USE(function);
117 
118   DCHECK(function->shared().HasDebugInfo());
119   DCHECK(function->shared().GetDebugInfo().BreakAtEntry());
120 
121   // Get the top-most JavaScript frame. This is the debug target function.
122   JavaScriptFrameIterator it(isolate);
123   DCHECK_EQ(*function, it.frame()->function());
124   // Check whether the next JS frame is closer than the last API entry.
125   // if yes, then the call to the debug target came from JavaScript. Otherwise,
126   // the call to the debug target came from API. Do not break for the latter.
127   it.Advance();
128   if (!it.done() &&
129       it.frame()->fp() < isolate->thread_local_top()->last_api_entry_) {
130     isolate->debug()->Break(it.frame(), function);
131   }
132 
133   return ReadOnlyRoots(isolate).undefined_value();
134 }
135 
RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement)136 RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
137   SealHandleScope shs(isolate);
138   DCHECK_EQ(0, args.length());
139   if (isolate->debug()->break_points_active()) {
140     isolate->debug()->HandleDebugBreak(
141         kIgnoreIfTopFrameBlackboxed,
142         v8::debug::BreakReasons({v8::debug::BreakReason::kDebuggerStatement}));
143   }
144   return isolate->stack_guard()->HandleInterrupts();
145 }
146 
RUNTIME_FUNCTION(Runtime_ScheduleBreak)147 RUNTIME_FUNCTION(Runtime_ScheduleBreak) {
148   SealHandleScope shs(isolate);
149   DCHECK_EQ(0, args.length());
150   isolate->RequestInterrupt(
151       [](v8::Isolate* isolate, void*) {
152         v8::debug::BreakRightNow(
153             isolate,
154             v8::debug::BreakReasons({v8::debug::BreakReason::kScheduled}));
155       },
156       nullptr);
157   return ReadOnlyRoots(isolate).undefined_value();
158 }
159 
160 namespace {
161 
162 template <class IteratorType>
AddIteratorInternalProperties( Isolate* isolate, Handle<ArrayList> result, Handle<IteratorType> iterator)163 static Handle<ArrayList> AddIteratorInternalProperties(
164     Isolate* isolate, Handle<ArrayList> result, Handle<IteratorType> iterator) {
165   const char* kind = nullptr;
166   switch (iterator->map().instance_type()) {
167     case JS_MAP_KEY_ITERATOR_TYPE:
168       kind = "keys";
169       break;
170     case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
171     case JS_SET_KEY_VALUE_ITERATOR_TYPE:
172       kind = "entries";
173       break;
174     case JS_MAP_VALUE_ITERATOR_TYPE:
175     case JS_SET_VALUE_ITERATOR_TYPE:
176       kind = "values";
177       break;
178     default:
179       UNREACHABLE();
180   }
181 
182   result = ArrayList::Add(
183       isolate, result,
184       isolate->factory()->NewStringFromAsciiChecked("[[IteratorHasMore]]"),
185       isolate->factory()->ToBoolean(iterator->HasMore()));
186   result = ArrayList::Add(
187       isolate, result,
188       isolate->factory()->NewStringFromAsciiChecked("[[IteratorIndex]]"),
189       handle(iterator->index(), isolate));
190   result = ArrayList::Add(
191       isolate, result,
192       isolate->factory()->NewStringFromAsciiChecked("[[IteratorKind]]"),
193       isolate->factory()->NewStringFromAsciiChecked(kind));
194   return result;
195 }
196 
197 }  // namespace
198 
GetInternalProperties(Isolate* isolate, Handle<Object> object)199 MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
200                                                     Handle<Object> object) {
201   auto result = ArrayList::New(isolate, 8 * 2);
202   if (object->IsJSObject()) {
203     PrototypeIterator iter(isolate, Handle<JSObject>::cast(object),
204                            kStartAtReceiver);
205     if (iter.HasAccess()) {
206       iter.Advance();
207       Handle<Object> prototype = PrototypeIterator::GetCurrent(iter);
208       if (!prototype->IsNull(isolate)) {
209         result = ArrayList::Add(
210             isolate, result,
211             isolate->factory()->NewStringFromStaticChars("[[Prototype]]"),
212             prototype);
213       }
214     }
215   }
216   if (object->IsJSBoundFunction()) {
217     Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object);
218 
219     result = ArrayList::Add(
220         isolate, result,
221         isolate->factory()->NewStringFromAsciiChecked("[[TargetFunction]]"),
222         handle(function->bound_target_function(), isolate));
223     result = ArrayList::Add(
224         isolate, result,
225         isolate->factory()->NewStringFromAsciiChecked("[[BoundThis]]"),
226         handle(function->bound_this(), isolate));
227     result = ArrayList::Add(
228         isolate, result,
229         isolate->factory()->NewStringFromAsciiChecked("[[BoundArgs]]"),
230         isolate->factory()->NewJSArrayWithElements(
231             isolate->factory()->CopyFixedArray(
232                 handle(function->bound_arguments(), isolate))));
233   } else if (object->IsJSMapIterator()) {
234     Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object);
235     result = AddIteratorInternalProperties(isolate, result, iterator);
236   } else if (object->IsJSSetIterator()) {
237     Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object);
238     result = AddIteratorInternalProperties(isolate, result, iterator);
239   } else if (object->IsJSGeneratorObject()) {
240     Handle<JSGeneratorObject> generator =
241         Handle<JSGeneratorObject>::cast(object);
242 
243     const char* status = "suspended";
244     if (generator->is_closed()) {
245       status = "closed";
246     } else if (generator->is_executing()) {
247       status = "running";
248     } else {
249       DCHECK(generator->is_suspended());
250     }
251 
252     result = ArrayList::Add(
253         isolate, result,
254         isolate->factory()->NewStringFromAsciiChecked("[[GeneratorState]]"),
255         isolate->factory()->NewStringFromAsciiChecked(status));
256     result = ArrayList::Add(
257         isolate, result,
258         isolate->factory()->NewStringFromAsciiChecked("[[GeneratorFunction]]"),
259         handle(generator->function(), isolate));
260     result = ArrayList::Add(
261         isolate, result,
262         isolate->factory()->NewStringFromAsciiChecked("[[GeneratorReceiver]]"),
263         handle(generator->receiver(), isolate));
264   } else if (object->IsJSPromise()) {
265     Handle<JSPromise> promise = Handle<JSPromise>::cast(object);
266 
267     result = ArrayList::Add(
268         isolate, result,
269         isolate->factory()->NewStringFromAsciiChecked("[[PromiseState]]"),
270         isolate->factory()->NewStringFromAsciiChecked(
271             JSPromise::Status(promise->status())));
272     result = ArrayList::Add(
273         isolate, result,
274         isolate->factory()->NewStringFromAsciiChecked("[[PromiseResult]]"),
275         promise->status() == Promise::kPending
276             ? isolate->factory()->undefined_value()
277             : handle(promise->result(), isolate));
278   } else if (object->IsJSProxy()) {
279     Handle<JSProxy> js_proxy = Handle<JSProxy>::cast(object);
280 
281     result = ArrayList::Add(
282         isolate, result,
283         isolate->factory()->NewStringFromAsciiChecked("[[Handler]]"),
284         handle(js_proxy->handler(), isolate));
285     result = ArrayList::Add(
286         isolate, result,
287         isolate->factory()->NewStringFromAsciiChecked("[[Target]]"),
288         handle(js_proxy->target(), isolate));
289     result = ArrayList::Add(
290         isolate, result,
291         isolate->factory()->NewStringFromAsciiChecked("[[IsRevoked]]"),
292         isolate->factory()->ToBoolean(js_proxy->IsRevoked()));
293   } else if (object->IsJSPrimitiveWrapper()) {
294     Handle<JSPrimitiveWrapper> js_value =
295         Handle<JSPrimitiveWrapper>::cast(object);
296 
297     result = ArrayList::Add(
298         isolate, result,
299         isolate->factory()->NewStringFromAsciiChecked("[[PrimitiveValue]]"),
300         handle(js_value->value(), isolate));
301   } else if (object->IsJSArrayBuffer()) {
302     Handle<JSArrayBuffer> js_array_buffer = Handle<JSArrayBuffer>::cast(object);
303     if (js_array_buffer->was_detached()) {
304       // Mark a detached JSArrayBuffer and such and don't even try to
305       // create views for it, since the TypedArray constructors will
306       // throw a TypeError when the underlying buffer is detached.
307       result = ArrayList::Add(
308           isolate, result,
309           isolate->factory()->NewStringFromAsciiChecked("[[IsDetached]]"),
310           isolate->factory()->true_value());
311     } else {
312       const size_t byte_length = js_array_buffer->byte_length();
313       static const ExternalArrayType kTypes[] = {
314           kExternalInt8Array,
315           kExternalUint8Array,
316           kExternalInt16Array,
317           kExternalInt32Array,
318       };
319       for (auto type : kTypes) {
320         switch (type) {
321 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                           \
322   case kExternal##Type##Array: {                                            \
323     if ((byte_length % sizeof(ctype)) != 0) continue;                       \
324     result = ArrayList::Add(                                                \
325         isolate, result,                                                    \
326         isolate->factory()->NewStringFromStaticChars("[[" #Type "Array]]"), \
327         isolate->factory()->NewJSTypedArray(kExternal##Type##Array,         \
328                                             js_array_buffer, 0,             \
329                                             byte_length / sizeof(ctype)));  \
330     break;                                                                  \
331   }
332           TYPED_ARRAYS(TYPED_ARRAY_CASE)
333 #undef TYPED_ARRAY_CASE
334         default:
335           UNREACHABLE();
336         }
337       }
338       result =
339           ArrayList::Add(isolate, result,
340                          isolate->factory()->NewStringFromAsciiChecked(
341                              "[[ArrayBufferByteLength]]"),
342                          isolate->factory()->NewNumberFromSize(byte_length));
343 
344       auto backing_store = js_array_buffer->GetBackingStore();
345       Handle<Object> array_buffer_data =
346           backing_store
347               ? isolate->factory()->NewNumberFromUint(backing_store->id())
348               : isolate->factory()->null_value();
349       result = ArrayList::Add(
350           isolate, result,
351           isolate->factory()->NewStringFromAsciiChecked("[[ArrayBufferData]]"),
352           array_buffer_data);
353 
354       Handle<Symbol> memory_symbol =
355           isolate->factory()->array_buffer_wasm_memory_symbol();
356       Handle<Object> memory_object =
357           JSObject::GetDataProperty(isolate, js_array_buffer, memory_symbol);
358       if (!memory_object->IsUndefined(isolate)) {
359         result = ArrayList::Add(isolate, result,
360                                 isolate->factory()->NewStringFromAsciiChecked(
361                                     "[[WebAssemblyMemory]]"),
362                                 memory_object);
363       }
364     }
365 #if V8_ENABLE_WEBASSEMBLY
366   } else if (object->IsWasmInstanceObject()) {
367     result = AddWasmInstanceObjectInternalProperties(
368         isolate, result, Handle<WasmInstanceObject>::cast(object));
369   } else if (object->IsWasmModuleObject()) {
370     result = AddWasmModuleObjectInternalProperties(
371         isolate, result, Handle<WasmModuleObject>::cast(object));
372   } else if (object->IsWasmTableObject()) {
373     result = AddWasmTableObjectInternalProperties(
374         isolate, result, Handle<WasmTableObject>::cast(object));
375 #endif  // V8_ENABLE_WEBASSEMBLY
376   }
377   return isolate->factory()->NewJSArrayWithElements(
378       ArrayList::Elements(isolate, result), PACKED_ELEMENTS);
379 }
380 
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount)381 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) {
382   HandleScope scope(isolate);
383   DCHECK_EQ(1, args.length());
384 
385   if (!args[0].IsJSGeneratorObject()) return Smi::zero();
386 
387   // Check arguments.
388   Handle<JSGeneratorObject> gen = args.at<JSGeneratorObject>(0);
389 
390   // Only inspect suspended generator scopes.
391   if (!gen->is_suspended()) {
392     return Smi::zero();
393   }
394 
395   // Count the visible scopes.
396   int n = 0;
397   for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) {
398     n++;
399   }
400 
401   return Smi::FromInt(n);
402 }
403 
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails)404 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) {
405   HandleScope scope(isolate);
406   DCHECK_EQ(2, args.length());
407 
408   if (!args[0].IsJSGeneratorObject()) {
409     return ReadOnlyRoots(isolate).undefined_value();
410   }
411 
412   // Check arguments.
413   Handle<JSGeneratorObject> gen = args.at<JSGeneratorObject>(0);
414   int index = NumberToInt32(args[1]);
415 
416   // Only inspect suspended generator scopes.
417   if (!gen->is_suspended()) {
418     return ReadOnlyRoots(isolate).undefined_value();
419   }
420 
421   // Find the requested scope.
422   int n = 0;
423   ScopeIterator it(isolate, gen);
424   for (; !it.Done() && n < index; it.Next()) {
425     n++;
426   }
427   if (it.Done()) {
428     return ReadOnlyRoots(isolate).undefined_value();
429   }
430 
431   return *it.MaterializeScopeDetails();
432 }
433 
SetScopeVariableValue(ScopeIterator* it, int index, Handle<String> variable_name, Handle<Object> new_value)434 static bool SetScopeVariableValue(ScopeIterator* it, int index,
435                                   Handle<String> variable_name,
436                                   Handle<Object> new_value) {
437   for (int n = 0; !it->Done() && n < index; it->Next()) {
438     n++;
439   }
440   if (it->Done()) {
441     return false;
442   }
443   return it->SetVariableValue(variable_name, new_value);
444 }
445 
446 // Change variable value in closure or local scope
447 // args[0]: number or JsFunction: break id or function
448 // args[1]: number: scope index
449 // args[2]: string: variable name
450 // args[3]: object: new value
451 //
452 // Return true if success and false otherwise
RUNTIME_FUNCTION(Runtime_SetGeneratorScopeVariableValue)453 RUNTIME_FUNCTION(Runtime_SetGeneratorScopeVariableValue) {
454   HandleScope scope(isolate);
455   DCHECK_EQ(4, args.length());
456   Handle<JSGeneratorObject> gen = args.at<JSGeneratorObject>(0);
457   int index = NumberToInt32(args[1]);
458   Handle<String> variable_name = args.at<String>(2);
459   Handle<Object> new_value = args.at(3);
460   ScopeIterator it(isolate, gen);
461   bool res = SetScopeVariableValue(&it, index, variable_name, new_value);
462   return isolate->heap()->ToBoolean(res);
463 }
464 
465 
RUNTIME_FUNCTION(Runtime_GetBreakLocations)466 RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
467   HandleScope scope(isolate);
468   DCHECK_EQ(1, args.length());
469   CHECK(isolate->debug()->is_active());
470   Handle<JSFunction> fun = args.at<JSFunction>(0);
471 
472   Handle<SharedFunctionInfo> shared(fun->shared(), isolate);
473   // Find the number of break points
474   Handle<Object> break_locations =
475       Debug::GetSourceBreakLocations(isolate, shared);
476   if (break_locations->IsUndefined(isolate)) {
477     return ReadOnlyRoots(isolate).undefined_value();
478   }
479   // Return array as JS array
480   return *isolate->factory()->NewJSArrayWithElements(
481       Handle<FixedArray>::cast(break_locations));
482 }
483 
484 
485 // Returns the state of break on exceptions
486 // args[0]: boolean indicating uncaught exceptions
RUNTIME_FUNCTION(Runtime_IsBreakOnException)487 RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
488   HandleScope scope(isolate);
489   DCHECK_EQ(1, args.length());
490   uint32_t type_arg = NumberToUint32(args[0]);
491 
492   ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
493   bool result = isolate->debug()->IsBreakOnException(type);
494   return Smi::FromInt(result);
495 }
496 
497 // Clear all stepping set by PrepareStep.
RUNTIME_FUNCTION(Runtime_ClearStepping)498 RUNTIME_FUNCTION(Runtime_ClearStepping) {
499   HandleScope scope(isolate);
500   DCHECK_EQ(0, args.length());
501   CHECK(isolate->debug()->is_active());
502   isolate->debug()->ClearStepping();
503   return ReadOnlyRoots(isolate).undefined_value();
504 }
505 
RUNTIME_FUNCTION(Runtime_DebugGetLoadedScriptIds)506 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScriptIds) {
507   HandleScope scope(isolate);
508   DCHECK_EQ(0, args.length());
509 
510   Handle<FixedArray> instances;
511   {
512     DebugScope debug_scope(isolate->debug());
513     // Fill the script objects.
514     instances = isolate->debug()->GetLoadedScripts();
515   }
516 
517   // Convert the script objects to proper JS objects.
518   for (int i = 0; i < instances->length(); i++) {
519     Handle<Script> script(Script::cast(instances->get(i)), isolate);
520     instances->set(i, Smi::FromInt(script->id()));
521   }
522 
523   // Return result as a JS array.
524   return *isolate->factory()->NewJSArrayWithElements(instances);
525 }
526 
527 
RUNTIME_FUNCTION(Runtime_FunctionGetInferredName)528 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
529   SealHandleScope shs(isolate);
530   DCHECK_EQ(1, args.length());
531 
532   Object f = args[0];
533   if (f.IsJSFunction()) {
534     return JSFunction::cast(f).shared().inferred_name();
535   }
536   return ReadOnlyRoots(isolate).empty_string();
537 }
538 
539 
540 // Performs a GC.
541 // Presently, it only does a full GC.
RUNTIME_FUNCTION(Runtime_CollectGarbage)542 RUNTIME_FUNCTION(Runtime_CollectGarbage) {
543   SealHandleScope shs(isolate);
544   DCHECK_EQ(1, args.length());
545   isolate->heap()->PreciseCollectAllGarbage(Heap::kNoGCFlags,
546                                             GarbageCollectionReason::kRuntime);
547   return ReadOnlyRoots(isolate).undefined_value();
548 }
549 
550 namespace {
551 
ScriptLinePosition(Handle<Script> script, int line)552 int ScriptLinePosition(Handle<Script> script, int line) {
553   if (line < 0) return -1;
554 
555 #if V8_ENABLE_WEBASSEMBLY
556   if (script->type() == Script::TYPE_WASM) {
557     // Wasm positions are relative to the start of the module.
558     return 0;
559   }
560 #endif  // V8_ENABLE_WEBASSEMBLY
561 
562   Script::InitLineEnds(script->GetIsolate(), script);
563 
564   FixedArray line_ends_array = FixedArray::cast(script->line_ends());
565   const int line_count = line_ends_array.length();
566   DCHECK_LT(0, line_count);
567 
568   if (line == 0) return 0;
569   // If line == line_count, we return the first position beyond the last line.
570   if (line > line_count) return -1;
571   return Smi::ToInt(line_ends_array.get(line - 1)) + 1;
572 }
573 
ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset)574 int ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset) {
575   if (line < 0 || offset < 0) return -1;
576 
577   if (line == 0 || offset == 0)
578     return ScriptLinePosition(script, line) + offset;
579 
580   Script::PositionInfo info;
581   if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET)) {
582     return -1;
583   }
584 
585   const int total_line = info.line + line;
586   return ScriptLinePosition(script, total_line);
587 }
588 
GetJSPositionInfo(Handle<Script> script, int position, Script::OffsetFlag offset_flag, Isolate* isolate)589 Handle<Object> GetJSPositionInfo(Handle<Script> script, int position,
590                                  Script::OffsetFlag offset_flag,
591                                  Isolate* isolate) {
592   Script::PositionInfo info;
593   if (!Script::GetPositionInfo(script, position, &info, offset_flag)) {
594     return isolate->factory()->null_value();
595   }
596 
597 #if V8_ENABLE_WEBASSEMBLY
598   const bool is_wasm_script = script->type() == Script::TYPE_WASM;
599 #else
600   const bool is_wasm_script = false;
601 #endif  // V8_ENABLE_WEBASSEMBLY
602   Handle<String> sourceText =
603       is_wasm_script ? isolate->factory()->empty_string()
604                      : isolate->factory()->NewSubString(
605                            handle(String::cast(script->source()), isolate),
606                            info.line_start, info.line_end);
607 
608   Handle<JSObject> jsinfo =
609       isolate->factory()->NewJSObject(isolate->object_function());
610 
611   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->script_string(),
612                         script, NONE);
613   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->position_string(),
614                         handle(Smi::FromInt(position), isolate), NONE);
615   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->line_string(),
616                         handle(Smi::FromInt(info.line), isolate), NONE);
617   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->column_string(),
618                         handle(Smi::FromInt(info.column), isolate), NONE);
619   JSObject::AddProperty(isolate, jsinfo,
620                         isolate->factory()->sourceText_string(), sourceText,
621                         NONE);
622 
623   return jsinfo;
624 }
625 
ScriptLocationFromLine(Isolate* isolate, Handle<Script> script, Handle<Object> opt_line, Handle<Object> opt_column, int32_t offset)626 Handle<Object> ScriptLocationFromLine(Isolate* isolate, Handle<Script> script,
627                                       Handle<Object> opt_line,
628                                       Handle<Object> opt_column,
629                                       int32_t offset) {
630   // Line and column are possibly undefined and we need to handle these cases,
631   // additionally subtracting corresponding offsets.
632 
633   int32_t line = 0;
634   if (!opt_line->IsNullOrUndefined(isolate)) {
635     CHECK(opt_line->IsNumber());
636     line = NumberToInt32(*opt_line) - script->line_offset();
637   }
638 
639   int32_t column = 0;
640   if (!opt_column->IsNullOrUndefined(isolate)) {
641     CHECK(opt_column->IsNumber());
642     column = NumberToInt32(*opt_column);
643     if (line == 0) column -= script->column_offset();
644   }
645 
646   int line_position = ScriptLinePositionWithOffset(script, line, offset);
647   if (line_position < 0 || column < 0) return isolate->factory()->null_value();
648 
649   return GetJSPositionInfo(script, line_position + column, Script::NO_OFFSET,
650                            isolate);
651 }
652 
653 // Slow traversal over all scripts on the heap.
GetScriptById(Isolate* isolate, int needle, Handle<Script>* result)654 bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) {
655   Script::Iterator iterator(isolate);
656   for (Script script = iterator.Next(); !script.is_null();
657        script = iterator.Next()) {
658     if (script.id() == needle) {
659       *result = handle(script, isolate);
660       return true;
661     }
662   }
663 
664   return false;
665 }
666 
667 }  // namespace
668 
669 // TODO(5530): Rename once conflicting function has been deleted.
RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2)670 RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) {
671   HandleScope scope(isolate);
672   DCHECK_EQ(4, args.length());
673   int32_t scriptid = NumberToInt32(args[0]);
674   Handle<Object> opt_line = args.at(1);
675   Handle<Object> opt_column = args.at(2);
676   int32_t offset = NumberToInt32(args[3]);
677 
678   Handle<Script> script;
679   CHECK(GetScriptById(isolate, scriptid, &script));
680 
681   return *ScriptLocationFromLine(isolate, script, opt_line, opt_column, offset);
682 }
683 
684 // On function call, depending on circumstances, prepare for stepping in,
685 // or perform a side effect check.
RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall)686 RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) {
687   HandleScope scope(isolate);
688   DCHECK_EQ(2, args.length());
689   Handle<JSFunction> fun = args.at<JSFunction>(0);
690   Handle<Object> receiver = args.at(1);
691   if (isolate->debug()->needs_check_on_function_call()) {
692     // Ensure that the callee will perform debug check on function call too.
693     Handle<SharedFunctionInfo> shared(fun->shared(), isolate);
694     isolate->debug()->DeoptimizeFunction(shared);
695     if (isolate->debug()->last_step_action() >= StepInto ||
696         isolate->debug()->break_on_next_function_call()) {
697       DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kBreakpoints);
698       isolate->debug()->PrepareStepIn(fun);
699     }
700     if (isolate->debug_execution_mode() == DebugInfo::kSideEffects &&
701         !isolate->debug()->PerformSideEffectCheck(fun, receiver)) {
702       return ReadOnlyRoots(isolate).exception();
703     }
704   }
705   return ReadOnlyRoots(isolate).undefined_value();
706 }
707 
708 // Set one shot breakpoints for the suspended generator object.
RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator)709 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator) {
710   HandleScope scope(isolate);
711   DCHECK_EQ(0, args.length());
712   isolate->debug()->PrepareStepInSuspendedGenerator();
713   return ReadOnlyRoots(isolate).undefined_value();
714 }
715 
RUNTIME_FUNCTION(Runtime_DebugPushPromise)716 RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
717   DCHECK_EQ(1, args.length());
718   HandleScope scope(isolate);
719   Handle<JSObject> promise = args.at<JSObject>(0);
720   isolate->PushPromise(promise);
721   return ReadOnlyRoots(isolate).undefined_value();
722 }
723 
724 
RUNTIME_FUNCTION(Runtime_DebugPopPromise)725 RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
726   DCHECK_EQ(0, args.length());
727   SealHandleScope shs(isolate);
728   isolate->PopPromise();
729   return ReadOnlyRoots(isolate).undefined_value();
730 }
731 
732 namespace {
MakeRangeObject(Isolate* isolate, const CoverageBlock& range)733 Handle<JSObject> MakeRangeObject(Isolate* isolate, const CoverageBlock& range) {
734   Factory* factory = isolate->factory();
735 
736   Handle<String> start_string = factory->InternalizeUtf8String("start");
737   Handle<String> end_string = factory->InternalizeUtf8String("end");
738   Handle<String> count_string = factory->InternalizeUtf8String("count");
739 
740   Handle<JSObject> range_obj = factory->NewJSObjectWithNullProto();
741   JSObject::AddProperty(isolate, range_obj, start_string,
742                         factory->NewNumberFromInt(range.start), NONE);
743   JSObject::AddProperty(isolate, range_obj, end_string,
744                         factory->NewNumberFromInt(range.end), NONE);
745   JSObject::AddProperty(isolate, range_obj, count_string,
746                         factory->NewNumberFromUint(range.count), NONE);
747 
748   return range_obj;
749 }
750 }  // namespace
751 
RUNTIME_FUNCTION(Runtime_DebugCollectCoverage)752 RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) {
753   HandleScope scope(isolate);
754   DCHECK_EQ(0, args.length());
755   // Collect coverage data.
756   std::unique_ptr<Coverage> coverage;
757   if (isolate->is_best_effort_code_coverage()) {
758     coverage = Coverage::CollectBestEffort(isolate);
759   } else {
760     coverage = Coverage::CollectPrecise(isolate);
761   }
762   Factory* factory = isolate->factory();
763   // Turn the returned data structure into JavaScript.
764   // Create an array of scripts.
765   int num_scripts = static_cast<int>(coverage->size());
766   // Prepare property keys.
767   Handle<FixedArray> scripts_array = factory->NewFixedArray(num_scripts);
768   Handle<String> script_string = factory->script_string();
769   for (int i = 0; i < num_scripts; i++) {
770     const auto& script_data = coverage->at(i);
771     HandleScope inner_scope(isolate);
772 
773     std::vector<CoverageBlock> ranges;
774     int num_functions = static_cast<int>(script_data.functions.size());
775     for (int j = 0; j < num_functions; j++) {
776       const auto& function_data = script_data.functions[j];
777       ranges.emplace_back(function_data.start, function_data.end,
778                           function_data.count);
779       for (size_t k = 0; k < function_data.blocks.size(); k++) {
780         const auto& block_data = function_data.blocks[k];
781         ranges.emplace_back(block_data.start, block_data.end, block_data.count);
782       }
783     }
784 
785     int num_ranges = static_cast<int>(ranges.size());
786     Handle<FixedArray> ranges_array = factory->NewFixedArray(num_ranges);
787     for (int j = 0; j < num_ranges; j++) {
788       Handle<JSObject> range_object = MakeRangeObject(isolate, ranges[j]);
789       ranges_array->set(j, *range_object);
790     }
791 
792     Handle<JSArray> script_obj =
793         factory->NewJSArrayWithElements(ranges_array, PACKED_ELEMENTS);
794     JSObject::AddProperty(isolate, script_obj, script_string,
795                           handle(script_data.script->source(), isolate), NONE);
796     scripts_array->set(i, *script_obj);
797   }
798   return *factory->NewJSArrayWithElements(scripts_array, PACKED_ELEMENTS);
799 }
800 
RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage)801 RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage) {
802   SealHandleScope shs(isolate);
803   bool enable = Oddball::cast(args[0]).ToBool(isolate);
804   Coverage::SelectMode(isolate, enable ? debug::CoverageMode::kPreciseCount
805                                        : debug::CoverageMode::kBestEffort);
806   return ReadOnlyRoots(isolate).undefined_value();
807 }
808 
RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage)809 RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage) {
810   SealHandleScope shs(isolate);
811   bool enable = Oddball::cast(args[0]).ToBool(isolate);
812   Coverage::SelectMode(isolate, enable ? debug::CoverageMode::kBlockCount
813                                        : debug::CoverageMode::kBestEffort);
814   return ReadOnlyRoots(isolate).undefined_value();
815 }
816 
RUNTIME_FUNCTION(Runtime_IncBlockCounter)817 RUNTIME_FUNCTION(Runtime_IncBlockCounter) {
818   UNREACHABLE();  // Never called. See the IncBlockCounter builtin instead.
819 }
820 
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended)821 RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended) {
822   DCHECK_EQ(5, args.length());
823   HandleScope scope(isolate);
824   Handle<JSPromise> promise = args.at<JSPromise>(0);
825   Handle<JSPromise> outer_promise = args.at<JSPromise>(1);
826   Handle<JSFunction> reject_handler = args.at<JSFunction>(2);
827   Handle<JSGeneratorObject> generator = args.at<JSGeneratorObject>(3);
828   bool is_predicted_as_caught = Oddball::cast(args[4]).ToBool(isolate);
829 
830   // Allocate the throwaway promise and fire the appropriate init
831   // hook for the throwaway promise (passing the {promise} as its
832   // parent).
833   Handle<JSPromise> throwaway = isolate->factory()->NewJSPromiseWithoutHook();
834   isolate->OnAsyncFunctionSuspended(throwaway, promise);
835 
836   // The Promise will be thrown away and not handled, but it
837   // shouldn't trigger unhandled reject events as its work is done
838   throwaway->set_has_handler(true);
839 
840   // Enable proper debug support for promises.
841   if (isolate->debug()->is_active()) {
842     Object::SetProperty(isolate, reject_handler,
843                         isolate->factory()->promise_forwarding_handler_symbol(),
844                         isolate->factory()->true_value(),
845                         StoreOrigin::kMaybeKeyed,
846                         Just(ShouldThrow::kThrowOnError))
847         .Check();
848     promise->set_handled_hint(is_predicted_as_caught);
849 
850     // Mark the dependency to {outer_promise} in case the {throwaway}
851     // Promise is found on the Promise stack
852     Object::SetProperty(isolate, throwaway,
853                         isolate->factory()->promise_handled_by_symbol(),
854                         outer_promise, StoreOrigin::kMaybeKeyed,
855                         Just(ShouldThrow::kThrowOnError))
856         .Check();
857 
858     Object::SetProperty(
859         isolate, promise, isolate->factory()->promise_awaited_by_symbol(),
860         generator, StoreOrigin::kMaybeKeyed, Just(ShouldThrow::kThrowOnError))
861         .Check();
862   }
863 
864   return *throwaway;
865 }
866 
RUNTIME_FUNCTION(Runtime_DebugPromiseThen)867 RUNTIME_FUNCTION(Runtime_DebugPromiseThen) {
868   DCHECK_EQ(1, args.length());
869   HandleScope scope(isolate);
870   Handle<JSReceiver> promise = args.at<JSReceiver>(0);
871   if (promise->IsJSPromise()) {
872     isolate->OnPromiseThen(Handle<JSPromise>::cast(promise));
873   }
874   return *promise;
875 }
876 
RUNTIME_FUNCTION(Runtime_LiveEditPatchScript)877 RUNTIME_FUNCTION(Runtime_LiveEditPatchScript) {
878   HandleScope scope(isolate);
879   DCHECK_EQ(2, args.length());
880   Handle<JSFunction> script_function = args.at<JSFunction>(0);
881   Handle<String> new_source = args.at<String>(1);
882 
883   Handle<Script> script(Script::cast(script_function->shared().script()),
884                         isolate);
885   v8::debug::LiveEditResult result;
886   LiveEdit::PatchScript(isolate, script, new_source, false, &result);
887   switch (result.status) {
888     case v8::debug::LiveEditResult::COMPILE_ERROR:
889       return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
890           "LiveEdit failed: COMPILE_ERROR"));
891     case v8::debug::LiveEditResult::BLOCKED_BY_RUNNING_GENERATOR:
892       return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
893           "LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR"));
894     case v8::debug::LiveEditResult::BLOCKED_BY_ACTIVE_FUNCTION:
895       return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
896           "LiveEdit failed: BLOCKED_BY_ACTIVE_FUNCTION"));
897     case v8::debug::LiveEditResult::OK:
898       return ReadOnlyRoots(isolate).undefined_value();
899   }
900   return ReadOnlyRoots(isolate).undefined_value();
901 }
902 
RUNTIME_FUNCTION(Runtime_ProfileCreateSnapshotDataBlob)903 RUNTIME_FUNCTION(Runtime_ProfileCreateSnapshotDataBlob) {
904   HandleScope scope(isolate);
905   DCHECK_EQ(0, args.length());
906 
907   // Used only by the test/memory/Memory.json benchmark. This creates a snapshot
908   // blob and outputs various statistics around it.
909 
910   DCHECK(FLAG_profile_deserialization && FLAG_serialization_statistics);
911 
912   DisableEmbeddedBlobRefcounting();
913 
914   v8::StartupData blob = CreateSnapshotDataBlobInternal(
915       v8::SnapshotCreator::FunctionCodeHandling::kClear, nullptr);
916   delete[] blob.data;
917 
918   // Track the embedded blob size as well.
919   {
920     i::EmbeddedData d = i::EmbeddedData::FromBlob(isolate);
921     PrintF("Embedded blob is %d bytes\n",
922            static_cast<int>(d.code_size() + d.data_size()));
923   }
924 
925   FreeCurrentEmbeddedBlob();
926 
927   return ReadOnlyRoots(isolate).undefined_value();
928 }
929 
930 }  // namespace internal
931 }  // namespace v8
932