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