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   CONVERT_ARG_HANDLE_CHECKED(Object, value, 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   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 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(kIgnoreIfTopFrameBlackboxed);
141   }
142   return isolate->stack_guard()->HandleInterrupts();
143 }
144 
RUNTIME_FUNCTION(Runtime_ScheduleBreak)145 RUNTIME_FUNCTION(Runtime_ScheduleBreak) {
146   SealHandleScope shs(isolate);
147   DCHECK_EQ(0, args.length());
148   isolate->RequestInterrupt(
149       [](v8::Isolate* isolate, void*) { v8::debug::BreakRightNow(isolate); },
150       nullptr);
151   return ReadOnlyRoots(isolate).undefined_value();
152 }
153 
154 namespace {
155 
156 template <class IteratorType>
AddIteratorInternalProperties(Isolate * isolate,Handle<ArrayList> result,Handle<IteratorType> iterator)157 static Handle<ArrayList> AddIteratorInternalProperties(
158     Isolate* isolate, Handle<ArrayList> result, Handle<IteratorType> iterator) {
159   const char* kind = nullptr;
160   switch (iterator->map().instance_type()) {
161     case JS_MAP_KEY_ITERATOR_TYPE:
162       kind = "keys";
163       break;
164     case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
165     case JS_SET_KEY_VALUE_ITERATOR_TYPE:
166       kind = "entries";
167       break;
168     case JS_MAP_VALUE_ITERATOR_TYPE:
169     case JS_SET_VALUE_ITERATOR_TYPE:
170       kind = "values";
171       break;
172     default:
173       UNREACHABLE();
174   }
175 
176   result = ArrayList::Add(
177       isolate, result,
178       isolate->factory()->NewStringFromAsciiChecked("[[IteratorHasMore]]"),
179       isolate->factory()->ToBoolean(iterator->HasMore()));
180   result = ArrayList::Add(
181       isolate, result,
182       isolate->factory()->NewStringFromAsciiChecked("[[IteratorIndex]]"),
183       handle(iterator->index(), isolate));
184   result = ArrayList::Add(
185       isolate, result,
186       isolate->factory()->NewStringFromAsciiChecked("[[IteratorKind]]"),
187       isolate->factory()->NewStringFromAsciiChecked(kind));
188   return result;
189 }
190 
191 }  // namespace
192 
GetInternalProperties(Isolate * isolate,Handle<Object> object)193 MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
194                                                     Handle<Object> object) {
195   auto result = ArrayList::New(isolate, 8 * 2);
196   if (object->IsJSObject()) {
197     PrototypeIterator iter(isolate, Handle<JSObject>::cast(object),
198                            kStartAtReceiver);
199     if (iter.HasAccess()) {
200       iter.Advance();
201       Handle<Object> prototype = PrototypeIterator::GetCurrent(iter);
202       if (!prototype->IsNull(isolate)) {
203         result = ArrayList::Add(
204             isolate, result,
205             isolate->factory()->NewStringFromStaticChars("[[Prototype]]"),
206             prototype);
207       }
208     }
209   }
210   if (object->IsJSBoundFunction()) {
211     Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object);
212 
213     result = ArrayList::Add(
214         isolate, result,
215         isolate->factory()->NewStringFromAsciiChecked("[[TargetFunction]]"),
216         handle(function->bound_target_function(), isolate));
217     result = ArrayList::Add(
218         isolate, result,
219         isolate->factory()->NewStringFromAsciiChecked("[[BoundThis]]"),
220         handle(function->bound_this(), isolate));
221     result = ArrayList::Add(
222         isolate, result,
223         isolate->factory()->NewStringFromAsciiChecked("[[BoundArgs]]"),
224         isolate->factory()->NewJSArrayWithElements(
225             isolate->factory()->CopyFixedArray(
226                 handle(function->bound_arguments(), isolate))));
227   } else if (object->IsJSMapIterator()) {
228     Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object);
229     result = AddIteratorInternalProperties(isolate, result, iterator);
230   } else if (object->IsJSSetIterator()) {
231     Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object);
232     result = AddIteratorInternalProperties(isolate, result, iterator);
233   } else if (object->IsJSGeneratorObject()) {
234     Handle<JSGeneratorObject> generator =
235         Handle<JSGeneratorObject>::cast(object);
236 
237     const char* status = "suspended";
238     if (generator->is_closed()) {
239       status = "closed";
240     } else if (generator->is_executing()) {
241       status = "running";
242     } else {
243       DCHECK(generator->is_suspended());
244     }
245 
246     result = ArrayList::Add(
247         isolate, result,
248         isolate->factory()->NewStringFromAsciiChecked("[[GeneratorState]]"),
249         isolate->factory()->NewStringFromAsciiChecked(status));
250     result = ArrayList::Add(
251         isolate, result,
252         isolate->factory()->NewStringFromAsciiChecked("[[GeneratorFunction]]"),
253         handle(generator->function(), isolate));
254     result = ArrayList::Add(
255         isolate, result,
256         isolate->factory()->NewStringFromAsciiChecked("[[GeneratorReceiver]]"),
257         handle(generator->receiver(), isolate));
258   } else if (object->IsJSPromise()) {
259     Handle<JSPromise> promise = Handle<JSPromise>::cast(object);
260 
261     result = ArrayList::Add(
262         isolate, result,
263         isolate->factory()->NewStringFromAsciiChecked("[[PromiseState]]"),
264         isolate->factory()->NewStringFromAsciiChecked(
265             JSPromise::Status(promise->status())));
266     result = ArrayList::Add(
267         isolate, result,
268         isolate->factory()->NewStringFromAsciiChecked("[[PromiseResult]]"),
269         promise->status() == Promise::kPending
270             ? isolate->factory()->undefined_value()
271             : handle(promise->result(), isolate));
272   } else if (object->IsJSProxy()) {
273     Handle<JSProxy> js_proxy = Handle<JSProxy>::cast(object);
274 
275     result = ArrayList::Add(
276         isolate, result,
277         isolate->factory()->NewStringFromAsciiChecked("[[Handler]]"),
278         handle(js_proxy->handler(), isolate));
279     result = ArrayList::Add(
280         isolate, result,
281         isolate->factory()->NewStringFromAsciiChecked("[[Target]]"),
282         handle(js_proxy->target(), isolate));
283     result = ArrayList::Add(
284         isolate, result,
285         isolate->factory()->NewStringFromAsciiChecked("[[IsRevoked]]"),
286         isolate->factory()->ToBoolean(js_proxy->IsRevoked()));
287   } else if (object->IsJSPrimitiveWrapper()) {
288     Handle<JSPrimitiveWrapper> js_value =
289         Handle<JSPrimitiveWrapper>::cast(object);
290 
291     result = ArrayList::Add(
292         isolate, result,
293         isolate->factory()->NewStringFromAsciiChecked("[[PrimitiveValue]]"),
294         handle(js_value->value(), isolate));
295   } else if (object->IsJSArrayBuffer()) {
296     Handle<JSArrayBuffer> js_array_buffer = Handle<JSArrayBuffer>::cast(object);
297     if (js_array_buffer->was_detached()) {
298       // Mark a detached JSArrayBuffer and such and don't even try to
299       // create views for it, since the TypedArray constructors will
300       // throw a TypeError when the underlying buffer is detached.
301       result = ArrayList::Add(
302           isolate, result,
303           isolate->factory()->NewStringFromAsciiChecked("[[IsDetached]]"),
304           isolate->factory()->true_value());
305     } else {
306       const size_t byte_length = js_array_buffer->byte_length();
307       static const ExternalArrayType kTypes[] = {
308           kExternalInt8Array,
309           kExternalUint8Array,
310           kExternalInt16Array,
311           kExternalInt32Array,
312       };
313       for (auto type : kTypes) {
314         switch (type) {
315 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                           \
316   case kExternal##Type##Array: {                                            \
317     if ((byte_length % sizeof(ctype)) != 0) continue;                       \
318     result = ArrayList::Add(                                                \
319         isolate, result,                                                    \
320         isolate->factory()->NewStringFromStaticChars("[[" #Type "Array]]"), \
321         isolate->factory()->NewJSTypedArray(kExternal##Type##Array,         \
322                                             js_array_buffer, 0,             \
323                                             byte_length / sizeof(ctype)));  \
324     break;                                                                  \
325   }
326           TYPED_ARRAYS(TYPED_ARRAY_CASE)
327 #undef TYPED_ARRAY_CASE
328         default:
329           UNREACHABLE();
330         }
331       }
332       result =
333           ArrayList::Add(isolate, result,
334                          isolate->factory()->NewStringFromAsciiChecked(
335                              "[[ArrayBufferByteLength]]"),
336                          isolate->factory()->NewNumberFromSize(byte_length));
337 
338       auto backing_store = js_array_buffer->GetBackingStore();
339       Handle<Object> array_buffer_data =
340           backing_store
341               ? isolate->factory()->NewNumberFromUint(backing_store->id())
342               : isolate->factory()->null_value();
343       result = ArrayList::Add(
344           isolate, result,
345           isolate->factory()->NewStringFromAsciiChecked("[[ArrayBufferData]]"),
346           array_buffer_data);
347 
348       Handle<Symbol> memory_symbol =
349           isolate->factory()->array_buffer_wasm_memory_symbol();
350       Handle<Object> memory_object =
351           JSObject::GetDataProperty(js_array_buffer, memory_symbol);
352       if (!memory_object->IsUndefined(isolate)) {
353         result = ArrayList::Add(isolate, result,
354                                 isolate->factory()->NewStringFromAsciiChecked(
355                                     "[[WebAssemblyMemory]]"),
356                                 memory_object);
357       }
358     }
359 #if V8_ENABLE_WEBASSEMBLY
360   } else if (object->IsWasmInstanceObject()) {
361     result = AddWasmInstanceObjectInternalProperties(
362         isolate, result, Handle<WasmInstanceObject>::cast(object));
363   } else if (object->IsWasmModuleObject()) {
364     result = AddWasmModuleObjectInternalProperties(
365         isolate, result, Handle<WasmModuleObject>::cast(object));
366   } else if (object->IsWasmTableObject()) {
367     result = AddWasmTableObjectInternalProperties(
368         isolate, result, Handle<WasmTableObject>::cast(object));
369 #endif  // V8_ENABLE_WEBASSEMBLY
370   }
371   return isolate->factory()->NewJSArrayWithElements(
372       ArrayList::Elements(isolate, result), PACKED_ELEMENTS);
373 }
374 
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount)375 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) {
376   HandleScope scope(isolate);
377   DCHECK_EQ(1, args.length());
378 
379   if (!args[0].IsJSGeneratorObject()) return Smi::zero();
380 
381   // Check arguments.
382   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
383 
384   // Only inspect suspended generator scopes.
385   if (!gen->is_suspended()) {
386     return Smi::zero();
387   }
388 
389   // Count the visible scopes.
390   int n = 0;
391   for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) {
392     n++;
393   }
394 
395   return Smi::FromInt(n);
396 }
397 
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails)398 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) {
399   HandleScope scope(isolate);
400   DCHECK_EQ(2, args.length());
401 
402   if (!args[0].IsJSGeneratorObject()) {
403     return ReadOnlyRoots(isolate).undefined_value();
404   }
405 
406   // Check arguments.
407   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
408   CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
409 
410   // Only inspect suspended generator scopes.
411   if (!gen->is_suspended()) {
412     return ReadOnlyRoots(isolate).undefined_value();
413   }
414 
415   // Find the requested scope.
416   int n = 0;
417   ScopeIterator it(isolate, gen);
418   for (; !it.Done() && n < index; it.Next()) {
419     n++;
420   }
421   if (it.Done()) {
422     return ReadOnlyRoots(isolate).undefined_value();
423   }
424 
425   return *it.MaterializeScopeDetails();
426 }
427 
SetScopeVariableValue(ScopeIterator * it,int index,Handle<String> variable_name,Handle<Object> new_value)428 static bool SetScopeVariableValue(ScopeIterator* it, int index,
429                                   Handle<String> variable_name,
430                                   Handle<Object> new_value) {
431   for (int n = 0; !it->Done() && n < index; it->Next()) {
432     n++;
433   }
434   if (it->Done()) {
435     return false;
436   }
437   return it->SetVariableValue(variable_name, new_value);
438 }
439 
440 // Change variable value in closure or local scope
441 // args[0]: number or JsFunction: break id or function
442 // args[1]: number: scope index
443 // args[2]: string: variable name
444 // args[3]: object: new value
445 //
446 // Return true if success and false otherwise
RUNTIME_FUNCTION(Runtime_SetGeneratorScopeVariableValue)447 RUNTIME_FUNCTION(Runtime_SetGeneratorScopeVariableValue) {
448   HandleScope scope(isolate);
449   DCHECK_EQ(4, args.length());
450   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
451   CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
452   CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 2);
453   CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 3);
454   ScopeIterator it(isolate, gen);
455   bool res = SetScopeVariableValue(&it, index, variable_name, new_value);
456   return isolate->heap()->ToBoolean(res);
457 }
458 
459 
RUNTIME_FUNCTION(Runtime_GetBreakLocations)460 RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
461   HandleScope scope(isolate);
462   DCHECK_EQ(1, args.length());
463   CHECK(isolate->debug()->is_active());
464   CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
465 
466   Handle<SharedFunctionInfo> shared(fun->shared(), isolate);
467   // Find the number of break points
468   Handle<Object> break_locations =
469       Debug::GetSourceBreakLocations(isolate, shared);
470   if (break_locations->IsUndefined(isolate)) {
471     return ReadOnlyRoots(isolate).undefined_value();
472   }
473   // Return array as JS array
474   return *isolate->factory()->NewJSArrayWithElements(
475       Handle<FixedArray>::cast(break_locations));
476 }
477 
478 
479 // Returns the state of break on exceptions
480 // args[0]: boolean indicating uncaught exceptions
RUNTIME_FUNCTION(Runtime_IsBreakOnException)481 RUNTIME_FUNCTION(Runtime_IsBreakOnException) {
482   HandleScope scope(isolate);
483   DCHECK_EQ(1, args.length());
484   CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
485 
486   ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
487   bool result = isolate->debug()->IsBreakOnException(type);
488   return Smi::FromInt(result);
489 }
490 
491 // Clear all stepping set by PrepareStep.
RUNTIME_FUNCTION(Runtime_ClearStepping)492 RUNTIME_FUNCTION(Runtime_ClearStepping) {
493   HandleScope scope(isolate);
494   DCHECK_EQ(0, args.length());
495   CHECK(isolate->debug()->is_active());
496   isolate->debug()->ClearStepping();
497   return ReadOnlyRoots(isolate).undefined_value();
498 }
499 
RUNTIME_FUNCTION(Runtime_DebugGetLoadedScriptIds)500 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScriptIds) {
501   HandleScope scope(isolate);
502   DCHECK_EQ(0, args.length());
503 
504   Handle<FixedArray> instances;
505   {
506     DebugScope debug_scope(isolate->debug());
507     // Fill the script objects.
508     instances = isolate->debug()->GetLoadedScripts();
509   }
510 
511   // Convert the script objects to proper JS objects.
512   for (int i = 0; i < instances->length(); i++) {
513     Handle<Script> script(Script::cast(instances->get(i)), isolate);
514     instances->set(i, Smi::FromInt(script->id()));
515   }
516 
517   // Return result as a JS array.
518   return *isolate->factory()->NewJSArrayWithElements(instances);
519 }
520 
521 
RUNTIME_FUNCTION(Runtime_FunctionGetInferredName)522 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
523   SealHandleScope shs(isolate);
524   DCHECK_EQ(1, args.length());
525 
526   CONVERT_ARG_CHECKED(Object, f, 0);
527   if (f.IsJSFunction()) {
528     return JSFunction::cast(f).shared().inferred_name();
529   }
530   return ReadOnlyRoots(isolate).empty_string();
531 }
532 
533 
534 // Performs a GC.
535 // Presently, it only does a full GC.
RUNTIME_FUNCTION(Runtime_CollectGarbage)536 RUNTIME_FUNCTION(Runtime_CollectGarbage) {
537   SealHandleScope shs(isolate);
538   DCHECK_EQ(1, args.length());
539   isolate->heap()->PreciseCollectAllGarbage(Heap::kNoGCFlags,
540                                             GarbageCollectionReason::kRuntime);
541   return ReadOnlyRoots(isolate).undefined_value();
542 }
543 
544 namespace {
545 
ScriptLinePosition(Handle<Script> script,int line)546 int ScriptLinePosition(Handle<Script> script, int line) {
547   if (line < 0) return -1;
548 
549 #if V8_ENABLE_WEBASSEMBLY
550   if (script->type() == Script::TYPE_WASM) {
551     // Wasm positions are relative to the start of the module.
552     return 0;
553   }
554 #endif  // V8_ENABLE_WEBASSEMBLY
555 
556   Script::InitLineEnds(script->GetIsolate(), script);
557 
558   FixedArray line_ends_array = FixedArray::cast(script->line_ends());
559   const int line_count = line_ends_array.length();
560   DCHECK_LT(0, line_count);
561 
562   if (line == 0) return 0;
563   // If line == line_count, we return the first position beyond the last line.
564   if (line > line_count) return -1;
565   return Smi::ToInt(line_ends_array.get(line - 1)) + 1;
566 }
567 
ScriptLinePositionWithOffset(Handle<Script> script,int line,int offset)568 int ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset) {
569   if (line < 0 || offset < 0) return -1;
570 
571   if (line == 0 || offset == 0)
572     return ScriptLinePosition(script, line) + offset;
573 
574   Script::PositionInfo info;
575   if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET)) {
576     return -1;
577   }
578 
579   const int total_line = info.line + line;
580   return ScriptLinePosition(script, total_line);
581 }
582 
GetJSPositionInfo(Handle<Script> script,int position,Script::OffsetFlag offset_flag,Isolate * isolate)583 Handle<Object> GetJSPositionInfo(Handle<Script> script, int position,
584                                  Script::OffsetFlag offset_flag,
585                                  Isolate* isolate) {
586   Script::PositionInfo info;
587   if (!Script::GetPositionInfo(script, position, &info, offset_flag)) {
588     return isolate->factory()->null_value();
589   }
590 
591 #if V8_ENABLE_WEBASSEMBLY
592   const bool is_wasm_script = script->type() == Script::TYPE_WASM;
593 #else
594   const bool is_wasm_script = false;
595 #endif  // V8_ENABLE_WEBASSEMBLY
596   Handle<String> sourceText =
597       is_wasm_script ? isolate->factory()->empty_string()
598                      : isolate->factory()->NewSubString(
599                            handle(String::cast(script->source()), isolate),
600                            info.line_start, info.line_end);
601 
602   Handle<JSObject> jsinfo =
603       isolate->factory()->NewJSObject(isolate->object_function());
604 
605   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->script_string(),
606                         script, NONE);
607   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->position_string(),
608                         handle(Smi::FromInt(position), isolate), NONE);
609   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->line_string(),
610                         handle(Smi::FromInt(info.line), isolate), NONE);
611   JSObject::AddProperty(isolate, jsinfo, isolate->factory()->column_string(),
612                         handle(Smi::FromInt(info.column), isolate), NONE);
613   JSObject::AddProperty(isolate, jsinfo,
614                         isolate->factory()->sourceText_string(), sourceText,
615                         NONE);
616 
617   return jsinfo;
618 }
619 
ScriptLocationFromLine(Isolate * isolate,Handle<Script> script,Handle<Object> opt_line,Handle<Object> opt_column,int32_t offset)620 Handle<Object> ScriptLocationFromLine(Isolate* isolate, Handle<Script> script,
621                                       Handle<Object> opt_line,
622                                       Handle<Object> opt_column,
623                                       int32_t offset) {
624   // Line and column are possibly undefined and we need to handle these cases,
625   // additionally subtracting corresponding offsets.
626 
627   int32_t line = 0;
628   if (!opt_line->IsNullOrUndefined(isolate)) {
629     CHECK(opt_line->IsNumber());
630     line = NumberToInt32(*opt_line) - script->line_offset();
631   }
632 
633   int32_t column = 0;
634   if (!opt_column->IsNullOrUndefined(isolate)) {
635     CHECK(opt_column->IsNumber());
636     column = NumberToInt32(*opt_column);
637     if (line == 0) column -= script->column_offset();
638   }
639 
640   int line_position = ScriptLinePositionWithOffset(script, line, offset);
641   if (line_position < 0 || column < 0) return isolate->factory()->null_value();
642 
643   return GetJSPositionInfo(script, line_position + column, Script::NO_OFFSET,
644                            isolate);
645 }
646 
647 // Slow traversal over all scripts on the heap.
GetScriptById(Isolate * isolate,int needle,Handle<Script> * result)648 bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) {
649   Script::Iterator iterator(isolate);
650   for (Script script = iterator.Next(); !script.is_null();
651        script = iterator.Next()) {
652     if (script.id() == needle) {
653       *result = handle(script, isolate);
654       return true;
655     }
656   }
657 
658   return false;
659 }
660 
661 }  // namespace
662 
663 // TODO(5530): Rename once conflicting function has been deleted.
RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2)664 RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) {
665   HandleScope scope(isolate);
666   DCHECK_EQ(4, args.length());
667   CONVERT_NUMBER_CHECKED(int32_t, scriptid, Int32, args[0]);
668   CONVERT_ARG_HANDLE_CHECKED(Object, opt_line, 1);
669   CONVERT_ARG_HANDLE_CHECKED(Object, opt_column, 2);
670   CONVERT_NUMBER_CHECKED(int32_t, offset, Int32, args[3]);
671 
672   Handle<Script> script;
673   CHECK(GetScriptById(isolate, scriptid, &script));
674 
675   return *ScriptLocationFromLine(isolate, script, opt_line, opt_column, offset);
676 }
677 
678 // On function call, depending on circumstances, prepare for stepping in,
679 // or perform a side effect check.
RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall)680 RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) {
681   HandleScope scope(isolate);
682   DCHECK_EQ(2, args.length());
683   CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
684   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
685   if (isolate->debug()->needs_check_on_function_call()) {
686     // Ensure that the callee will perform debug check on function call too.
687     Handle<SharedFunctionInfo> shared(fun->shared(), isolate);
688     isolate->debug()->DeoptimizeFunction(shared);
689     if (isolate->debug()->last_step_action() >= StepInto ||
690         isolate->debug()->break_on_next_function_call()) {
691       DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kBreakpoints);
692       isolate->debug()->PrepareStepIn(fun);
693     }
694     if (isolate->debug_execution_mode() == DebugInfo::kSideEffects &&
695         !isolate->debug()->PerformSideEffectCheck(fun, receiver)) {
696       return ReadOnlyRoots(isolate).exception();
697     }
698   }
699   return ReadOnlyRoots(isolate).undefined_value();
700 }
701 
702 // Set one shot breakpoints for the suspended generator object.
RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator)703 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator) {
704   HandleScope scope(isolate);
705   DCHECK_EQ(0, args.length());
706   isolate->debug()->PrepareStepInSuspendedGenerator();
707   return ReadOnlyRoots(isolate).undefined_value();
708 }
709 
RUNTIME_FUNCTION(Runtime_DebugPushPromise)710 RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
711   DCHECK_EQ(1, args.length());
712   HandleScope scope(isolate);
713   CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
714   isolate->PushPromise(promise);
715   return ReadOnlyRoots(isolate).undefined_value();
716 }
717 
718 
RUNTIME_FUNCTION(Runtime_DebugPopPromise)719 RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
720   DCHECK_EQ(0, args.length());
721   SealHandleScope shs(isolate);
722   isolate->PopPromise();
723   return ReadOnlyRoots(isolate).undefined_value();
724 }
725 
726 namespace {
MakeRangeObject(Isolate * isolate,const CoverageBlock & range)727 Handle<JSObject> MakeRangeObject(Isolate* isolate, const CoverageBlock& range) {
728   Factory* factory = isolate->factory();
729 
730   Handle<String> start_string = factory->InternalizeUtf8String("start");
731   Handle<String> end_string = factory->InternalizeUtf8String("end");
732   Handle<String> count_string = factory->InternalizeUtf8String("count");
733 
734   Handle<JSObject> range_obj = factory->NewJSObjectWithNullProto();
735   JSObject::AddProperty(isolate, range_obj, start_string,
736                         factory->NewNumberFromInt(range.start), NONE);
737   JSObject::AddProperty(isolate, range_obj, end_string,
738                         factory->NewNumberFromInt(range.end), NONE);
739   JSObject::AddProperty(isolate, range_obj, count_string,
740                         factory->NewNumberFromUint(range.count), NONE);
741 
742   return range_obj;
743 }
744 }  // namespace
745 
RUNTIME_FUNCTION(Runtime_DebugCollectCoverage)746 RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) {
747   HandleScope scope(isolate);
748   DCHECK_EQ(0, args.length());
749   // Collect coverage data.
750   std::unique_ptr<Coverage> coverage;
751   if (isolate->is_best_effort_code_coverage()) {
752     coverage = Coverage::CollectBestEffort(isolate);
753   } else {
754     coverage = Coverage::CollectPrecise(isolate);
755   }
756   Factory* factory = isolate->factory();
757   // Turn the returned data structure into JavaScript.
758   // Create an array of scripts.
759   int num_scripts = static_cast<int>(coverage->size());
760   // Prepare property keys.
761   Handle<FixedArray> scripts_array = factory->NewFixedArray(num_scripts);
762   Handle<String> script_string = factory->script_string();
763   for (int i = 0; i < num_scripts; i++) {
764     const auto& script_data = coverage->at(i);
765     HandleScope inner_scope(isolate);
766 
767     std::vector<CoverageBlock> ranges;
768     int num_functions = static_cast<int>(script_data.functions.size());
769     for (int j = 0; j < num_functions; j++) {
770       const auto& function_data = script_data.functions[j];
771       ranges.emplace_back(function_data.start, function_data.end,
772                           function_data.count);
773       for (size_t k = 0; k < function_data.blocks.size(); k++) {
774         const auto& block_data = function_data.blocks[k];
775         ranges.emplace_back(block_data.start, block_data.end, block_data.count);
776       }
777     }
778 
779     int num_ranges = static_cast<int>(ranges.size());
780     Handle<FixedArray> ranges_array = factory->NewFixedArray(num_ranges);
781     for (int j = 0; j < num_ranges; j++) {
782       Handle<JSObject> range_object = MakeRangeObject(isolate, ranges[j]);
783       ranges_array->set(j, *range_object);
784     }
785 
786     Handle<JSArray> script_obj =
787         factory->NewJSArrayWithElements(ranges_array, PACKED_ELEMENTS);
788     JSObject::AddProperty(isolate, script_obj, script_string,
789                           handle(script_data.script->source(), isolate), NONE);
790     scripts_array->set(i, *script_obj);
791   }
792   return *factory->NewJSArrayWithElements(scripts_array, PACKED_ELEMENTS);
793 }
794 
RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage)795 RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage) {
796   SealHandleScope shs(isolate);
797   CONVERT_BOOLEAN_ARG_CHECKED(enable, 0);
798   Coverage::SelectMode(isolate, enable ? debug::CoverageMode::kPreciseCount
799                                        : debug::CoverageMode::kBestEffort);
800   return ReadOnlyRoots(isolate).undefined_value();
801 }
802 
RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage)803 RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage) {
804   SealHandleScope shs(isolate);
805   CONVERT_BOOLEAN_ARG_CHECKED(enable, 0);
806   Coverage::SelectMode(isolate, enable ? debug::CoverageMode::kBlockCount
807                                        : debug::CoverageMode::kBestEffort);
808   return ReadOnlyRoots(isolate).undefined_value();
809 }
810 
RUNTIME_FUNCTION(Runtime_IncBlockCounter)811 RUNTIME_FUNCTION(Runtime_IncBlockCounter) {
812   UNREACHABLE();  // Never called. See the IncBlockCounter builtin instead.
813 }
814 
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionEntered)815 RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionEntered) {
816   DCHECK_EQ(1, args.length());
817   HandleScope scope(isolate);
818   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
819   isolate->RunPromiseHook(PromiseHookType::kInit, promise,
820                           isolate->factory()->undefined_value());
821   if (isolate->debug()->is_active()) isolate->PushPromise(promise);
822   return ReadOnlyRoots(isolate).undefined_value();
823 }
824 
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended)825 RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended) {
826   DCHECK_EQ(1, args.length());
827   HandleScope scope(isolate);
828   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
829   isolate->PopPromise();
830   isolate->OnAsyncFunctionStateChanged(promise, debug::kAsyncFunctionSuspended);
831   return ReadOnlyRoots(isolate).undefined_value();
832 }
833 
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionResumed)834 RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionResumed) {
835   DCHECK_EQ(1, args.length());
836   HandleScope scope(isolate);
837   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
838   isolate->PushPromise(promise);
839   return ReadOnlyRoots(isolate).undefined_value();
840 }
841 
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionFinished)842 RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionFinished) {
843   DCHECK_EQ(2, args.length());
844   HandleScope scope(isolate);
845   CONVERT_BOOLEAN_ARG_CHECKED(has_suspend, 0);
846   CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
847   isolate->PopPromise();
848   if (has_suspend) {
849     isolate->OnAsyncFunctionStateChanged(promise,
850                                          debug::kAsyncFunctionFinished);
851   }
852   return *promise;
853 }
854 
RUNTIME_FUNCTION(Runtime_LiveEditPatchScript)855 RUNTIME_FUNCTION(Runtime_LiveEditPatchScript) {
856   HandleScope scope(isolate);
857   DCHECK_EQ(2, args.length());
858   CONVERT_ARG_HANDLE_CHECKED(JSFunction, script_function, 0);
859   CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
860 
861   Handle<Script> script(Script::cast(script_function->shared().script()),
862                         isolate);
863   v8::debug::LiveEditResult result;
864   LiveEdit::PatchScript(isolate, script, new_source, false, &result);
865   switch (result.status) {
866     case v8::debug::LiveEditResult::COMPILE_ERROR:
867       return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
868           "LiveEdit failed: COMPILE_ERROR"));
869     case v8::debug::LiveEditResult::BLOCKED_BY_RUNNING_GENERATOR:
870       return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
871           "LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR"));
872     case v8::debug::LiveEditResult::BLOCKED_BY_ACTIVE_FUNCTION:
873       return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked(
874           "LiveEdit failed: BLOCKED_BY_ACTIVE_FUNCTION"));
875     case v8::debug::LiveEditResult::OK:
876       return ReadOnlyRoots(isolate).undefined_value();
877   }
878   return ReadOnlyRoots(isolate).undefined_value();
879 }
880 
RUNTIME_FUNCTION(Runtime_ProfileCreateSnapshotDataBlob)881 RUNTIME_FUNCTION(Runtime_ProfileCreateSnapshotDataBlob) {
882   HandleScope scope(isolate);
883   DCHECK_EQ(0, args.length());
884 
885   // Used only by the test/memory/Memory.json benchmark. This creates a snapshot
886   // blob and outputs various statistics around it.
887 
888   DCHECK(FLAG_profile_deserialization && FLAG_serialization_statistics);
889 
890   DisableEmbeddedBlobRefcounting();
891 
892   v8::StartupData blob = CreateSnapshotDataBlobInternal(
893       v8::SnapshotCreator::FunctionCodeHandling::kClear, nullptr);
894   delete[] blob.data;
895 
896   // Track the embedded blob size as well.
897   {
898     i::EmbeddedData d = i::EmbeddedData::FromBlob(isolate);
899     PrintF("Embedded blob is %d bytes\n",
900            static_cast<int>(d.code_size() + d.data_size()));
901   }
902 
903   FreeCurrentEmbeddedBlob();
904 
905   return ReadOnlyRoots(isolate).undefined_value();
906 }
907 
908 }  // namespace internal
909 }  // namespace v8
910