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