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