diff options
author | Michaël Zasso <targos@protonmail.com> | 2018-09-07 17:07:13 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2018-09-07 20:59:13 +0200 |
commit | 586db2414a338e1bf6eaf6e672a3adc7ce309f6a (patch) | |
tree | 139fa972aef648481ddee22a3a85b99707d28df5 /deps/v8/src/runtime/runtime-debug.cc | |
parent | 12ed7c94e5160aa6d38e3d2cb2a73dae0a6f9342 (diff) | |
download | android-node-v8-586db2414a338e1bf6eaf6e672a3adc7ce309f6a.tar.gz android-node-v8-586db2414a338e1bf6eaf6e672a3adc7ce309f6a.tar.bz2 android-node-v8-586db2414a338e1bf6eaf6e672a3adc7ce309f6a.zip |
deps: update V8 to 6.9.427.22
PR-URL: https://github.com/nodejs/node/pull/21983
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'deps/v8/src/runtime/runtime-debug.cc')
-rw-r--r-- | deps/v8/src/runtime/runtime-debug.cc | 1301 |
1 files changed, 136 insertions, 1165 deletions
diff --git a/deps/v8/src/runtime/runtime-debug.cc b/deps/v8/src/runtime/runtime-debug.cc index fabb1a80da..9711ffad54 100644 --- a/deps/v8/src/runtime/runtime-debug.cc +++ b/deps/v8/src/runtime/runtime-debug.cc @@ -21,6 +21,8 @@ #include "src/interpreter/interpreter.h" #include "src/isolate-inl.h" #include "src/objects/debug-objects-inl.h" +#include "src/objects/js-collection-inl.h" +#include "src/objects/js-promise-inl.h" #include "src/runtime/runtime.h" #include "src/snapshot/snapshot.h" #include "src/wasm/wasm-objects-inl.h" @@ -45,7 +47,8 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) { // Get the top-most JavaScript frame. JavaScriptFrameIterator it(isolate); if (isolate->debug_execution_mode() == DebugInfo::kBreakpoints) { - isolate->debug()->Break(it.frame(), handle(it.frame()->function())); + isolate->debug()->Break(it.frame(), + handle(it.frame()->function(), isolate)); } // Return the handler from the original bytecode array. @@ -81,7 +84,7 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) { operand_scale); if (side_effect_check_failed) { - return MakePair(isolate->heap()->exception(), + return MakePair(ReadOnlyRoots(isolate).exception(), Smi::FromInt(static_cast<uint8_t>(bytecode))); } Object* interrupt_object = isolate->stack_guard()->HandleInterrupts(); @@ -107,15 +110,7 @@ RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) { DCHECK_EQ(*function, it.frame()->function()); isolate->debug()->Break(it.frame(), function); - return isolate->heap()->undefined_value(); -} - -RUNTIME_FUNCTION(Runtime_DebugApplyInstrumentation) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); - isolate->debug()->ApplyInstrumentation(handle(function->shared())); - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { @@ -127,50 +122,13 @@ RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { return isolate->stack_guard()->HandleInterrupts(); } - RUNTIME_FUNCTION(Runtime_ScheduleBreak) { SealHandleScope shs(isolate); DCHECK_EQ(0, args.length()); - isolate->stack_guard()->RequestDebugBreak(); - return isolate->heap()->undefined_value(); -} - -static Handle<Object> DebugGetProperty(LookupIterator* it, - bool* has_caught = nullptr) { - for (; it->IsFound(); it->Next()) { - switch (it->state()) { - case LookupIterator::NOT_FOUND: - case LookupIterator::TRANSITION: - UNREACHABLE(); - case LookupIterator::ACCESS_CHECK: - // Ignore access checks. - break; - case LookupIterator::INTEGER_INDEXED_EXOTIC: - case LookupIterator::INTERCEPTOR: - case LookupIterator::JSPROXY: - return it->isolate()->factory()->undefined_value(); - case LookupIterator::ACCESSOR: { - Handle<Object> accessors = it->GetAccessors(); - if (!accessors->IsAccessorInfo()) { - return it->isolate()->factory()->undefined_value(); - } - MaybeHandle<Object> maybe_result = - JSObject::GetPropertyWithAccessor(it); - Handle<Object> result; - if (!maybe_result.ToHandle(&result)) { - result = handle(it->isolate()->pending_exception(), it->isolate()); - it->isolate()->clear_pending_exception(); - if (has_caught != nullptr) *has_caught = true; - } - return result; - } - - case LookupIterator::DATA: - return it->GetDataValue(); - } - } - - return it->isolate()->factory()->undefined_value(); + isolate->RequestInterrupt( + [](v8::Isolate* isolate, void*) { v8::debug::BreakRightNow(isolate); }, + nullptr); + return ReadOnlyRoots(isolate).undefined_value(); } template <class IteratorType> @@ -288,7 +246,7 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, result->set(1, *status_str); Handle<Object> value_obj(promise->status() == Promise::kPending - ? isolate->heap()->undefined_value() + ? ReadOnlyRoots(isolate).undefined_value() : promise->result(), isolate); Handle<String> promise_value = @@ -328,627 +286,6 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, return factory->NewJSArray(0); } - -RUNTIME_FUNCTION(Runtime_DebugGetInternalProperties) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); - RETURN_RESULT_OR_FAILURE(isolate, - Runtime::GetInternalProperties(isolate, obj)); -} - - -// Get debugger related details for an object property, in the following format: -// 0: Property value -// 1: Property details -// 2: Property value is exception -// 3: Getter function if defined -// 4: Setter function if defined -// Items 2-4 are only filled if the property has either a getter or a setter. -RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, name_obj, 1); - - // Convert the {name_obj} to a Name. - Handle<Name> name; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, - Object::ToName(isolate, name_obj)); - - // Make sure to set the current context to the context before the debugger was - // entered (if the debugger is entered). The reason for switching context here - // is that for some property lookups (accessors and interceptors) callbacks - // into the embedding application can occur, and the embedding application - // could have the assumption that its own native context is the current - // context and not some internal debugger context. - SaveContext save(isolate); - if (isolate->debug()->in_debug_scope()) { - isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); - } - - // Check if the name is trivially convertible to an index and get the element - // if so. - uint32_t index; - // TODO(verwaest): Make sure DebugGetProperty can handle arrays, and remove - // this special case. - if (name->AsArrayIndex(&index)) { - Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); - Handle<Object> element_or_char; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, element_or_char, JSReceiver::GetElement(isolate, obj, index)); - details->set(0, *element_or_char); - details->set(1, PropertyDetails::Empty().AsSmi()); - return *isolate->factory()->NewJSArrayWithElements(details); - } - - LookupIterator it(obj, name, LookupIterator::OWN); - bool has_caught = false; - Handle<Object> value = DebugGetProperty(&it, &has_caught); - if (!it.IsFound()) return isolate->heap()->undefined_value(); - - Handle<Object> maybe_pair; - if (it.state() == LookupIterator::ACCESSOR) { - maybe_pair = it.GetAccessors(); - } - - // If the callback object is a fixed array then it contains JavaScript - // getter and/or setter. - bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair(); - Handle<FixedArray> details = - isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3); - details->set(0, *value); - // TODO(verwaest): Get rid of this random way of handling interceptors. - PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR - ? PropertyDetails::Empty() - : it.property_details(); - details->set(1, d.AsSmi()); - details->set( - 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR)); - if (has_js_accessors) { - Handle<AccessorPair> accessors = Handle<AccessorPair>::cast(maybe_pair); - details->set(3, isolate->heap()->ToBoolean(has_caught)); - Handle<Object> getter = - AccessorPair::GetComponent(accessors, ACCESSOR_GETTER); - Handle<Object> setter = - AccessorPair::GetComponent(accessors, ACCESSOR_SETTER); - details->set(4, *getter); - details->set(5, *setter); - } - - return *isolate->factory()->NewJSArrayWithElements(details); -} - - -RUNTIME_FUNCTION(Runtime_DebugGetProperty) { - HandleScope scope(isolate); - - DCHECK_EQ(2, args.length()); - - CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); - CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); - - LookupIterator it(obj, name); - return *DebugGetProperty(&it); -} - -// Return the property kind calculated from the property details. -// args[0]: smi with property details. -RUNTIME_FUNCTION(Runtime_DebugPropertyKindFromDetails) { - SealHandleScope shs(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); - return Smi::FromInt(static_cast<int>(details.kind())); -} - - -// Return the property attribute calculated from the property details. -// args[0]: smi with property details. -RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) { - SealHandleScope shs(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); - return Smi::FromInt(static_cast<int>(details.attributes())); -} - - -RUNTIME_FUNCTION(Runtime_CheckExecutionState) { - SealHandleScope shs(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - return isolate->heap()->true_value(); -} - - -RUNTIME_FUNCTION(Runtime_GetFrameCount) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - // Count all frames which are relevant to debugging stack trace. - int n = 0; - StackFrame::Id id = isolate->debug()->break_frame_id(); - if (id == StackFrame::NO_ID) { - // If there is no JavaScript stack frame count is 0. - return Smi::kZero; - } - - std::vector<FrameSummary> frames; - for (StackTraceFrameIterator it(isolate, id); !it.done(); it.Advance()) { - frames.clear(); - it.frame()->Summarize(&frames); - for (size_t i = frames.size(); i != 0; i--) { - // Omit functions from native and extension scripts. - if (frames[i - 1].is_subject_to_debugging()) n++; - } - } - return Smi::FromInt(n); -} - -static const int kFrameDetailsFrameIdIndex = 0; -static const int kFrameDetailsReceiverIndex = 1; -static const int kFrameDetailsFunctionIndex = 2; -static const int kFrameDetailsScriptIndex = 3; -static const int kFrameDetailsArgumentCountIndex = 4; -static const int kFrameDetailsLocalCountIndex = 5; -static const int kFrameDetailsSourcePositionIndex = 6; -static const int kFrameDetailsConstructCallIndex = 7; -static const int kFrameDetailsAtReturnIndex = 8; -static const int kFrameDetailsFlagsIndex = 9; -static const int kFrameDetailsFirstDynamicIndex = 10; - -// Return an array with frame details -// args[0]: number: break id -// args[1]: number: frame index -// -// The array returned contains the following information: -// 0: Frame id -// 1: Receiver -// 2: Function -// 3: Script -// 4: Argument count -// 5: Local count -// 6: Source position -// 7: Constructor call -// 8: Is at return -// 9: Flags -// Arguments name, value -// Locals name, value -// Return value if any -RUNTIME_FUNCTION(Runtime_GetFrameDetails) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); - Heap* heap = isolate->heap(); - - // Find the relevant frame with the requested index. - StackFrame::Id id = isolate->debug()->break_frame_id(); - if (id == StackFrame::NO_ID) { - // If there are no JavaScript stack frames return undefined. - return heap->undefined_value(); - } - - StackTraceFrameIterator it(isolate, id); - // Inlined frame index in optimized frame, starting from outer function. - int inlined_frame_index = - DebugFrameHelper::FindIndexedNonNativeFrame(&it, index); - if (inlined_frame_index == -1) return heap->undefined_value(); - - FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate); - - // Traverse the saved contexts chain to find the active context for the - // selected frame. - SaveContext* save = - DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame()); - - // Get the frame id. - Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()), - isolate); - - if (frame_inspector.IsWasm()) { - // Create the details array (no dynamic information for wasm). - Handle<FixedArray> details = - isolate->factory()->NewFixedArray(kFrameDetailsFirstDynamicIndex); - - // Add the frame id. - details->set(kFrameDetailsFrameIdIndex, *frame_id); - - // Add the function name. - Handle<String> func_name = frame_inspector.GetFunctionName(); - details->set(kFrameDetailsFunctionIndex, *func_name); - - // Add the script wrapper - Handle<Object> script_wrapper = - Script::GetWrapper(frame_inspector.GetScript()); - details->set(kFrameDetailsScriptIndex, *script_wrapper); - - // Add the arguments count. - details->set(kFrameDetailsArgumentCountIndex, Smi::kZero); - - // Add the locals count - details->set(kFrameDetailsLocalCountIndex, Smi::kZero); - - // Add the source position. - int position = frame_inspector.GetSourcePosition(); - details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); - - // Add the constructor information. - details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(false)); - - // Add the at return information. - details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(false)); - - // Add flags to indicate information on whether this frame is - // bit 0: invoked in the debugger context. - // bit 1: optimized frame. - // bit 2: inlined in optimized frame - int flags = inlined_frame_index << 2; - if (*save->context() == *isolate->debug()->debug_context()) { - flags |= 1 << 0; - } - details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); - - return *isolate->factory()->NewJSArrayWithElements(details); - } - - // Find source position in unoptimized code. - int position = frame_inspector.GetSourcePosition(); - - // Handle JavaScript frames. - bool is_optimized = it.frame()->is_optimized(); - - // Check for constructor frame. - bool constructor = frame_inspector.IsConstructor(); - - // Get scope info and read from it for local variable information. - Handle<JSFunction> function = - Handle<JSFunction>::cast(frame_inspector.GetFunction()); - CHECK(function->shared()->IsSubjectToDebugging()); - Handle<SharedFunctionInfo> shared(function->shared()); - Handle<ScopeInfo> scope_info(shared->scope_info()); - DCHECK(*scope_info != ScopeInfo::Empty(isolate)); - - // Get the locals names and values into a temporary array. - Handle<Object> maybe_context = frame_inspector.GetContext(); - const int local_count_with_synthetic = maybe_context->IsContext() - ? scope_info->LocalCount() - : scope_info->StackLocalCount(); - int local_count = local_count_with_synthetic; - for (int slot = 0; slot < local_count_with_synthetic; ++slot) { - // Hide compiler-introduced temporary variables, whether on the stack or on - // the context. - if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(slot))) { - local_count--; - } - } - - std::vector<Handle<Object>> locals; - // Fill in the values of the locals. - int i = 0; - for (; i < scope_info->StackLocalCount(); ++i) { - // Use the value from the stack. - if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(i))) continue; - locals.emplace_back(scope_info->LocalName(i), isolate); - Handle<Object> value = - frame_inspector.GetExpression(scope_info->StackLocalIndex(i)); - // TODO(yangguo): We convert optimized out values to {undefined} when they - // are passed to the debugger. Eventually we should handle them somehow. - if (value->IsOptimizedOut(isolate)) { - value = isolate->factory()->undefined_value(); - } - locals.push_back(value); - } - if (static_cast<int>(locals.size()) < local_count * 2) { - // Get the context containing declarations. - DCHECK(maybe_context->IsContext()); - Handle<Context> context(Context::cast(*maybe_context)->closure_context()); - - for (; i < scope_info->LocalCount(); ++i) { - Handle<String> name(scope_info->LocalName(i)); - if (ScopeInfo::VariableIsSynthetic(*name)) continue; - VariableMode mode; - InitializationFlag init_flag; - MaybeAssignedFlag maybe_assigned_flag; - locals.push_back(name); - int context_slot_index = ScopeInfo::ContextSlotIndex( - scope_info, name, &mode, &init_flag, &maybe_assigned_flag); - Object* value = context->get(context_slot_index); - locals.emplace_back(value, isolate); - } - } - - // Check whether this frame is positioned at return. If not top - // frame or if the frame is optimized it cannot be at a return. - bool at_return = false; - if (!is_optimized && index == 0) { - at_return = isolate->debug()->IsBreakAtReturn(it.javascript_frame()); - } - - // If positioned just before return find the value to be returned and add it - // to the frame information. - Handle<Object> return_value = isolate->factory()->undefined_value(); - if (at_return) { - return_value = handle(isolate->debug()->return_value(), isolate); - } - - // Now advance to the arguments adapter frame (if any). It contains all - // the provided parameters whereas the function frame always have the number - // of arguments matching the functions parameters. The rest of the - // information (except for what is collected above) is the same. - if ((inlined_frame_index == 0) && - it.javascript_frame()->has_adapted_arguments()) { - it.AdvanceOneFrame(); - DCHECK(it.frame()->is_arguments_adaptor()); - frame_inspector.SetArgumentsFrame(it.frame()); - } - - // Find the number of arguments to fill. At least fill the number of - // parameters for the function and fill more if more parameters are provided. - int argument_count = scope_info->ParameterCount(); - if (argument_count < frame_inspector.GetParametersCount()) { - argument_count = frame_inspector.GetParametersCount(); - } - - // Calculate the size of the result. - int details_size = kFrameDetailsFirstDynamicIndex + - 2 * (argument_count + local_count) + (at_return ? 1 : 0); - Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); - - // Add the frame id. - details->set(kFrameDetailsFrameIdIndex, *frame_id); - - // Add the function (same as in function frame). - details->set(kFrameDetailsFunctionIndex, *(frame_inspector.GetFunction())); - - // Add the script wrapper - Handle<Object> script_wrapper = - Script::GetWrapper(frame_inspector.GetScript()); - details->set(kFrameDetailsScriptIndex, *script_wrapper); - - // Add the arguments count. - details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); - - // Add the locals count - details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count)); - - // Add the source position. - if (position != kNoSourcePosition) { - details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); - } else { - details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); - } - - // Add the constructor information. - details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); - - // Add the at return information. - details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); - - // Add flags to indicate information on whether this frame is - // bit 0: invoked in the debugger context. - // bit 1: optimized frame. - // bit 2: inlined in optimized frame - int flags = 0; - if (*save->context() == *isolate->debug()->debug_context()) { - flags |= 1 << 0; - } - if (is_optimized) { - flags |= 1 << 1; - flags |= inlined_frame_index << 2; - } - details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); - - // Fill the dynamic part. - int details_index = kFrameDetailsFirstDynamicIndex; - - // Add arguments name and value. - for (int i = 0; i < argument_count; i++) { - // Name of the argument. - if (i < scope_info->ParameterCount()) { - details->set(details_index++, scope_info->ParameterName(i)); - } else { - details->set(details_index++, heap->undefined_value()); - } - - // Parameter value. - if (i < frame_inspector.GetParametersCount()) { - // Get the value from the stack. - details->set(details_index++, *(frame_inspector.GetParameter(i))); - } else { - details->set(details_index++, heap->undefined_value()); - } - } - - // Add locals name and value from the temporary copy from the function frame. - for (const auto& local : locals) details->set(details_index++, *local); - - // Add the value being returned. - if (at_return) { - details->set(details_index++, *return_value); - } - - // Add the receiver (same as in function frame). - Handle<Object> receiver = frame_inspector.GetReceiver(); - DCHECK(function->shared()->IsUserJavaScript()); - // Optimized frames only restore the receiver as best-effort (see - // OptimizedFrame::Summarize). - DCHECK_IMPLIES(!is_optimized && is_sloppy(shared->language_mode()), - receiver->IsJSReceiver()); - details->set(kFrameDetailsReceiverIndex, *receiver); - - DCHECK_EQ(details_size, details_index); - return *isolate->factory()->NewJSArrayWithElements(details); -} - - -RUNTIME_FUNCTION(Runtime_GetScopeCount) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); - - // Get the frame where the debugging is performed. - StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); - StackTraceFrameIterator it(isolate, id); - StandardFrame* frame = it.frame(); - if (it.frame()->is_wasm()) return 0; - - FrameInspector frame_inspector(frame, 0, isolate); - - // Count the visible scopes. - int n = 0; - for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) { - n++; - } - - return Smi::FromInt(n); -} - - -// Return an array with scope details -// args[0]: number: break id -// args[1]: number: frame index -// args[2]: number: inlined frame index -// args[3]: number: scope index -// -// The array returned contains the following information: -// 0: Scope type -// 1: Scope object -RUNTIME_FUNCTION(Runtime_GetScopeDetails) { - HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); - CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); - CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); - - // Get the frame where the debugging is performed. - StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); - StackTraceFrameIterator frame_it(isolate, id); - // Wasm has no scopes, this must be javascript. - JavaScriptFrame* frame = JavaScriptFrame::cast(frame_it.frame()); - FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); - - // Find the requested scope. - int n = 0; - ScopeIterator it(isolate, &frame_inspector); - for (; !it.Done() && n < index; it.Next()) { - n++; - } - if (it.Done()) { - return isolate->heap()->undefined_value(); - } - RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails()); -} - - -// Return an array of scope details -// args[0]: number: break id -// args[1]: number: frame index -// args[2]: number: inlined frame index -// args[3]: boolean: ignore nested scopes -// -// The array returned contains arrays with the following information: -// 0: Scope type -// 1: Scope object -RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { - HandleScope scope(isolate); - DCHECK(args.length() == 3 || args.length() == 4); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); - CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]); - - ScopeIterator::Option option = ScopeIterator::DEFAULT; - if (args.length() == 4) { - CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); - if (flag) option = ScopeIterator::IGNORE_NESTED_SCOPES; - } - - // Get the frame where the debugging is performed. - StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); - StackTraceFrameIterator frame_it(isolate, id); - StandardFrame* frame = frame_it.frame(); - - // Handle wasm frames specially. They provide exactly two scopes (global / - // local). - if (frame->is_wasm_interpreter_entry()) { - Handle<WasmDebugInfo> debug_info( - WasmInterpreterEntryFrame::cast(frame)->debug_info(), isolate); - return *WasmDebugInfo::GetScopeDetails(debug_info, frame->fp(), - inlined_frame_index); - } - - FrameInspector frame_inspector(frame, inlined_frame_index, isolate); - std::vector<Handle<JSObject>> result; - ScopeIterator it(isolate, &frame_inspector, option); - for (; !it.Done(); it.Next()) { - Handle<JSObject> details; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, - it.MaterializeScopeDetails()); - result.push_back(details); - } - - int result_size = static_cast<int>(result.size()); - Handle<FixedArray> array = isolate->factory()->NewFixedArray(result_size); - for (int i = 0; i < result_size; ++i) { - array->set(i, *result[i]); - } - return *isolate->factory()->NewJSArrayWithElements(array); -} - - -RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - - // Check arguments. - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); - - // Count the visible scopes. - int n = 0; - if (function->IsJSFunction()) { - for (ScopeIterator it(isolate, Handle<JSFunction>::cast(function)); - !it.Done(); it.Next()) { - n++; - } - } - - return Smi::FromInt(n); -} - - -RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - - // Check arguments. - CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); - CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); - - // Find the requested scope. - int n = 0; - ScopeIterator it(isolate, fun); - for (; !it.Done() && n < index; it.Next()) { - n++; - } - if (it.Done()) { - return isolate->heap()->undefined_value(); - } - - RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails()); -} - RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); @@ -977,7 +314,7 @@ RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) { DCHECK_EQ(2, args.length()); if (!args[0]->IsJSGeneratorObject()) { - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } // Check arguments. @@ -986,7 +323,7 @@ RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) { // Only inspect suspended generator scopes. if (!gen->is_suspended()) { - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } // Find the requested scope. @@ -996,10 +333,10 @@ RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) { n++; } if (it.Done()) { - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } - RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails()); + return *it.MaterializeScopeDetails(); } static bool SetScopeVariableValue(ScopeIterator* it, int index, @@ -1014,52 +351,22 @@ static bool SetScopeVariableValue(ScopeIterator* it, int index, return it->SetVariableValue(variable_name, new_value); } - // Change variable value in closure or local scope // args[0]: number or JsFunction: break id or function -// args[1]: number: frame index (when arg[0] is break id) -// args[2]: number: inlined frame index (when arg[0] is break id) -// args[3]: number: scope index -// args[4]: string: variable name -// args[5]: object: new value +// args[1]: number: scope index +// args[2]: string: variable name +// args[3]: object: new value // // Return true if success and false otherwise -RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { +RUNTIME_FUNCTION(Runtime_SetGeneratorScopeVariableValue) { HandleScope scope(isolate); - DCHECK_EQ(6, args.length()); - - // Check arguments. - CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); - CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); - CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5); - - bool res; - if (args[0]->IsNumber()) { - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); - CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); - - // Get the frame where the debugging is performed. - StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); - StackTraceFrameIterator frame_it(isolate, id); - // Wasm has no scopes, this must be javascript. - JavaScriptFrame* frame = JavaScriptFrame::cast(frame_it.frame()); - FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); - - ScopeIterator it(isolate, &frame_inspector); - res = SetScopeVariableValue(&it, index, variable_name, new_value); - } else if (args[0]->IsJSFunction()) { - CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); - ScopeIterator it(isolate, fun); - res = SetScopeVariableValue(&it, index, variable_name, new_value); - } else { - CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0); - ScopeIterator it(isolate, gen); - res = SetScopeVariableValue(&it, index, variable_name, new_value); - } - + DCHECK_EQ(4, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0); + CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); + CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 2); + CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 3); + ScopeIterator it(isolate, gen); + bool res = SetScopeVariableValue(&it, index, variable_name, new_value); return isolate->heap()->ToBoolean(res); } @@ -1070,11 +377,12 @@ RUNTIME_FUNCTION(Runtime_GetBreakLocations) { CHECK(isolate->debug()->is_active()); CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); - Handle<SharedFunctionInfo> shared(fun->shared()); + Handle<SharedFunctionInfo> shared(fun->shared(), isolate); // Find the number of break points - Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared); + Handle<Object> break_locations = + Debug::GetSourceBreakLocations(isolate, shared); if (break_locations->IsUndefined(isolate)) { - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } // Return array as JS array return *isolate->factory()->NewJSArrayWithElements( @@ -1082,24 +390,6 @@ RUNTIME_FUNCTION(Runtime_GetBreakLocations) { } -// Change the state of break on exceptions. -// args[0]: Enum value indicating whether to affect caught/uncaught exceptions. -// args[1]: Boolean indicating on/off. -RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); - CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); - - // If the number doesn't match an enum value, the ChangeBreakOnException - // function will default to affecting caught exceptions. - ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); - // Update break point state. - isolate->debug()->ChangeBreakOnException(type, enable); - return isolate->heap()->undefined_value(); -} - - // Returns the state of break on exceptions // args[0]: boolean indicating uncaught exceptions RUNTIME_FUNCTION(Runtime_IsBreakOnException) { @@ -1112,256 +402,36 @@ RUNTIME_FUNCTION(Runtime_IsBreakOnException) { return Smi::FromInt(result); } - -// Prepare for stepping -// args[0]: break id for checking execution state -// args[1]: step action from the enumeration StepAction -// args[2]: number of times to perform the step, for step out it is the number -// of frames to step down. -RUNTIME_FUNCTION(Runtime_PrepareStep) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - if (!args[1]->IsNumber()) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } - - // Get the step action and check validity. - StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); - if (step_action != StepIn && step_action != StepNext && - step_action != StepOut) { - return isolate->Throw(isolate->heap()->illegal_argument_string()); - } - - // Clear all current stepping setup. - isolate->debug()->ClearStepping(); - - // Prepare step. - isolate->debug()->PrepareStep(static_cast<StepAction>(step_action)); - return isolate->heap()->undefined_value(); -} - // Clear all stepping set by PrepareStep. RUNTIME_FUNCTION(Runtime_ClearStepping) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); CHECK(isolate->debug()->is_active()); isolate->debug()->ClearStepping(); - return isolate->heap()->undefined_value(); -} - - -RUNTIME_FUNCTION(Runtime_DebugEvaluate) { - HandleScope scope(isolate); - - // Check the execution state and decode arguments frame and source to be - // evaluated. - DCHECK_EQ(5, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); - CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); - CONVERT_ARG_HANDLE_CHECKED(String, source, 3); - CONVERT_BOOLEAN_ARG_CHECKED(throw_on_side_effect, 4); - - StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); - - RETURN_RESULT_OR_FAILURE( - isolate, DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source, - throw_on_side_effect)); + return ReadOnlyRoots(isolate).undefined_value(); } - -RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { - HandleScope scope(isolate); - - // Check the execution state and decode arguments frame and source to be - // evaluated. - DCHECK_EQ(2, args.length()); - CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); - CHECK(isolate->debug()->CheckExecutionState(break_id)); - - CONVERT_ARG_HANDLE_CHECKED(String, source, 1); - - RETURN_RESULT_OR_FAILURE(isolate, - DebugEvaluate::Global(isolate, source, false)); -} - - -RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { +RUNTIME_FUNCTION(Runtime_DebugGetLoadedScriptIds) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); Handle<FixedArray> instances; { DebugScope debug_scope(isolate->debug()); - if (debug_scope.failed()) { - DCHECK(isolate->has_pending_exception()); - return isolate->heap()->exception(); - } // Fill the script objects. instances = isolate->debug()->GetLoadedScripts(); } // Convert the script objects to proper JS objects. for (int i = 0; i < instances->length(); i++) { - Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); - // Get the script wrapper in a local handle before calling GetScriptWrapper, - // because using - // instances->set(i, *GetScriptWrapper(script)) - // is unsafe as GetScriptWrapper might call GC and the C++ compiler might - // already have dereferenced the instances handle. - Handle<JSObject> wrapper = Script::GetWrapper(script); - instances->set(i, *wrapper); + Handle<Script> script(Script::cast(instances->get(i)), isolate); + instances->set(i, Smi::FromInt(script->id())); } // Return result as a JS array. return *isolate->factory()->NewJSArrayWithElements(instances); } -static bool HasInPrototypeChainIgnoringProxies(Isolate* isolate, - JSObject* object, - Object* proto) { - PrototypeIterator iter(isolate, object, kStartAtReceiver); - while (true) { - iter.AdvanceIgnoringProxies(); - if (iter.IsAtEnd()) return false; - if (iter.GetCurrent() == proto) return true; - } -} - - -// Scan the heap for objects with direct references to an object -// args[0]: the object to find references to -// args[1]: constructor function for instances to exclude (Mirror) -// args[2]: the the maximum number of objects to return -RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, filter, 1); - CHECK(filter->IsUndefined(isolate) || filter->IsJSObject()); - CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); - CHECK_GE(max_references, 0); - - std::vector<Handle<JSObject>> instances; - Heap* heap = isolate->heap(); - { - HeapIterator iterator(heap, HeapIterator::kFilterUnreachable); - // Get the constructor function for context extension and arguments array. - Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor(); - HeapObject* heap_obj; - while ((heap_obj = iterator.next()) != nullptr) { - if (!heap_obj->IsJSObject()) continue; - JSObject* obj = JSObject::cast(heap_obj); - if (obj->IsJSContextExtensionObject()) continue; - if (obj->map()->GetConstructor() == arguments_fun) continue; - if (!obj->ReferencesObject(*target)) continue; - // Check filter if supplied. This is normally used to avoid - // references from mirror objects. - if (!filter->IsUndefined(isolate) && - HasInPrototypeChainIgnoringProxies(isolate, obj, *filter)) { - continue; - } - if (obj->IsJSGlobalObject()) { - obj = JSGlobalObject::cast(obj)->global_proxy(); - } - instances.emplace_back(obj); - if (static_cast<int32_t>(instances.size()) == max_references) break; - } - // Iterate the rest of the heap to satisfy HeapIterator constraints. - while (iterator.next()) { - } - } - - Handle<FixedArray> result; - if (instances.size() == 1 && instances.back().is_identical_to(target)) { - // Check for circular reference only. This can happen when the object is - // only referenced from mirrors and has a circular reference in which case - // the object is not really alive and would have been garbage collected if - // not referenced from the mirror. - result = isolate->factory()->empty_fixed_array(); - } else { - int instances_size = static_cast<int>(instances.size()); - result = isolate->factory()->NewFixedArray(instances_size); - for (int i = 0; i < instances_size; ++i) result->set(i, *instances[i]); - } - return *isolate->factory()->NewJSArrayWithElements(result); -} - - -// Scan the heap for objects constructed by a specific function. -// args[0]: the constructor to find instances of -// args[1]: the the maximum number of objects to return -RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); - CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); - CHECK_GE(max_references, 0); - - std::vector<Handle<JSObject>> instances; - Heap* heap = isolate->heap(); - { - HeapIterator iterator(heap, HeapIterator::kFilterUnreachable); - HeapObject* heap_obj; - while ((heap_obj = iterator.next()) != nullptr) { - if (!heap_obj->IsJSObject()) continue; - JSObject* obj = JSObject::cast(heap_obj); - if (obj->map()->GetConstructor() != *constructor) continue; - instances.emplace_back(obj); - if (static_cast<int32_t>(instances.size()) == max_references) break; - } - // Iterate the rest of the heap to satisfy HeapIterator constraints. - while (iterator.next()) { - } - } - - int instances_size = static_cast<int>(instances.size()); - Handle<FixedArray> result = isolate->factory()->NewFixedArray(instances_size); - for (int i = 0; i < instances_size; ++i) result->set(i, *instances[i]); - return *isolate->factory()->NewJSArrayWithElements(result); -} - - -// Find the effective prototype object as returned by __proto__. -// args[0]: the object to find the prototype for. -RUNTIME_FUNCTION(Runtime_DebugGetPrototype) { - HandleScope shs(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); - // TODO(1543): Come up with a solution for clients to handle potential errors - // thrown by an intermediate proxy. - RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj)); -} - - -// Patches script source (should be called upon BeforeCompile event). -// TODO(5530): Remove once uses in debug.js are gone. -RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - - CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); - CONVERT_ARG_HANDLE_CHECKED(String, source, 1); - - CHECK(script_wrapper->value()->IsScript()); - Handle<Script> script(Script::cast(script_wrapper->value())); - - // The following condition is not guaranteed to hold and a failure is also - // propagated to callers. Hence we fail gracefully here and don't crash. - if (script->compilation_state() != Script::COMPILATION_STATE_INITIAL) { - return isolate->ThrowIllegalOperation(); - } - - script->set_source(*source); - - return isolate->heap()->undefined_value(); -} - RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { SealHandleScope shs(isolate); @@ -1371,41 +441,7 @@ RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { if (f->IsJSFunction()) { return JSFunction::cast(f)->shared()->inferred_name(); } - return isolate->heap()->empty_string(); -} - - -RUNTIME_FUNCTION(Runtime_FunctionGetDebugName) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); - - if (function->IsJSBoundFunction()) { - RETURN_RESULT_OR_FAILURE( - isolate, JSBoundFunction::GetName( - isolate, Handle<JSBoundFunction>::cast(function))); - } else { - return *JSFunction::GetDebugName(Handle<JSFunction>::cast(function)); - } -} - - -RUNTIME_FUNCTION(Runtime_GetDebugContext) { - HandleScope scope(isolate); - DCHECK_EQ(0, args.length()); - Handle<Context> context; - { - DebugScope debug_scope(isolate->debug()); - if (debug_scope.failed()) { - DCHECK(isolate->has_pending_exception()); - return isolate->heap()->exception(); - } - context = isolate->debug()->GetDebugContext(); - } - if (context.is_null()) return isolate->heap()->undefined_value(); - context->set_security_token(isolate->native_context()->security_token()); - return context->global_proxy(); + return ReadOnlyRoots(isolate).empty_string(); } @@ -1416,7 +452,7 @@ RUNTIME_FUNCTION(Runtime_CollectGarbage) { DCHECK_EQ(1, args.length()); isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask, GarbageCollectionReason::kRuntime); - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } @@ -1431,56 +467,6 @@ RUNTIME_FUNCTION(Runtime_GetHeapUsage) { return Smi::FromInt(usage); } - -// Finds the script object from the script data. NOTE: This operation uses -// heap traversal to find the function generated for the source position -// for the requested break point. For lazily compiled functions several heap -// traversals might be required rendering this operation as a rather slow -// operation. However for setting break points which is normally done through -// some kind of user interaction the performance is not crucial. -RUNTIME_FUNCTION(Runtime_GetScript) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0); - - Handle<Script> found; - { - Script::Iterator iterator(isolate); - Script* script = nullptr; - while ((script = iterator.Next()) != nullptr) { - if (!script->name()->IsString()) continue; - String* name = String::cast(script->name()); - if (name->Equals(*script_name)) { - found = Handle<Script>(script, isolate); - break; - } - } - } - - if (found.is_null()) return isolate->heap()->undefined_value(); - return *Script::GetWrapper(found); -} - -// TODO(5530): Remove once uses in debug.js are gone. -RUNTIME_FUNCTION(Runtime_ScriptLineCount) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_CHECKED(JSValue, script, 0); - - CHECK(script->value()->IsScript()); - Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); - - if (script_handle->type() == Script::TYPE_WASM) { - // Return 0 for now; this function will disappear soon anyway. - return Smi::FromInt(0); - } - - Script::InitLineEnds(script_handle); - - FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends()); - return Smi::FromInt(line_ends_array->length()); -} - namespace { int ScriptLinePosition(Handle<Script> script, int line) { @@ -1488,7 +474,6 @@ int ScriptLinePosition(Handle<Script> script, int line) { if (script->type() == Script::TYPE_WASM) { return WasmModuleObject::cast(script->wasm_module_object()) - ->shared() ->GetFunctionOffset(line); } @@ -1504,11 +489,24 @@ int ScriptLinePosition(Handle<Script> script, int line) { return Smi::ToInt(line_ends_array->get(line - 1)) + 1; } -} // namespace +int ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset) { + if (line < 0 || offset < 0) return -1; + + if (line == 0 || offset == 0) + return ScriptLinePosition(script, line) + offset; + + Script::PositionInfo info; + if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET)) { + return -1; + } -static Handle<Object> GetJSPositionInfo(Handle<Script> script, int position, - Script::OffsetFlag offset_flag, - Isolate* isolate) { + const int total_line = info.line + line; + return ScriptLinePosition(script, total_line); +} + +Handle<Object> GetJSPositionInfo(Handle<Script> script, int position, + Script::OffsetFlag offset_flag, + Isolate* isolate) { Script::PositionInfo info; if (!Script::GetPositionInfo(script, position, &info, offset_flag)) { return isolate->factory()->null_value(); @@ -1523,37 +521,21 @@ static Handle<Object> GetJSPositionInfo(Handle<Script> script, int position, Handle<JSObject> jsinfo = isolate->factory()->NewJSObject(isolate->object_function()); - JSObject::AddProperty(jsinfo, isolate->factory()->script_string(), script, - NONE); - JSObject::AddProperty(jsinfo, isolate->factory()->position_string(), + JSObject::AddProperty(isolate, jsinfo, isolate->factory()->script_string(), + script, NONE); + JSObject::AddProperty(isolate, jsinfo, isolate->factory()->position_string(), handle(Smi::FromInt(position), isolate), NONE); - JSObject::AddProperty(jsinfo, isolate->factory()->line_string(), + JSObject::AddProperty(isolate, jsinfo, isolate->factory()->line_string(), handle(Smi::FromInt(info.line), isolate), NONE); - JSObject::AddProperty(jsinfo, isolate->factory()->column_string(), + JSObject::AddProperty(isolate, jsinfo, isolate->factory()->column_string(), handle(Smi::FromInt(info.column), isolate), NONE); - JSObject::AddProperty(jsinfo, isolate->factory()->sourceText_string(), - sourceText, NONE); + JSObject::AddProperty(isolate, jsinfo, + isolate->factory()->sourceText_string(), sourceText, + NONE); return jsinfo; } -namespace { - -int ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset) { - if (line < 0 || offset < 0) return -1; - - if (line == 0 || offset == 0) - return ScriptLinePosition(script, line) + offset; - - Script::PositionInfo info; - if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET)) { - return -1; - } - - const int total_line = info.line + line; - return ScriptLinePosition(script, total_line); -} - Handle<Object> ScriptLocationFromLine(Isolate* isolate, Handle<Script> script, Handle<Object> opt_line, Handle<Object> opt_column, @@ -1587,7 +569,7 @@ bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) { Script* script = nullptr; while ((script = iterator.Next()) != nullptr) { if (script->id() == needle) { - *result = handle(script); + *result = handle(script, isolate); return true; } } @@ -1597,30 +579,6 @@ bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) { } // namespace -// Get information on a specific source line and column possibly offset by a -// fixed source position. This function is used to find a source position from -// a line and column position. The fixed source position offset is typically -// used to find a source position in a function based on a line and column in -// the source for the function alone. The offset passed will then be the -// start position of the source for the function within the full script source. -// Note that incoming line and column parameters may be undefined, and are -// assumed to be passed *with* offsets. -// TODO(5530): Remove once uses in debug.js are gone. -RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine) { - HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSValue, script, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, opt_line, 1); - CONVERT_ARG_HANDLE_CHECKED(Object, opt_column, 2); - CONVERT_NUMBER_CHECKED(int32_t, offset, Int32, args[3]); - - CHECK(script->value()->IsScript()); - Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); - - return *ScriptLocationFromLine(isolate, script_handle, opt_line, opt_column, - offset); -} - // TODO(5530): Rename once conflicting function has been deleted. RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) { HandleScope scope(isolate); @@ -1636,38 +594,6 @@ RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) { return *ScriptLocationFromLine(isolate, script, opt_line, opt_column, offset); } -// TODO(5530): Remove once uses in debug.js are gone. -RUNTIME_FUNCTION(Runtime_ScriptPositionInfo) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - CONVERT_ARG_CHECKED(JSValue, script, 0); - CONVERT_NUMBER_CHECKED(int32_t, position, Int32, args[1]); - CONVERT_BOOLEAN_ARG_CHECKED(with_offset, 2); - - CHECK(script->value()->IsScript()); - Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); - - const Script::OffsetFlag offset_flag = - with_offset ? Script::WITH_OFFSET : Script::NO_OFFSET; - return *GetJSPositionInfo(script_handle, position, offset_flag, isolate); -} - -// TODO(5530): Rename once conflicting function has been deleted. -RUNTIME_FUNCTION(Runtime_ScriptPositionInfo2) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - CONVERT_NUMBER_CHECKED(int32_t, scriptid, Int32, args[0]); - CONVERT_NUMBER_CHECKED(int32_t, position, Int32, args[1]); - CONVERT_BOOLEAN_ARG_CHECKED(with_offset, 2); - - Handle<Script> script; - CHECK(GetScriptById(isolate, scriptid, &script)); - - const Script::OffsetFlag offset_flag = - with_offset ? Script::WITH_OFFSET : Script::NO_OFFSET; - return *GetJSPositionInfo(script, position, offset_flag, isolate); -} - // On function call, depending on circumstances, prepare for stepping in, // or perform a side effect check. RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) { @@ -1678,16 +604,17 @@ RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) { if (isolate->debug()->needs_check_on_function_call()) { // Ensure that the callee will perform debug check on function call too. Deoptimizer::DeoptimizeFunction(*fun); - if (isolate->debug()->last_step_action() >= StepIn) { + if (isolate->debug()->last_step_action() >= StepIn || + isolate->debug()->break_on_next_function_call()) { DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kBreakpoints); isolate->debug()->PrepareStepIn(fun); } if (isolate->debug_execution_mode() == DebugInfo::kSideEffects && !isolate->debug()->PerformSideEffectCheck(fun, receiver)) { - return isolate->heap()->exception(); + return ReadOnlyRoots(isolate).exception(); } } - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } // Set one shot breakpoints for the suspended generator object. @@ -1695,7 +622,7 @@ RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator) { HandleScope scope(isolate); DCHECK_EQ(0, args.length()); isolate->debug()->PrepareStepInSuspendedGenerator(); - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } RUNTIME_FUNCTION(Runtime_DebugPushPromise) { @@ -1703,7 +630,7 @@ RUNTIME_FUNCTION(Runtime_DebugPushPromise) { HandleScope scope(isolate); CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); isolate->PushPromise(promise); - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } @@ -1711,22 +638,7 @@ RUNTIME_FUNCTION(Runtime_DebugPopPromise) { DCHECK_EQ(0, args.length()); SealHandleScope shs(isolate); isolate->PopPromise(); - return isolate->heap()->undefined_value(); -} - -RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionPromiseCreated) { - DCHECK_EQ(1, args.length()); - HandleScope scope(isolate); - CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); - isolate->PushPromise(promise); - int id = isolate->debug()->NextAsyncTaskId(promise); - Handle<Symbol> async_stack_id_symbol = - isolate->factory()->promise_async_stack_id_symbol(); - JSObject::SetProperty(promise, async_stack_id_symbol, - handle(Smi::FromInt(id), isolate), - LanguageMode::kStrict) - .Assert(); - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } RUNTIME_FUNCTION(Runtime_DebugIsActive) { @@ -1743,11 +655,11 @@ Handle<JSObject> MakeRangeObject(Isolate* isolate, const CoverageBlock& range) { Handle<String> count_string = factory->InternalizeUtf8String("count"); Handle<JSObject> range_obj = factory->NewJSObjectWithNullProto(); - JSObject::AddProperty(range_obj, start_string, + JSObject::AddProperty(isolate, range_obj, start_string, factory->NewNumberFromInt(range.start), NONE); - JSObject::AddProperty(range_obj, end_string, + JSObject::AddProperty(isolate, range_obj, end_string, factory->NewNumberFromInt(range.end), NONE); - JSObject::AddProperty(range_obj, count_string, + JSObject::AddProperty(isolate, range_obj, count_string, factory->NewNumberFromUint(range.count), NONE); return range_obj; @@ -1796,8 +708,8 @@ RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) { Handle<JSArray> script_obj = factory->NewJSArrayWithElements(ranges_array, PACKED_ELEMENTS); - Handle<JSObject> wrapper = Script::GetWrapper(script_data.script); - JSObject::AddProperty(script_obj, script_string, wrapper, NONE); + JSObject::AddProperty(isolate, script_obj, script_string, + handle(script_data.script->source(), isolate), NONE); scripts_array->set(i, *script_obj); } return *factory->NewJSArrayWithElements(scripts_array, PACKED_ELEMENTS); @@ -1808,7 +720,7 @@ RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage) { CONVERT_BOOLEAN_ARG_CHECKED(enable, 0); Coverage::SelectMode(isolate, enable ? debug::Coverage::kPreciseCount : debug::Coverage::kBestEffort); - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage) { @@ -1816,7 +728,7 @@ RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage) { CONVERT_BOOLEAN_ARG_CHECKED(enable, 0); Coverage::SelectMode(isolate, enable ? debug::Coverage::kBlockCount : debug::Coverage::kBestEffort); - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } RUNTIME_FUNCTION(Runtime_IncBlockCounter) { @@ -1836,8 +748,67 @@ RUNTIME_FUNCTION(Runtime_IncBlockCounter) { coverage_info->IncrementBlockCount(coverage_array_slot_index); } - return isolate->heap()->undefined_value(); + return ReadOnlyRoots(isolate).undefined_value(); } +RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended) { + DCHECK_EQ(1, args.length()); + HandleScope scope(isolate); + CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); + isolate->OnAsyncFunctionStateChanged(promise, debug::kAsyncFunctionSuspended); + return ReadOnlyRoots(isolate).undefined_value(); +} + +RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionFinished) { + DCHECK_EQ(2, args.length()); + HandleScope scope(isolate); + CONVERT_BOOLEAN_ARG_CHECKED(has_suspend, 0); + CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1); + isolate->PopPromise(); + if (has_suspend) { + isolate->OnAsyncFunctionStateChanged(promise, + debug::kAsyncFunctionFinished); + } + return ReadOnlyRoots(isolate).undefined_value(); +} + +RUNTIME_FUNCTION(Runtime_LiveEditPatchScript) { + HandleScope scope(isolate); + DCHECK_EQ(2, args.length()); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, script_function, 0); + CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); + + Handle<Script> script(Script::cast(script_function->shared()->script()), + isolate); + v8::debug::LiveEditResult result; + LiveEdit::PatchScript(isolate, script, new_source, false, &result); + switch (result.status) { + case v8::debug::LiveEditResult::COMPILE_ERROR: + return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( + "LiveEdit failed: COMPILE_ERROR")); + case v8::debug::LiveEditResult::BLOCKED_BY_RUNNING_GENERATOR: + return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( + "LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR")); + case v8::debug::LiveEditResult::BLOCKED_BY_FUNCTION_ABOVE_BREAK_FRAME: + return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( + "LiveEdit failed: BLOCKED_BY_FUNCTION_ABOVE_BREAK_FRAME")); + case v8::debug::LiveEditResult:: + BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME: + return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( + "LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME")); + case v8::debug::LiveEditResult::BLOCKED_BY_ACTIVE_FUNCTION: + return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( + "LiveEdit failed: BLOCKED_BY_ACTIVE_FUNCTION")); + case v8::debug::LiveEditResult::BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME: + return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( + "LiveEdit failed: BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME")); + case v8::debug::LiveEditResult::FRAME_RESTART_IS_NOT_SUPPORTED: + return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( + "LiveEdit failed: FRAME_RESTART_IS_NOT_SUPPORTED")); + case v8::debug::LiveEditResult::OK: + return ReadOnlyRoots(isolate).undefined_value(); + } + return ReadOnlyRoots(isolate).undefined_value(); +} } // namespace internal } // namespace v8 |