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
40namespace v8 {
41namespace internal {
42
43RUNTIME_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
112RUNTIME_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
136RUNTIME_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
147RUNTIME_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
160namespace {
161
162template <class IteratorType>
163static 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
199MaybeHandle<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
381RUNTIME_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
404RUNTIME_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
434static 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
453RUNTIME_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
466RUNTIME_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
487RUNTIME_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.
498RUNTIME_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
506RUNTIME_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
528RUNTIME_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.
542RUNTIME_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
550namespace {
551
552int 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
574int 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
589Handle<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
626Handle<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.
654bool 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.
670RUNTIME_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.
686RUNTIME_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.
709RUNTIME_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
716RUNTIME_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
725RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
726  DCHECK_EQ(0, args.length());
727  SealHandleScope shs(isolate);
728  isolate->PopPromise();
729  return ReadOnlyRoots(isolate).undefined_value();
730}
731
732namespace {
733Handle<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
752RUNTIME_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
801RUNTIME_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
809RUNTIME_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
817RUNTIME_FUNCTION(Runtime_IncBlockCounter) {
818  UNREACHABLE();  // Never called. See the IncBlockCounter builtin instead.
819}
820
821RUNTIME_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
867RUNTIME_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
877RUNTIME_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
903RUNTIME_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