--- /dev/null
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/accessors.h"
+#include "src/arguments.h"
+#include "src/debug.h"
+#include "src/deoptimizer.h"
+#include "src/isolate-inl.h"
+#include "src/parser.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+
+namespace v8 {
+namespace internal {
+
+RUNTIME_FUNCTION(Runtime_DebugBreak) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 0);
+ isolate->debug()->HandleDebugBreak();
+ return isolate->heap()->undefined_value();
+}
+
+
+// Helper functions for wrapping and unwrapping stack frame ids.
+static Smi* WrapFrameId(StackFrame::Id id) {
+ DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
+ return Smi::FromInt(id >> 2);
+}
+
+
+static StackFrame::Id UnwrapFrameId(int wrapped) {
+ return static_cast<StackFrame::Id>(wrapped << 2);
+}
+
+
+// Adds a JavaScript function as a debug event listener.
+// args[0]: debug event listener function to set or null or undefined for
+// clearing the event listener function
+// args[1]: object supplied during callback
+RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 2);
+ RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() ||
+ args[0]->IsNull());
+ CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
+ isolate->debug()->SetEventListener(callback, data);
+
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_Break) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 0);
+ isolate->stack_guard()->RequestDebugBreak();
+ return isolate->heap()->undefined_value();
+}
+
+
+static Handle<Object> DebugGetProperty(LookupIterator* it,
+ bool* has_caught = NULL) {
+ 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::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->GetReceiver(), it->name(), it->GetHolder<JSObject>(),
+ accessors);
+ Handle<Object> result;
+ if (!maybe_result.ToHandle(&result)) {
+ result = handle(it->isolate()->pending_exception(), it->isolate());
+ it->isolate()->clear_pending_exception();
+ if (has_caught != NULL) *has_caught = true;
+ }
+ return result;
+ }
+
+ case LookupIterator::DATA:
+ return it->GetDataValue();
+ }
+ }
+
+ return it->isolate()->factory()->undefined_value();
+}
+
+
+// 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(args.length() == 2);
+
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+
+ // 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 occour, 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;
+ 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,
+ Runtime::GetElementOrCharAt(isolate, obj, index));
+ details->set(0, *element_or_char);
+ details->set(1,
+ PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
+ return *isolate->factory()->NewJSArrayWithElements(details);
+ }
+
+ LookupIterator it(obj, name, LookupIterator::HIDDEN);
+ 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(NONE, NORMAL, 0)
+ : it.property_details();
+ details->set(1, d.AsSmi());
+ details->set(
+ 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
+ if (has_js_accessors) {
+ AccessorPair* accessors = AccessorPair::cast(*maybe_pair);
+ details->set(3, isolate->heap()->ToBoolean(has_caught));
+ details->set(4, accessors->GetComponent(ACCESSOR_GETTER));
+ details->set(5, accessors->GetComponent(ACCESSOR_SETTER));
+ }
+
+ return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
+ HandleScope scope(isolate);
+
+ DCHECK(args.length() == 2);
+
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+
+ LookupIterator it(obj, name);
+ return *DebugGetProperty(&it);
+}
+
+
+// Return the property type calculated from the property details.
+// args[0]: smi with property details.
+RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
+ return Smi::FromInt(static_cast<int>(details.type()));
+}
+
+
+// Return the property attribute calculated from the property details.
+// args[0]: smi with property details.
+RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
+ return Smi::FromInt(static_cast<int>(details.attributes()));
+}
+
+
+// Return the property insertion index calculated from the property details.
+// args[0]: smi with property details.
+RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
+ // TODO(verwaest): Depends on the type of details.
+ return Smi::FromInt(details.dictionary_index());
+}
+
+
+// Return property value from named interceptor.
+// args[0]: object
+// args[1]: property name
+RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ RUNTIME_ASSERT(obj->HasNamedInterceptor());
+ CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+ JSObject::GetProperty(obj, name));
+ return *result;
+}
+
+
+// Return element value from indexed interceptor.
+// args[0]: object
+// args[1]: index
+RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ RUNTIME_ASSERT(obj->HasIndexedInterceptor());
+ CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+ return isolate->heap()->true_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFrameCount) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(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::FromInt(0);
+ }
+
+ for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
+ List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+ it.frame()->Summarize(&frames);
+ for (int i = frames.length() - 1; i >= 0; i--) {
+ // Omit functions from native scripts.
+ if (!frames[i].function()->IsFromNativeScript()) n++;
+ }
+ }
+ return Smi::FromInt(n);
+}
+
+
+class FrameInspector {
+ public:
+ FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index,
+ Isolate* isolate)
+ : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
+ // Calculate the deoptimized frame.
+ if (frame->is_optimized()) {
+ deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
+ frame, inlined_jsframe_index, isolate);
+ }
+ has_adapted_arguments_ = frame_->has_adapted_arguments();
+ is_bottommost_ = inlined_jsframe_index == 0;
+ is_optimized_ = frame_->is_optimized();
+ }
+
+ ~FrameInspector() {
+ // Get rid of the calculated deoptimized frame if any.
+ if (deoptimized_frame_ != NULL) {
+ Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
+ }
+ }
+
+ int GetParametersCount() {
+ return is_optimized_ ? deoptimized_frame_->parameters_count()
+ : frame_->ComputeParametersCount();
+ }
+ int expression_count() { return deoptimized_frame_->expression_count(); }
+ Object* GetFunction() {
+ return is_optimized_ ? deoptimized_frame_->GetFunction()
+ : frame_->function();
+ }
+ Object* GetParameter(int index) {
+ return is_optimized_ ? deoptimized_frame_->GetParameter(index)
+ : frame_->GetParameter(index);
+ }
+ Object* GetExpression(int index) {
+ return is_optimized_ ? deoptimized_frame_->GetExpression(index)
+ : frame_->GetExpression(index);
+ }
+ int GetSourcePosition() {
+ return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
+ : frame_->LookupCode()->SourcePosition(frame_->pc());
+ }
+ bool IsConstructor() {
+ return is_optimized_ && !is_bottommost_
+ ? deoptimized_frame_->HasConstructStub()
+ : frame_->IsConstructor();
+ }
+ Object* GetContext() {
+ return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
+ }
+
+ // To inspect all the provided arguments the frame might need to be
+ // replaced with the arguments frame.
+ void SetArgumentsFrame(JavaScriptFrame* frame) {
+ DCHECK(has_adapted_arguments_);
+ frame_ = frame;
+ is_optimized_ = frame_->is_optimized();
+ DCHECK(!is_optimized_);
+ }
+
+ private:
+ JavaScriptFrame* frame_;
+ DeoptimizedFrameInfo* deoptimized_frame_;
+ Isolate* isolate_;
+ bool is_optimized_;
+ bool is_bottommost_;
+ bool has_adapted_arguments_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameInspector);
+};
+
+
+static const int kFrameDetailsFrameIdIndex = 0;
+static const int kFrameDetailsReceiverIndex = 1;
+static const int kFrameDetailsFunctionIndex = 2;
+static const int kFrameDetailsArgumentCountIndex = 3;
+static const int kFrameDetailsLocalCountIndex = 4;
+static const int kFrameDetailsSourcePositionIndex = 5;
+static const int kFrameDetailsConstructCallIndex = 6;
+static const int kFrameDetailsAtReturnIndex = 7;
+static const int kFrameDetailsFlagsIndex = 8;
+static const int kFrameDetailsFirstDynamicIndex = 9;
+
+
+static SaveContext* FindSavedContextForFrame(Isolate* isolate,
+ JavaScriptFrame* frame) {
+ SaveContext* save = isolate->save_context();
+ while (save != NULL && !save->IsBelowFrame(frame)) {
+ save = save->prev();
+ }
+ DCHECK(save != NULL);
+ return save;
+}
+
+
+// Advances the iterator to the frame that matches the index and returns the
+// inlined frame index, or -1 if not found. Skips native JS functions.
+int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) {
+ int count = -1;
+ for (; !it->done(); it->Advance()) {
+ List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
+ it->frame()->Summarize(&frames);
+ for (int i = frames.length() - 1; i >= 0; i--) {
+ // Omit functions from native scripts.
+ if (frames[i].function()->IsFromNativeScript()) continue;
+ if (++count == index) return i;
+ }
+ }
+ return -1;
+}
+
+
+// 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: Argument count
+// 4: Local count
+// 5: Source position
+// 6: Constructor call
+// 7: Is at return
+// 8: Flags
+// Arguments name, value
+// Locals name, value
+// Return value if any
+RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(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();
+ }
+
+ JavaScriptFrameIterator it(isolate, id);
+ // Inlined frame index in optimized frame, starting from outer function.
+ int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index);
+ if (inlined_jsframe_index == -1) return heap->undefined_value();
+
+ FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
+ bool is_optimized = it.frame()->is_optimized();
+
+ // Traverse the saved contexts chain to find the active context for the
+ // selected frame.
+ SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
+
+ // Get the frame id.
+ Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
+
+ // Find source position in unoptimized code.
+ int position = frame_inspector.GetSourcePosition();
+
+ // Check for constructor frame.
+ bool constructor = frame_inspector.IsConstructor();
+
+ // Get scope info and read from it for local variable information.
+ Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
+ 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.
+ int local_count = scope_info->LocalCount();
+ for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
+ // Hide compiler-introduced temporary variables, whether on the stack or on
+ // the context.
+ if (scope_info->LocalIsSynthetic(slot)) local_count--;
+ }
+
+ Handle<FixedArray> locals =
+ isolate->factory()->NewFixedArray(local_count * 2);
+
+ // Fill in the values of the locals.
+ int local = 0;
+ int i = 0;
+ for (; i < scope_info->StackLocalCount(); ++i) {
+ // Use the value from the stack.
+ if (scope_info->LocalIsSynthetic(i)) continue;
+ locals->set(local * 2, scope_info->LocalName(i));
+ locals->set(local * 2 + 1, frame_inspector.GetExpression(i));
+ local++;
+ }
+ if (local < local_count) {
+ // Get the context containing declarations.
+ Handle<Context> context(
+ Context::cast(frame_inspector.GetContext())->declaration_context());
+ for (; i < scope_info->LocalCount(); ++i) {
+ if (scope_info->LocalIsSynthetic(i)) continue;
+ Handle<String> name(scope_info->LocalName(i));
+ VariableMode mode;
+ InitializationFlag init_flag;
+ MaybeAssignedFlag maybe_assigned_flag;
+ locals->set(local * 2, *name);
+ int context_slot_index = ScopeInfo::ContextSlotIndex(
+ scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
+ Object* value = context->get(context_slot_index);
+ locals->set(local * 2 + 1, value);
+ local++;
+ }
+ }
+
+ // 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.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) {
+ StackFrameIterator it2(isolate);
+ Address internal_frame_sp = NULL;
+ while (!it2.done()) {
+ if (it2.frame()->is_internal()) {
+ internal_frame_sp = it2.frame()->sp();
+ } else {
+ if (it2.frame()->is_java_script()) {
+ if (it2.frame()->id() == it.frame()->id()) {
+ // The internal frame just before the JavaScript frame contains the
+ // value to return on top. A debug break at return will create an
+ // internal frame to store the return value (eax/rax/r0) before
+ // entering the debug break exit frame.
+ if (internal_frame_sp != NULL) {
+ return_value =
+ Handle<Object>(Memory::Object_at(internal_frame_sp), isolate);
+ break;
+ }
+ }
+ }
+
+ // Indicate that the previous frame was not an internal frame.
+ internal_frame_sp = NULL;
+ }
+ it2.Advance();
+ }
+ }
+
+ // 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_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
+ it.AdvanceToArgumentsFrame();
+ 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 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 != RelocInfo::kNoPosition) {
+ 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_jsframe_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 (int i = 0; i < local_count * 2; i++) {
+ details->set(details_index++, locals->get(i));
+ }
+
+ // Add the value being returned.
+ if (at_return) {
+ details->set(details_index++, *return_value);
+ }
+
+ // Add the receiver (same as in function frame).
+ // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
+ // THE FRAME ITERATOR TO WRAP THE RECEIVER.
+ Handle<Object> receiver(it.frame()->receiver(), isolate);
+ if (!receiver->IsJSObject() && shared->strict_mode() == SLOPPY &&
+ !function->IsBuiltin()) {
+ // If the receiver is not a JSObject and the function is not a
+ // builtin or strict-mode we have hit an optimization where a
+ // value object is not converted into a wrapped JS objects. To
+ // hide this optimization from the debugger, we wrap the receiver
+ // by creating correct wrapper object based on the calling frame's
+ // native context.
+ it.Advance();
+ if (receiver->IsUndefined()) {
+ receiver = handle(function->global_proxy());
+ } else {
+ Context* context = Context::cast(it.frame()->context());
+ Handle<Context> native_context(Context::cast(context->native_context()));
+ if (!Object::ToObject(isolate, receiver, native_context)
+ .ToHandle(&receiver)) {
+ // This only happens if the receiver is forcibly set in %_CallFunction.
+ return heap->undefined_value();
+ }
+ }
+ }
+ details->set(kFrameDetailsReceiverIndex, *receiver);
+
+ DCHECK_EQ(details_size, details_index);
+ return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
+ Handle<String> parameter_name) {
+ VariableMode mode;
+ InitializationFlag init_flag;
+ MaybeAssignedFlag maybe_assigned_flag;
+ return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
+ &maybe_assigned_flag) != -1;
+}
+
+
+// Create a plain JSObject which materializes the local scope for the specified
+// frame.
+MUST_USE_RESULT
+static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector(
+ Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
+ FrameInspector* frame_inspector) {
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<ScopeInfo> scope_info(shared->scope_info());
+
+ // First fill all parameters.
+ for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+ // Do not materialize the parameter if it is shadowed by a context local.
+ Handle<String> name(scope_info->ParameterName(i));
+ if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
+
+ HandleScope scope(isolate);
+ Handle<Object> value(i < frame_inspector->GetParametersCount()
+ ? frame_inspector->GetParameter(i)
+ : isolate->heap()->undefined_value(),
+ isolate);
+ DCHECK(!value->IsTheHole());
+
+ RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
+ isolate, target, name, value, SLOPPY),
+ JSObject);
+ }
+
+ // Second fill all stack locals.
+ for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+ if (scope_info->LocalIsSynthetic(i)) continue;
+ Handle<String> name(scope_info->StackLocalName(i));
+ Handle<Object> value(frame_inspector->GetExpression(i), isolate);
+ if (value->IsTheHole()) continue;
+
+ RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
+ isolate, target, name, value, SLOPPY),
+ JSObject);
+ }
+
+ return target;
+}
+
+
+static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
+ Handle<JSObject> target,
+ Handle<JSFunction> function,
+ JavaScriptFrame* frame,
+ int inlined_jsframe_index) {
+ if (inlined_jsframe_index != 0 || frame->is_optimized()) {
+ // Optimized frames are not supported.
+ // TODO(yangguo): make sure all code deoptimized when debugger is active
+ // and assert that this cannot happen.
+ return;
+ }
+
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<ScopeInfo> scope_info(shared->scope_info());
+
+ // Parameters.
+ for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+ // Shadowed parameters were not materialized.
+ Handle<String> name(scope_info->ParameterName(i));
+ if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
+
+ DCHECK(!frame->GetParameter(i)->IsTheHole());
+ HandleScope scope(isolate);
+ Handle<Object> value =
+ Object::GetPropertyOrElement(target, name).ToHandleChecked();
+ frame->SetParameterValue(i, *value);
+ }
+
+ // Stack locals.
+ for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+ if (scope_info->LocalIsSynthetic(i)) continue;
+ if (frame->GetExpression(i)->IsTheHole()) continue;
+ HandleScope scope(isolate);
+ Handle<Object> value = Object::GetPropertyOrElement(
+ target, handle(scope_info->StackLocalName(i),
+ isolate)).ToHandleChecked();
+ frame->SetExpression(i, *value);
+ }
+}
+
+
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
+ Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
+ JavaScriptFrame* frame) {
+ HandleScope scope(isolate);
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<ScopeInfo> scope_info(shared->scope_info());
+
+ if (!scope_info->HasContext()) return target;
+
+ // Third fill all context locals.
+ Handle<Context> frame_context(Context::cast(frame->context()));
+ Handle<Context> function_context(frame_context->declaration_context());
+ if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context,
+ target)) {
+ return MaybeHandle<JSObject>();
+ }
+
+ // Finally copy any properties from the function context extension.
+ // These will be variables introduced by eval.
+ if (function_context->closure() == *function) {
+ if (function_context->has_extension() &&
+ !function_context->IsNativeContext()) {
+ Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+ Handle<FixedArray> keys;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
+ JSObject);
+
+ for (int i = 0; i < keys->length(); i++) {
+ // Names of variables introduced by eval are strings.
+ DCHECK(keys->get(i)->IsString());
+ Handle<String> key(String::cast(keys->get(i)));
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
+ RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
+ isolate, target, key, value, SLOPPY),
+ JSObject);
+ }
+ }
+ }
+
+ return target;
+}
+
+
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
+ Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) {
+ FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
+ Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
+
+ Handle<JSObject> local_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, local_scope,
+ MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function,
+ &frame_inspector),
+ JSObject);
+
+ return MaterializeLocalContext(isolate, local_scope, function, frame);
+}
+
+
+// Set the context local variable value.
+static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info,
+ Handle<Context> context,
+ Handle<String> variable_name,
+ Handle<Object> new_value) {
+ for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
+ Handle<String> next_name(scope_info->ContextLocalName(i));
+ if (String::Equals(variable_name, next_name)) {
+ VariableMode mode;
+ InitializationFlag init_flag;
+ MaybeAssignedFlag maybe_assigned_flag;
+ int context_index = ScopeInfo::ContextSlotIndex(
+ scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
+ context->set(context_index, *new_value);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
+ int inlined_jsframe_index,
+ Handle<String> variable_name,
+ Handle<Object> new_value) {
+ if (inlined_jsframe_index != 0 || frame->is_optimized()) {
+ // Optimized frames are not supported.
+ return false;
+ }
+
+ Handle<JSFunction> function(frame->function());
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<ScopeInfo> scope_info(shared->scope_info());
+
+ bool default_result = false;
+
+ // Parameters.
+ for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+ HandleScope scope(isolate);
+ if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
+ frame->SetParameterValue(i, *new_value);
+ // Argument might be shadowed in heap context, don't stop here.
+ default_result = true;
+ }
+ }
+
+ // Stack locals.
+ for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+ HandleScope scope(isolate);
+ if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
+ frame->SetExpression(i, *new_value);
+ return true;
+ }
+ }
+
+ if (scope_info->HasContext()) {
+ // Context locals.
+ Handle<Context> frame_context(Context::cast(frame->context()));
+ Handle<Context> function_context(frame_context->declaration_context());
+ if (SetContextLocalValue(isolate, scope_info, function_context,
+ variable_name, new_value)) {
+ return true;
+ }
+
+ // Function context extension. These are variables introduced by eval.
+ if (function_context->closure() == *function) {
+ if (function_context->has_extension() &&
+ !function_context->IsNativeContext()) {
+ Handle<JSObject> ext(JSObject::cast(function_context->extension()));
+
+ Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
+ DCHECK(maybe.has_value);
+ if (maybe.value) {
+ // We don't expect this to do anything except replacing
+ // property value.
+ Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
+ SLOPPY).Assert();
+ return true;
+ }
+ }
+ }
+ }
+
+ return default_result;
+}
+
+
+// Create a plain JSObject which materializes the closure content for the
+// context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure(
+ Isolate* isolate, Handle<Context> context) {
+ DCHECK(context->IsFunctionContext());
+
+ Handle<SharedFunctionInfo> shared(context->closure()->shared());
+ Handle<ScopeInfo> scope_info(shared->scope_info());
+
+ // Allocate and initialize a JSObject with all the content of this function
+ // closure.
+ Handle<JSObject> closure_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+
+ // Fill all context locals to the context extension.
+ if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
+ closure_scope)) {
+ return MaybeHandle<JSObject>();
+ }
+
+ // Finally copy any properties from the function context extension. This will
+ // be variables introduced by eval.
+ if (context->has_extension()) {
+ Handle<JSObject> ext(JSObject::cast(context->extension()));
+ Handle<FixedArray> keys;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
+ JSObject);
+
+ for (int i = 0; i < keys->length(); i++) {
+ HandleScope scope(isolate);
+ // Names of variables introduced by eval are strings.
+ DCHECK(keys->get(i)->IsString());
+ Handle<String> key(String::cast(keys->get(i)));
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
+ RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
+ closure_scope, key, value, NONE),
+ JSObject);
+ }
+ }
+
+ return closure_scope;
+}
+
+
+// This method copies structure of MaterializeClosure method above.
+static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
+ Handle<String> variable_name,
+ Handle<Object> new_value) {
+ DCHECK(context->IsFunctionContext());
+
+ Handle<SharedFunctionInfo> shared(context->closure()->shared());
+ Handle<ScopeInfo> scope_info(shared->scope_info());
+
+ // Context locals to the context extension.
+ if (SetContextLocalValue(isolate, scope_info, context, variable_name,
+ new_value)) {
+ return true;
+ }
+
+ // Properties from the function context extension. This will
+ // be variables introduced by eval.
+ if (context->has_extension()) {
+ Handle<JSObject> ext(JSObject::cast(context->extension()));
+ Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
+ DCHECK(maybe.has_value);
+ if (maybe.value) {
+ // We don't expect this to do anything except replacing property value.
+ Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE)
+ .Assert();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+// Create a plain JSObject which materializes the scope for the specified
+// catch context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope(
+ Isolate* isolate, Handle<Context> context) {
+ DCHECK(context->IsCatchContext());
+ Handle<String> name(String::cast(context->extension()));
+ Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
+ isolate);
+ Handle<JSObject> catch_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+ RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
+ catch_scope, name, thrown_object, NONE),
+ JSObject);
+ return catch_scope;
+}
+
+
+static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context,
+ Handle<String> variable_name,
+ Handle<Object> new_value) {
+ DCHECK(context->IsCatchContext());
+ Handle<String> name(String::cast(context->extension()));
+ if (!String::Equals(name, variable_name)) {
+ return false;
+ }
+ context->set(Context::THROWN_OBJECT_INDEX, *new_value);
+ return true;
+}
+
+
+// Create a plain JSObject which materializes the block scope for the specified
+// block context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope(
+ Isolate* isolate, Handle<Context> context) {
+ DCHECK(context->IsBlockContext());
+ Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+
+ // Allocate and initialize a JSObject with all the arguments, stack locals
+ // heap locals and extension properties of the debugged function.
+ Handle<JSObject> block_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+
+ // Fill all context locals.
+ if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
+ block_scope)) {
+ return MaybeHandle<JSObject>();
+ }
+
+ return block_scope;
+}
+
+
+// Create a plain JSObject which materializes the module scope for the specified
+// module context.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
+ Isolate* isolate, Handle<Context> context) {
+ DCHECK(context->IsModuleContext());
+ Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+
+ // Allocate and initialize a JSObject with all the members of the debugged
+ // module.
+ Handle<JSObject> module_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+
+ // Fill all context locals.
+ if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
+ module_scope)) {
+ return MaybeHandle<JSObject>();
+ }
+
+ return module_scope;
+}
+
+
+// Iterate over the actual scopes visible from a stack frame or from a closure.
+// The iteration proceeds from the innermost visible nested scope outwards.
+// All scopes are backed by an actual context except the local scope,
+// which is inserted "artificially" in the context chain.
+class ScopeIterator {
+ public:
+ enum ScopeType {
+ ScopeTypeGlobal = 0,
+ ScopeTypeLocal,
+ ScopeTypeWith,
+ ScopeTypeClosure,
+ ScopeTypeCatch,
+ ScopeTypeBlock,
+ ScopeTypeModule
+ };
+
+ ScopeIterator(Isolate* isolate, JavaScriptFrame* frame,
+ int inlined_jsframe_index, bool ignore_nested_scopes = false)
+ : isolate_(isolate),
+ frame_(frame),
+ inlined_jsframe_index_(inlined_jsframe_index),
+ function_(frame->function()),
+ context_(Context::cast(frame->context())),
+ nested_scope_chain_(4),
+ failed_(false) {
+ // Catch the case when the debugger stops in an internal function.
+ Handle<SharedFunctionInfo> shared_info(function_->shared());
+ Handle<ScopeInfo> scope_info(shared_info->scope_info());
+ if (shared_info->script() == isolate->heap()->undefined_value()) {
+ while (context_->closure() == *function_) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ return;
+ }
+
+ // Get the debug info (create it if it does not exist).
+ if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
+ // Return if ensuring debug info failed.
+ return;
+ }
+
+ // Currently it takes too much time to find nested scopes due to script
+ // parsing. Sometimes we want to run the ScopeIterator as fast as possible
+ // (for example, while collecting async call stacks on every
+ // addEventListener call), even if we drop some nested scopes.
+ // Later we may optimize getting the nested scopes (cache the result?)
+ // and include nested scopes into the "fast" iteration case as well.
+ if (!ignore_nested_scopes) {
+ Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
+
+ // Find the break point where execution has stopped.
+ BreakLocationIterator break_location_iterator(debug_info,
+ ALL_BREAK_LOCATIONS);
+ // pc points to the instruction after the current one, possibly a break
+ // location as well. So the "- 1" to exclude it from the search.
+ break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
+
+ // Within the return sequence at the moment it is not possible to
+ // get a source position which is consistent with the current scope chain.
+ // Thus all nested with, catch and block contexts are skipped and we only
+ // provide the function scope.
+ ignore_nested_scopes = break_location_iterator.IsExit();
+ }
+
+ if (ignore_nested_scopes) {
+ if (scope_info->HasContext()) {
+ context_ = Handle<Context>(context_->declaration_context(), isolate_);
+ } else {
+ while (context_->closure() == *function_) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ }
+ if (scope_info->scope_type() == FUNCTION_SCOPE) {
+ nested_scope_chain_.Add(scope_info);
+ }
+ } else {
+ // Reparse the code and analyze the scopes.
+ Handle<Script> script(Script::cast(shared_info->script()));
+ Scope* scope = NULL;
+
+ // Check whether we are in global, eval or function code.
+ Handle<ScopeInfo> scope_info(shared_info->scope_info());
+ if (scope_info->scope_type() != FUNCTION_SCOPE) {
+ // Global or eval code.
+ CompilationInfoWithZone info(script);
+ if (scope_info->scope_type() == GLOBAL_SCOPE) {
+ info.MarkAsGlobal();
+ } else {
+ DCHECK(scope_info->scope_type() == EVAL_SCOPE);
+ info.MarkAsEval();
+ info.SetContext(Handle<Context>(function_->context()));
+ }
+ if (Parser::Parse(&info) && Scope::Analyze(&info)) {
+ scope = info.function()->scope();
+ }
+ RetrieveScopeChain(scope, shared_info);
+ } else {
+ // Function code
+ CompilationInfoWithZone info(shared_info);
+ if (Parser::Parse(&info) && Scope::Analyze(&info)) {
+ scope = info.function()->scope();
+ }
+ RetrieveScopeChain(scope, shared_info);
+ }
+ }
+ }
+
+ ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
+ : isolate_(isolate),
+ frame_(NULL),
+ inlined_jsframe_index_(0),
+ function_(function),
+ context_(function->context()),
+ failed_(false) {
+ if (function->IsBuiltin()) {
+ context_ = Handle<Context>();
+ }
+ }
+
+ // More scopes?
+ bool Done() {
+ DCHECK(!failed_);
+ return context_.is_null();
+ }
+
+ bool Failed() { return failed_; }
+
+ // Move to the next scope.
+ void Next() {
+ DCHECK(!failed_);
+ ScopeType scope_type = Type();
+ if (scope_type == ScopeTypeGlobal) {
+ // The global scope is always the last in the chain.
+ DCHECK(context_->IsNativeContext());
+ context_ = Handle<Context>();
+ return;
+ }
+ if (nested_scope_chain_.is_empty()) {
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ } else {
+ if (nested_scope_chain_.last()->HasContext()) {
+ DCHECK(context_->previous() != NULL);
+ context_ = Handle<Context>(context_->previous(), isolate_);
+ }
+ nested_scope_chain_.RemoveLast();
+ }
+ }
+
+ // Return the type of the current scope.
+ ScopeType Type() {
+ DCHECK(!failed_);
+ if (!nested_scope_chain_.is_empty()) {
+ Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
+ switch (scope_info->scope_type()) {
+ case FUNCTION_SCOPE:
+ DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
+ return ScopeTypeLocal;
+ case MODULE_SCOPE:
+ DCHECK(context_->IsModuleContext());
+ return ScopeTypeModule;
+ case GLOBAL_SCOPE:
+ DCHECK(context_->IsNativeContext());
+ return ScopeTypeGlobal;
+ case WITH_SCOPE:
+ DCHECK(context_->IsWithContext());
+ return ScopeTypeWith;
+ case CATCH_SCOPE:
+ DCHECK(context_->IsCatchContext());
+ return ScopeTypeCatch;
+ case BLOCK_SCOPE:
+ DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
+ return ScopeTypeBlock;
+ case EVAL_SCOPE:
+ UNREACHABLE();
+ }
+ }
+ if (context_->IsNativeContext()) {
+ DCHECK(context_->global_object()->IsGlobalObject());
+ return ScopeTypeGlobal;
+ }
+ if (context_->IsFunctionContext()) {
+ return ScopeTypeClosure;
+ }
+ if (context_->IsCatchContext()) {
+ return ScopeTypeCatch;
+ }
+ if (context_->IsBlockContext()) {
+ return ScopeTypeBlock;
+ }
+ if (context_->IsModuleContext()) {
+ return ScopeTypeModule;
+ }
+ DCHECK(context_->IsWithContext());
+ return ScopeTypeWith;
+ }
+
+ // Return the JavaScript object with the content of the current scope.
+ MaybeHandle<JSObject> ScopeObject() {
+ DCHECK(!failed_);
+ switch (Type()) {
+ case ScopeIterator::ScopeTypeGlobal:
+ return Handle<JSObject>(CurrentContext()->global_object());
+ case ScopeIterator::ScopeTypeLocal:
+ // Materialize the content of the local scope into a JSObject.
+ DCHECK(nested_scope_chain_.length() == 1);
+ return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
+ case ScopeIterator::ScopeTypeWith:
+ // Return the with object.
+ return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
+ case ScopeIterator::ScopeTypeCatch:
+ return MaterializeCatchScope(isolate_, CurrentContext());
+ case ScopeIterator::ScopeTypeClosure:
+ // Materialize the content of the closure scope into a JSObject.
+ return MaterializeClosure(isolate_, CurrentContext());
+ case ScopeIterator::ScopeTypeBlock:
+ return MaterializeBlockScope(isolate_, CurrentContext());
+ case ScopeIterator::ScopeTypeModule:
+ return MaterializeModuleScope(isolate_, CurrentContext());
+ }
+ UNREACHABLE();
+ return Handle<JSObject>();
+ }
+
+ bool SetVariableValue(Handle<String> variable_name,
+ Handle<Object> new_value) {
+ DCHECK(!failed_);
+ switch (Type()) {
+ case ScopeIterator::ScopeTypeGlobal:
+ break;
+ case ScopeIterator::ScopeTypeLocal:
+ return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
+ variable_name, new_value);
+ case ScopeIterator::ScopeTypeWith:
+ break;
+ case ScopeIterator::ScopeTypeCatch:
+ return SetCatchVariableValue(isolate_, CurrentContext(), variable_name,
+ new_value);
+ case ScopeIterator::ScopeTypeClosure:
+ return SetClosureVariableValue(isolate_, CurrentContext(),
+ variable_name, new_value);
+ case ScopeIterator::ScopeTypeBlock:
+ // TODO(2399): should we implement it?
+ break;
+ case ScopeIterator::ScopeTypeModule:
+ // TODO(2399): should we implement it?
+ break;
+ }
+ return false;
+ }
+
+ Handle<ScopeInfo> CurrentScopeInfo() {
+ DCHECK(!failed_);
+ if (!nested_scope_chain_.is_empty()) {
+ return nested_scope_chain_.last();
+ } else if (context_->IsBlockContext()) {
+ return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
+ } else if (context_->IsFunctionContext()) {
+ return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
+ }
+ return Handle<ScopeInfo>::null();
+ }
+
+ // Return the context for this scope. For the local context there might not
+ // be an actual context.
+ Handle<Context> CurrentContext() {
+ DCHECK(!failed_);
+ if (Type() == ScopeTypeGlobal || nested_scope_chain_.is_empty()) {
+ return context_;
+ } else if (nested_scope_chain_.last()->HasContext()) {
+ return context_;
+ } else {
+ return Handle<Context>();
+ }
+ }
+
+#ifdef DEBUG
+ // Debug print of the content of the current scope.
+ void DebugPrint() {
+ OFStream os(stdout);
+ DCHECK(!failed_);
+ switch (Type()) {
+ case ScopeIterator::ScopeTypeGlobal:
+ os << "Global:\n";
+ CurrentContext()->Print(os);
+ break;
+
+ case ScopeIterator::ScopeTypeLocal: {
+ os << "Local:\n";
+ function_->shared()->scope_info()->Print();
+ if (!CurrentContext().is_null()) {
+ CurrentContext()->Print(os);
+ if (CurrentContext()->has_extension()) {
+ Handle<Object> extension(CurrentContext()->extension(), isolate_);
+ if (extension->IsJSContextExtensionObject()) {
+ extension->Print(os);
+ }
+ }
+ }
+ break;
+ }
+
+ case ScopeIterator::ScopeTypeWith:
+ os << "With:\n";
+ CurrentContext()->extension()->Print(os);
+ break;
+
+ case ScopeIterator::ScopeTypeCatch:
+ os << "Catch:\n";
+ CurrentContext()->extension()->Print(os);
+ CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
+ break;
+
+ case ScopeIterator::ScopeTypeClosure:
+ os << "Closure:\n";
+ CurrentContext()->Print(os);
+ if (CurrentContext()->has_extension()) {
+ Handle<Object> extension(CurrentContext()->extension(), isolate_);
+ if (extension->IsJSContextExtensionObject()) {
+ extension->Print(os);
+ }
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+ PrintF("\n");
+ }
+#endif
+
+ private:
+ Isolate* isolate_;
+ JavaScriptFrame* frame_;
+ int inlined_jsframe_index_;
+ Handle<JSFunction> function_;
+ Handle<Context> context_;
+ List<Handle<ScopeInfo> > nested_scope_chain_;
+ bool failed_;
+
+ void RetrieveScopeChain(Scope* scope,
+ Handle<SharedFunctionInfo> shared_info) {
+ if (scope != NULL) {
+ int source_position = shared_info->code()->SourcePosition(frame_->pc());
+ scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
+ } else {
+ // A failed reparse indicates that the preparser has diverged from the
+ // parser or that the preparse data given to the initial parse has been
+ // faulty. We fail in debug mode but in release mode we only provide the
+ // information we get from the context chain but nothing about
+ // completely stack allocated scopes or stack allocated locals.
+ // Or it could be due to stack overflow.
+ DCHECK(isolate_->has_pending_exception());
+ failed_ = true;
+ }
+ }
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
+};
+
+
+RUNTIME_FUNCTION(Runtime_GetScopeCount) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+ CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+
+ // Get the frame where the debugging is performed.
+ StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ JavaScriptFrameIterator it(isolate, id);
+ JavaScriptFrame* frame = it.frame();
+
+ // Count the visible scopes.
+ int n = 0;
+ for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
+ n++;
+ }
+
+ return Smi::FromInt(n);
+}
+
+
+// Returns the list of step-in positions (text offset) in a function of the
+// stack frame in a range from the current debug break position to the end
+// of the corresponding statement.
+RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+ CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+
+ // Get the frame where the debugging is performed.
+ StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ JavaScriptFrameIterator frame_it(isolate, id);
+ RUNTIME_ASSERT(!frame_it.done());
+
+ JavaScriptFrame* frame = frame_it.frame();
+
+ Handle<JSFunction> fun = Handle<JSFunction>(frame->function());
+ Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
+
+ if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
+ return isolate->heap()->undefined_value();
+ }
+
+ Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
+
+ int len = 0;
+ Handle<JSArray> array(isolate->factory()->NewJSArray(10));
+ // Find the break point where execution has stopped.
+ BreakLocationIterator break_location_iterator(debug_info,
+ ALL_BREAK_LOCATIONS);
+
+ break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
+ int current_statement_pos = break_location_iterator.statement_position();
+
+ while (!break_location_iterator.Done()) {
+ bool accept;
+ if (break_location_iterator.pc() > frame->pc()) {
+ accept = true;
+ } else {
+ StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
+ // The break point is near our pc. Could be a step-in possibility,
+ // that is currently taken by active debugger call.
+ if (break_frame_id == StackFrame::NO_ID) {
+ // We are not stepping.
+ accept = false;
+ } else {
+ JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
+ // If our frame is a top frame and we are stepping, we can do step-in
+ // at this place.
+ accept = additional_frame_it.frame()->id() == id;
+ }
+ }
+ if (accept) {
+ if (break_location_iterator.IsStepInLocation(isolate)) {
+ Smi* position_value = Smi::FromInt(break_location_iterator.position());
+ RETURN_FAILURE_ON_EXCEPTION(
+ isolate, JSObject::SetElement(
+ array, len, Handle<Object>(position_value, isolate),
+ NONE, SLOPPY));
+ len++;
+ }
+ }
+ // Advance iterator.
+ break_location_iterator.Next();
+ if (current_statement_pos != break_location_iterator.statement_position()) {
+ break;
+ }
+ }
+ return *array;
+}
+
+
+static const int kScopeDetailsTypeIndex = 0;
+static const int kScopeDetailsObjectIndex = 1;
+static const int kScopeDetailsSize = 2;
+
+
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
+ Isolate* isolate, ScopeIterator* it) {
+ // Calculate the size of the result.
+ int details_size = kScopeDetailsSize;
+ Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
+
+ // Fill in scope details.
+ details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
+ Handle<JSObject> scope_object;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(),
+ JSObject);
+ details->set(kScopeDetailsObjectIndex, *scope_object);
+
+ return isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+// 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(args.length() == 4);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(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 = UnwrapFrameId(wrapped_id);
+ JavaScriptFrameIterator frame_it(isolate, id);
+ JavaScriptFrame* frame = frame_it.frame();
+
+ // Find the requested scope.
+ int n = 0;
+ ScopeIterator it(isolate, frame, inlined_jsframe_index);
+ for (; !it.Done() && n < index; it.Next()) {
+ n++;
+ }
+ if (it.Done()) {
+ return isolate->heap()->undefined_value();
+ }
+ Handle<JSObject> details;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
+ MaterializeScopeDetails(isolate, &it));
+ return *details;
+}
+
+
+// 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]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+ CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
+ CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
+
+ bool ignore_nested_scopes = false;
+ if (args.length() == 4) {
+ CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
+ ignore_nested_scopes = flag;
+ }
+
+ // Get the frame where the debugging is performed.
+ StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ JavaScriptFrameIterator frame_it(isolate, id);
+ JavaScriptFrame* frame = frame_it.frame();
+
+ List<Handle<JSObject> > result(4);
+ ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
+ for (; !it.Done(); it.Next()) {
+ Handle<JSObject> details;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
+ MaterializeScopeDetails(isolate, &it));
+ result.Add(details);
+ }
+
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
+ for (int i = 0; i < result.length(); ++i) {
+ array->set(i, *result[i]);
+ }
+ return *isolate->factory()->NewJSArrayWithElements(array);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+
+ // Check arguments.
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+
+ // Count the visible scopes.
+ int n = 0;
+ for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
+ n++;
+ }
+
+ return Smi::FromInt(n);
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+
+ // 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();
+ }
+
+ Handle<JSObject> details;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
+ MaterializeScopeDetails(isolate, &it));
+ return *details;
+}
+
+
+static bool SetScopeVariableValue(ScopeIterator* it, int index,
+ Handle<String> variable_name,
+ Handle<Object> new_value) {
+ for (int n = 0; !it->Done() && n < index; it->Next()) {
+ n++;
+ }
+ if (it->Done()) {
+ return false;
+ }
+ 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
+//
+// Return true if success and false otherwise
+RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 6);
+
+ // 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]);
+ RUNTIME_ASSERT(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 = UnwrapFrameId(wrapped_id);
+ JavaScriptFrameIterator frame_it(isolate, id);
+ JavaScriptFrame* frame = frame_it.frame();
+
+ ScopeIterator it(isolate, frame, inlined_jsframe_index);
+ res = SetScopeVariableValue(&it, index, variable_name, new_value);
+ } else {
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+ ScopeIterator it(isolate, fun);
+ res = SetScopeVariableValue(&it, index, variable_name, new_value);
+ }
+
+ return isolate->heap()->ToBoolean(res);
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 0);
+
+#ifdef DEBUG
+ // Print the scopes for the top frame.
+ StackFrameLocator locator(isolate);
+ JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
+ for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
+ it.DebugPrint();
+ }
+#endif
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetThreadCount) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+ // Count all archived V8 threads.
+ int n = 0;
+ for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
+ thread != NULL; thread = thread->Next()) {
+ n++;
+ }
+
+ // Total number of threads is current thread and archived threads.
+ return Smi::FromInt(n + 1);
+}
+
+
+static const int kThreadDetailsCurrentThreadIndex = 0;
+static const int kThreadDetailsThreadIdIndex = 1;
+static const int kThreadDetailsSize = 2;
+
+// Return an array with thread details
+// args[0]: number: break id
+// args[1]: number: thread index
+//
+// The array returned contains the following information:
+// 0: Is current thread?
+// 1: Thread id
+RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+ CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
+
+ // Allocate array for result.
+ Handle<FixedArray> details =
+ isolate->factory()->NewFixedArray(kThreadDetailsSize);
+
+ // Thread index 0 is current thread.
+ if (index == 0) {
+ // Fill the details.
+ details->set(kThreadDetailsCurrentThreadIndex,
+ isolate->heap()->true_value());
+ details->set(kThreadDetailsThreadIdIndex,
+ Smi::FromInt(ThreadId::Current().ToInteger()));
+ } else {
+ // Find the thread with the requested index.
+ int n = 1;
+ ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
+ while (index != n && thread != NULL) {
+ thread = thread->Next();
+ n++;
+ }
+ if (thread == NULL) {
+ return isolate->heap()->undefined_value();
+ }
+
+ // Fill the details.
+ details->set(kThreadDetailsCurrentThreadIndex,
+ isolate->heap()->false_value());
+ details->set(kThreadDetailsThreadIdIndex,
+ Smi::FromInt(thread->id().ToInteger()));
+ }
+
+ // Convert to JS array and return.
+ return *isolate->factory()->NewJSArrayWithElements(details);
+}
+
+
+// Sets the disable break state
+// args[0]: disable break state
+RUNTIME_FUNCTION(Runtime_SetDisableBreak) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
+ isolate->debug()->set_disable_break(disable_break);
+ return isolate->heap()->undefined_value();
+}
+
+
+static bool IsPositionAlignmentCodeCorrect(int alignment) {
+ return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
+ CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
+
+ if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
+ return isolate->ThrowIllegalOperation();
+ }
+ BreakPositionAlignment alignment =
+ static_cast<BreakPositionAlignment>(statement_aligned_code);
+
+ Handle<SharedFunctionInfo> shared(fun->shared());
+ // Find the number of break points
+ Handle<Object> break_locations =
+ Debug::GetSourceBreakLocations(shared, alignment);
+ if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
+ // Return array as JS array
+ return *isolate->factory()->NewJSArrayWithElements(
+ Handle<FixedArray>::cast(break_locations));
+}
+
+
+// Set a break point in a function.
+// args[0]: function
+// args[1]: number: break source position (within the function source)
+// args[2]: number: break point object
+RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+ RUNTIME_ASSERT(source_position >= function->shared()->start_position() &&
+ source_position <= function->shared()->end_position());
+ CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
+
+ // Set break point.
+ RUNTIME_ASSERT(isolate->debug()->SetBreakPoint(
+ function, break_point_object_arg, &source_position));
+
+ return Smi::FromInt(source_position);
+}
+
+
+// Changes the state of a break point in a script and returns source position
+// where break point was set. NOTE: Regarding performance see the NOTE for
+// GetScriptFromScriptData.
+// args[0]: script to set break point in
+// args[1]: number: break source position (within the script source)
+// args[2]: number, breakpoint position alignment
+// args[3]: number: break point object
+RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 4);
+ CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
+ CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+ RUNTIME_ASSERT(source_position >= 0);
+ CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
+ CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
+
+ if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
+ return isolate->ThrowIllegalOperation();
+ }
+ BreakPositionAlignment alignment =
+ static_cast<BreakPositionAlignment>(statement_aligned_code);
+
+ // Get the script from the script wrapper.
+ RUNTIME_ASSERT(wrapper->value()->IsScript());
+ Handle<Script> script(Script::cast(wrapper->value()));
+
+ // Set break point.
+ if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
+ &source_position, alignment)) {
+ return isolate->heap()->undefined_value();
+ }
+
+ return Smi::FromInt(source_position);
+}
+
+
+// Clear a break point
+// args[0]: number: break point object
+RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
+
+ // Clear break point.
+ isolate->debug()->ClearBreakPoint(break_point_object_arg);
+
+ return isolate->heap()->undefined_value();
+}
+
+
+// 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(args.length() == 2);
+ 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) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
+
+ ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
+ bool result = isolate->debug()->IsBreakOnException(type);
+ 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(args.length() == 4);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+ if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
+ }
+
+ CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
+
+ StackFrame::Id frame_id;
+ if (wrapped_frame_id == 0) {
+ frame_id = StackFrame::NO_ID;
+ } else {
+ frame_id = UnwrapFrameId(wrapped_frame_id);
+ }
+
+ // 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 && step_action != StepInMin &&
+ step_action != StepMin) {
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
+ }
+
+ if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
+ step_action != StepMin && step_action != StepOut) {
+ return isolate->ThrowIllegalOperation();
+ }
+
+ // Get the number of steps.
+ int step_count = NumberToInt32(args[2]);
+ if (step_count < 1) {
+ 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),
+ step_count, frame_id);
+ return isolate->heap()->undefined_value();
+}
+
+
+// Clear all stepping set by PrepareStep.
+RUNTIME_FUNCTION(Runtime_ClearStepping) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 0);
+ isolate->debug()->ClearStepping();
+ return isolate->heap()->undefined_value();
+}
+
+
+// Helper function to find or create the arguments object for
+// Runtime_DebugEvaluate.
+MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
+ Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function) {
+ // Do not materialize the arguments object for eval or top-level code.
+ // Skip if "arguments" is already taken.
+ if (!function->shared()->is_function()) return target;
+ Maybe<bool> maybe = JSReceiver::HasOwnProperty(
+ target, isolate->factory()->arguments_string());
+ if (!maybe.has_value) return MaybeHandle<JSObject>();
+ if (maybe.value) return target;
+
+ // FunctionGetArguments can't throw an exception.
+ Handle<JSObject> arguments =
+ Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
+ Handle<String> arguments_str = isolate->factory()->arguments_string();
+ RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
+ target, arguments_str, arguments, NONE),
+ JSObject);
+ return target;
+}
+
+
+// Compile and evaluate source for the given context.
+static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
+ Handle<Context> context,
+ Handle<Object> context_extension,
+ Handle<Object> receiver,
+ Handle<String> source) {
+ if (context_extension->IsJSObject()) {
+ Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
+ Handle<JSFunction> closure(context->closure(), isolate);
+ context = isolate->factory()->NewWithContext(closure, context, extension);
+ }
+
+ Handle<JSFunction> eval_fun;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, eval_fun, Compiler::GetFunctionFromEval(source, context, SLOPPY,
+ NO_PARSE_RESTRICTION,
+ RelocInfo::kNoPosition),
+ Object);
+
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
+ Object);
+
+ // Skip the global proxy as it has no properties and always delegates to the
+ // real global object.
+ if (result->IsJSGlobalProxy()) {
+ PrototypeIterator iter(isolate, result);
+ // TODO(verwaest): This will crash when the global proxy is detached.
+ result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+ }
+
+ // Clear the oneshot breakpoints so that the debugger does not step further.
+ isolate->debug()->ClearStepping();
+ return result;
+}
+
+
+static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
+ Handle<JSObject> result =
+ isolate->factory()->NewJSObject(isolate->object_function());
+ Handle<Map> new_map = Map::Copy(Handle<Map>(result->map()));
+ new_map->set_prototype(*isolate->factory()->null_value());
+ JSObject::MigrateToMap(result, new_map);
+ return result;
+}
+
+
+// Evaluate a piece of JavaScript in the context of a stack frame for
+// debugging. Things that need special attention are:
+// - Parameters and stack-allocated locals need to be materialized. Altered
+// values need to be written back to the stack afterwards.
+// - The arguments object needs to materialized.
+RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
+ HandleScope scope(isolate);
+
+ // Check the execution state and decode arguments frame and source to be
+ // evaluated.
+ DCHECK(args.length() == 6);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(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(disable_break, 4);
+ CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
+
+ // Handle the processing of break.
+ DisableBreak disable_break_scope(isolate->debug(), disable_break);
+
+ // Get the frame where the debugging is performed.
+ StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ JavaScriptFrameIterator it(isolate, id);
+ JavaScriptFrame* frame = it.frame();
+ FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
+ Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
+
+ // Traverse the saved contexts chain to find the active context for the
+ // selected frame.
+ SaveContext* save = FindSavedContextForFrame(isolate, frame);
+
+ SaveContext savex(isolate);
+ isolate->set_context(*(save->context()));
+
+ // Materialize stack locals and the arguments object.
+ Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate);
+
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, materialized,
+ MaterializeStackLocalsWithFrameInspector(isolate, materialized, function,
+ &frame_inspector));
+
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, materialized,
+ MaterializeArgumentsObject(isolate, materialized, function));
+
+ // At this point, the lookup chain may look like this:
+ // [inner context] -> [function stack]+[function context] -> [outer context]
+ // The function stack is not an actual context, it complements the function
+ // context. In order to have the same lookup chain when debug-evaluating,
+ // we materialize the stack and insert it into the context chain as a
+ // with-context before the function context.
+ // [inner context] -> [with context] -> [function context] -> [outer context]
+ // Ordering the with-context before the function context forces a dynamic
+ // lookup instead of a static lookup that could fail as the scope info is
+ // outdated and may expect variables to still be stack-allocated.
+ // Afterwards, we write changes to the with-context back to the stack
+ // and remove it from the context chain.
+ // This could cause lookup failures if debug-evaluate creates a closure that
+ // uses this temporary context chain.
+
+ Handle<Context> eval_context(Context::cast(frame_inspector.GetContext()));
+ DCHECK(!eval_context.is_null());
+ Handle<Context> function_context = eval_context;
+ Handle<Context> outer_context(function->context(), isolate);
+ Handle<Context> inner_context;
+ // We iterate to find the function's context. If the function has no
+ // context-allocated variables, we iterate until we hit the outer context.
+ while (!function_context->IsFunctionContext() &&
+ !function_context.is_identical_to(outer_context)) {
+ inner_context = function_context;
+ function_context = Handle<Context>(function_context->previous(), isolate);
+ }
+
+ Handle<Context> materialized_context = isolate->factory()->NewWithContext(
+ function, function_context, materialized);
+
+ if (inner_context.is_null()) {
+ // No inner context. The with-context is now inner-most.
+ eval_context = materialized_context;
+ } else {
+ inner_context->set_previous(*materialized_context);
+ }
+
+ Handle<Object> receiver(frame->receiver(), isolate);
+ MaybeHandle<Object> maybe_result =
+ DebugEvaluate(isolate, eval_context, context_extension, receiver, source);
+
+ // Remove with-context if it was inserted in between.
+ if (!inner_context.is_null()) inner_context->set_previous(*function_context);
+
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
+
+ // Write back potential changes to materialized stack locals to the stack.
+ UpdateStackLocalsFromMaterializedObject(isolate, materialized, function,
+ frame, inlined_jsframe_index);
+
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
+ HandleScope scope(isolate);
+
+ // Check the execution state and decode arguments frame and source to be
+ // evaluated.
+ DCHECK(args.length() == 4);
+ CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
+ RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
+
+ CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
+ CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
+ CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
+
+ // Handle the processing of break.
+ DisableBreak disable_break_scope(isolate->debug(), disable_break);
+
+ // Enter the top context from before the debugger was invoked.
+ SaveContext save(isolate);
+ SaveContext* top = &save;
+ while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
+ top = top->prev();
+ }
+ if (top != NULL) {
+ isolate->set_context(*top->context());
+ }
+
+ // Get the native context now set to the top context from before the
+ // debugger was invoked.
+ Handle<Context> context = isolate->native_context();
+ Handle<JSObject> receiver(context->global_proxy());
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ DebugEvaluate(isolate, context, context_extension, receiver, source));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 0);
+
+ // Fill the script objects.
+ Handle<FixedArray> 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);
+ }
+
+ // Return result as a JS array.
+ Handle<JSObject> result =
+ isolate->factory()->NewJSObject(isolate->array_function());
+ JSArray::SetContent(Handle<JSArray>::cast(result), instances);
+ return *result;
+}
+
+
+// Helper function used by Runtime_DebugReferencedBy below.
+static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
+ Object* instance_filter, int max_references,
+ FixedArray* instances, int instances_size,
+ JSFunction* arguments_function) {
+ Isolate* isolate = target->GetIsolate();
+ SealHandleScope shs(isolate);
+ DisallowHeapAllocation no_allocation;
+
+ // Iterate the heap.
+ int count = 0;
+ JSObject* last = NULL;
+ HeapObject* heap_obj = NULL;
+ while (((heap_obj = iterator->next()) != NULL) &&
+ (max_references == 0 || count < max_references)) {
+ // Only look at all JSObjects.
+ if (heap_obj->IsJSObject()) {
+ // Skip context extension objects and argument arrays as these are
+ // checked in the context of functions using them.
+ JSObject* obj = JSObject::cast(heap_obj);
+ if (obj->IsJSContextExtensionObject() ||
+ obj->map()->constructor() == arguments_function) {
+ continue;
+ }
+
+ // Check if the JS object has a reference to the object looked for.
+ if (obj->ReferencesObject(target)) {
+ // Check instance filter if supplied. This is normally used to avoid
+ // references from mirror objects (see Runtime_IsInPrototypeChain).
+ if (!instance_filter->IsUndefined()) {
+ for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
+ iter.Advance()) {
+ if (iter.GetCurrent() == instance_filter) {
+ obj = NULL; // Don't add this object.
+ break;
+ }
+ }
+ }
+
+ if (obj != NULL) {
+ // Valid reference found add to instance array if supplied an update
+ // count.
+ if (instances != NULL && count < instances_size) {
+ instances->set(count, obj);
+ }
+ last = obj;
+ count++;
+ }
+ }
+ }
+ }
+
+ // 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.
+ if (count == 1 && last == target) {
+ count = 0;
+ }
+
+ // Return the number of referencing objects found.
+ return count;
+}
+
+
+// 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(args.length() == 3);
+
+ // Check parameters.
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
+ RUNTIME_ASSERT(instance_filter->IsUndefined() ||
+ instance_filter->IsJSObject());
+ CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
+ RUNTIME_ASSERT(max_references >= 0);
+
+
+ // Get the constructor function for context extension and arguments array.
+ Handle<JSFunction> arguments_function(
+ JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
+
+ // Get the number of referencing objects.
+ int count;
+ // First perform a full GC in order to avoid dead objects and to make the heap
+ // iterable.
+ Heap* heap = isolate->heap();
+ heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
+ {
+ HeapIterator heap_iterator(heap);
+ count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
+ max_references, NULL, 0, *arguments_function);
+ }
+
+ // Allocate an array to hold the result.
+ Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
+
+ // Fill the referencing objects.
+ {
+ HeapIterator heap_iterator(heap);
+ count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
+ max_references, *instances, count,
+ *arguments_function);
+ }
+
+ // Return result as JS array.
+ Handle<JSFunction> constructor = isolate->array_function();
+
+ Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
+ JSArray::SetContent(Handle<JSArray>::cast(result), instances);
+ return *result;
+}
+
+
+// Helper function used by Runtime_DebugConstructedBy below.
+static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
+ int max_references, FixedArray* instances,
+ int instances_size) {
+ DisallowHeapAllocation no_allocation;
+
+ // Iterate the heap.
+ int count = 0;
+ HeapObject* heap_obj = NULL;
+ while (((heap_obj = iterator->next()) != NULL) &&
+ (max_references == 0 || count < max_references)) {
+ // Only look at all JSObjects.
+ if (heap_obj->IsJSObject()) {
+ JSObject* obj = JSObject::cast(heap_obj);
+ if (obj->map()->constructor() == constructor) {
+ // Valid reference found add to instance array if supplied an update
+ // count.
+ if (instances != NULL && count < instances_size) {
+ instances->set(count, obj);
+ }
+ count++;
+ }
+ }
+ }
+
+ // Return the number of referencing objects found.
+ return count;
+}
+
+
+// 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(args.length() == 2);
+
+
+ // Check parameters.
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
+ CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
+ RUNTIME_ASSERT(max_references >= 0);
+
+ // Get the number of referencing objects.
+ int count;
+ // First perform a full GC in order to avoid dead objects and to make the heap
+ // iterable.
+ Heap* heap = isolate->heap();
+ heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
+ {
+ HeapIterator heap_iterator(heap);
+ count = DebugConstructedBy(&heap_iterator, *constructor, max_references,
+ NULL, 0);
+ }
+
+ // Allocate an array to hold the result.
+ Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
+
+ // Fill the referencing objects.
+ {
+ HeapIterator heap_iterator2(heap);
+ count = DebugConstructedBy(&heap_iterator2, *constructor, max_references,
+ *instances, count);
+ }
+
+ // Return result as JS array.
+ Handle<JSFunction> array_function = isolate->array_function();
+ Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
+ JSArray::SetContent(Handle<JSArray>::cast(result), instances);
+ return *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(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ return *Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
+}
+
+
+// Patches script source (should be called upon BeforeCompile event).
+RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+
+ CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
+ CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
+
+ RUNTIME_ASSERT(script_wrapper->value()->IsScript());
+ Handle<Script> script(Script::cast(script_wrapper->value()));
+
+ int compilation_state = script->compilation_state();
+ RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
+ script->set_source(*source);
+
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
+ HandleScope scope(isolate);
+#ifdef DEBUG
+ DCHECK(args.length() == 1);
+ // Get the function and make sure it is compiled.
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
+ if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
+ return isolate->heap()->exception();
+ }
+ OFStream os(stdout);
+ func->code()->Print(os);
+ os << endl;
+#endif // DEBUG
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) {
+ HandleScope scope(isolate);
+#ifdef DEBUG
+ DCHECK(args.length() == 1);
+ // Get the function and make sure it is compiled.
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
+ if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
+ return isolate->heap()->exception();
+ }
+ OFStream os(stdout);
+ func->shared()->construct_stub()->Print(os);
+ os << endl;
+#endif // DEBUG
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+
+ CONVERT_ARG_CHECKED(JSFunction, f, 0);
+ return f->shared()->inferred_name();
+}
+
+
+// A testing entry. Returns statement position which is the closest to
+// source_position.
+RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
+ HandleScope scope(isolate);
+ CHECK(isolate->debug()->live_edit_enabled());
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
+
+ Handle<Code> code(function->code(), isolate);
+
+ if (code->kind() != Code::FUNCTION &&
+ code->kind() != Code::OPTIMIZED_FUNCTION) {
+ return isolate->heap()->undefined_value();
+ }
+
+ RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
+ int closest_pc = 0;
+ int distance = kMaxInt;
+ while (!it.done()) {
+ int statement_position = static_cast<int>(it.rinfo()->data());
+ // Check if this break point is closer that what was previously found.
+ if (source_position <= statement_position &&
+ statement_position - source_position < distance) {
+ closest_pc =
+ static_cast<int>(it.rinfo()->pc() - code->instruction_start());
+ distance = statement_position - source_position;
+ // Check whether we can't get any closer.
+ if (distance == 0) break;
+ }
+ it.next();
+ }
+
+ return Smi::FromInt(closest_pc);
+}
+
+
+// Calls specified function with or without entering the debugger.
+// This is used in unit tests to run code as if debugger is entered or simply
+// to have a stack with C++ frame in the middle.
+RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
+
+ MaybeHandle<Object> maybe_result;
+ if (without_debugger) {
+ maybe_result = Execution::Call(isolate, function,
+ handle(function->global_proxy()), 0, NULL);
+ } else {
+ DebugScope debug_scope(isolate->debug());
+ maybe_result = Execution::Call(isolate, function,
+ handle(function->global_proxy()), 0, NULL);
+ }
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
+ return *result;
+}
+
+
+// Performs a GC.
+// Presently, it only does a full GC.
+RUNTIME_FUNCTION(Runtime_CollectGarbage) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+ isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
+ return isolate->heap()->undefined_value();
+}
+
+
+// Gets the current heap usage.
+RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 0);
+ int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
+ if (!Smi::IsValid(usage)) {
+ return *isolate->factory()->NewNumberFromInt(usage);
+ }
+ 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.
+static Handle<Object> Runtime_GetScriptFromScriptName(
+ Handle<String> script_name) {
+ // Scan the heap for Script objects to find the script with the requested
+ // script data.
+ Handle<Script> script;
+ Factory* factory = script_name->GetIsolate()->factory();
+ Heap* heap = script_name->GetHeap();
+ HeapIterator iterator(heap);
+ HeapObject* obj = NULL;
+ while (script.is_null() && ((obj = iterator.next()) != NULL)) {
+ // If a script is found check if it has the script data requested.
+ if (obj->IsScript()) {
+ if (Script::cast(obj)->name()->IsString()) {
+ if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
+ script = Handle<Script>(Script::cast(obj));
+ }
+ }
+ }
+ }
+
+ // If no script with the requested script data is found return undefined.
+ if (script.is_null()) return factory->undefined_value();
+
+ // Return the script found.
+ return Script::GetWrapper(script);
+}
+
+
+// Get the script object from script data. NOTE: Regarding performance
+// see the NOTE for GetScriptFromScriptData.
+// args[0]: script data for the script to find the source for
+RUNTIME_FUNCTION(Runtime_GetScript) {
+ HandleScope scope(isolate);
+
+ DCHECK(args.length() == 1);
+
+ CONVERT_ARG_CHECKED(String, script_name, 0);
+
+ // Find the requested script.
+ Handle<Object> result =
+ Runtime_GetScriptFromScriptName(Handle<String>(script_name));
+ return *result;
+}
+
+
+// Check whether debugger and is about to step into the callback that is passed
+// to a built-in function such as Array.forEach.
+RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
+ DCHECK(args.length() == 1);
+ if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) {
+ return isolate->heap()->false_value();
+ }
+ CONVERT_ARG_CHECKED(Object, callback, 0);
+ // We do not step into the callback if it's a builtin or not even a function.
+ return isolate->heap()->ToBoolean(callback->IsJSFunction() &&
+ !JSFunction::cast(callback)->IsBuiltin());
+}
+
+
+// Set one shot breakpoints for the callback function that is passed to a
+// built-in function such as Array.forEach to enable stepping into the callback.
+RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
+ DCHECK(args.length() == 1);
+ Debug* debug = isolate->debug();
+ if (!debug->IsStepping()) return isolate->heap()->undefined_value();
+
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+ RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject());
+ Handle<JSFunction> fun;
+ if (object->IsJSFunction()) {
+ fun = Handle<JSFunction>::cast(object);
+ } else {
+ fun = Handle<JSFunction>(
+ Handle<JSGeneratorObject>::cast(object)->function(), isolate);
+ }
+ // When leaving the function, step out has been activated, but not performed
+ // if we do not leave the builtin. To be able to step into the function
+ // again, we need to clear the step out at this point.
+ debug->ClearStepOut();
+ debug->FloodWithOneShot(fun);
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
+ DCHECK(args.length() == 1);
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
+ isolate->PushPromise(promise);
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
+ DCHECK(args.length() == 0);
+ SealHandleScope shs(isolate);
+ isolate->PopPromise();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
+ DCHECK(args.length() == 1);
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
+ isolate->debug()->OnPromiseEvent(data);
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
+ DCHECK(args.length() == 1);
+ HandleScope scope(isolate);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
+ isolate->debug()->OnAsyncTaskEvent(data);
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) {
+ SealHandleScope shs(isolate);
+ return Smi::FromInt(isolate->debug()->is_active());
+}
+}
+} // namespace v8::internal
#include "src/compilation-cache.h"
#include "src/compiler.h"
#include "src/conversions.h"
-#include "src/cpu-profiler.h"
-#include "src/date.h"
-#include "src/dateparser-inl.h"
-#include "src/debug.h"
#include "src/deoptimizer.h"
#include "src/execution.h"
#include "src/full-codegen.h"
#include "src/global-handles.h"
#include "src/isolate-inl.h"
-#include "src/liveedit.h"
-#include "src/misc-intrinsics.h"
#include "src/parser.h"
#include "src/prototype.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
-#include "src/runtime-profiler.h"
#include "src/scopeinfo.h"
#include "src/smart-pointers.h"
#include "src/utils.h"
#include "src/v8threads.h"
-#include "src/vm-state-inl.h"
namespace v8 {
}
-static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
- Isolate* isolate, Handle<Object> receiver) {
- PrototypeIterator iter(isolate, receiver);
- while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
- if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
- return PrototypeIterator::GetCurrent(iter);
- }
- iter.Advance();
- }
- return PrototypeIterator::GetCurrent(iter);
-}
-
-
RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
return isolate->heap()->undefined_value();
}
if (obj->map()->is_observed()) {
- Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
+ Handle<Object> old_value =
+ Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, JSObject::SetPrototype(obj, prototype, true));
- Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj);
+ Handle<Object> new_value =
+ Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
if (!new_value->SameValue(*old_value)) {
JSObject::EnqueueChangeRecord(
obj, "setPrototype", isolate->factory()->proto_string(), old_value);
}
-RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_CHECKED(JSFunction, f, 0);
- return isolate->heap()->ToBoolean(f->shared()->is_generator());
-}
-
-
RUNTIME_FUNCTION(Runtime_FunctionIsArrow) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
}
-RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
-
- JavaScriptFrameIterator it(isolate);
- JavaScriptFrame* frame = it.frame();
- Handle<JSFunction> function(frame->function());
- RUNTIME_ASSERT(function->shared()->is_generator());
-
- Handle<JSGeneratorObject> generator;
- if (frame->IsConstructor()) {
- generator = handle(JSGeneratorObject::cast(frame->receiver()));
- } else {
- generator = isolate->factory()->NewJSGeneratorObject(function);
- }
- generator->set_function(*function);
- generator->set_context(Context::cast(frame->context()));
- generator->set_receiver(frame->receiver());
- generator->set_continuation(0);
- generator->set_operand_stack(isolate->heap()->empty_fixed_array());
- generator->set_stack_handler_index(-1);
-
- return *generator;
-}
-
-
-RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
- HandleScope handle_scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
-
- JavaScriptFrameIterator stack_iterator(isolate);
- JavaScriptFrame* frame = stack_iterator.frame();
- RUNTIME_ASSERT(frame->function()->shared()->is_generator());
- DCHECK_EQ(frame->function(), generator_object->function());
-
- // The caller should have saved the context and continuation already.
- DCHECK_EQ(generator_object->context(), Context::cast(frame->context()));
- DCHECK_LT(0, generator_object->continuation());
-
- // We expect there to be at least two values on the operand stack: the return
- // value of the yield expression, and the argument to this runtime call.
- // Neither of those should be saved.
- int operands_count = frame->ComputeOperandsCount();
- DCHECK_GE(operands_count, 2);
- operands_count -= 2;
-
- if (operands_count == 0) {
- // Although it's semantically harmless to call this function with an
- // operands_count of zero, it is also unnecessary.
- DCHECK_EQ(generator_object->operand_stack(),
- isolate->heap()->empty_fixed_array());
- DCHECK_EQ(generator_object->stack_handler_index(), -1);
- // If there are no operands on the stack, there shouldn't be a handler
- // active either.
- DCHECK(!frame->HasHandler());
- } else {
- int stack_handler_index = -1;
- Handle<FixedArray> operand_stack =
- isolate->factory()->NewFixedArray(operands_count);
- frame->SaveOperandStack(*operand_stack, &stack_handler_index);
- generator_object->set_operand_stack(*operand_stack);
- generator_object->set_stack_handler_index(stack_handler_index);
- }
-
- return isolate->heap()->undefined_value();
-}
-
-
-// Note that this function is the slow path for resuming generators. It is only
-// called if the suspended activation had operands on the stack, stack handlers
-// needing rewinding, or if the resume should throw an exception. The fast path
-// is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
-// inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
-// called in any case, as it needs to reconstruct the stack frame and make space
-// for arguments and operands.
-RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 3);
- CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
- CONVERT_ARG_CHECKED(Object, value, 1);
- CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
- JavaScriptFrameIterator stack_iterator(isolate);
- JavaScriptFrame* frame = stack_iterator.frame();
-
- DCHECK_EQ(frame->function(), generator_object->function());
- DCHECK(frame->function()->is_compiled());
-
- STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
- STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
-
- Address pc = generator_object->function()->code()->instruction_start();
- int offset = generator_object->continuation();
- DCHECK(offset > 0);
- frame->set_pc(pc + offset);
- if (FLAG_enable_ool_constant_pool) {
- frame->set_constant_pool(
- generator_object->function()->code()->constant_pool());
- }
- generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
-
- FixedArray* operand_stack = generator_object->operand_stack();
- int operands_count = operand_stack->length();
- if (operands_count != 0) {
- frame->RestoreOperandStack(operand_stack,
- generator_object->stack_handler_index());
- generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
- generator_object->set_stack_handler_index(-1);
- }
-
- JSGeneratorObject::ResumeMode resume_mode =
- static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
- switch (resume_mode) {
- case JSGeneratorObject::NEXT:
- return value;
- case JSGeneratorObject::THROW:
- return isolate->Throw(value);
- }
-
- UNREACHABLE();
- return isolate->ThrowIllegalOperation();
-}
-
-
-RUNTIME_FUNCTION(Runtime_ThrowGeneratorStateError) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
- int continuation = generator->continuation();
- const char* message = continuation == JSGeneratorObject::kGeneratorClosed
- ? "generator_finished"
- : "generator_running";
- Vector<Handle<Object> > argv = HandleVector<Object>(NULL, 0);
- THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(message, argv));
-}
-
-
RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
}
-// Check whether debugger and is about to step into the callback that is passed
-// to a built-in function such as Array.forEach.
-RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
- DCHECK(args.length() == 1);
- if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) {
- return isolate->heap()->false_value();
- }
- CONVERT_ARG_CHECKED(Object, callback, 0);
- // We do not step into the callback if it's a builtin or not even a function.
- return isolate->heap()->ToBoolean(callback->IsJSFunction() &&
- !JSFunction::cast(callback)->IsBuiltin());
-}
-
-
-// Set one shot breakpoints for the callback function that is passed to a
-// built-in function such as Array.forEach to enable stepping into the callback.
-RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
- DCHECK(args.length() == 1);
- Debug* debug = isolate->debug();
- if (!debug->IsStepping()) return isolate->heap()->undefined_value();
-
- HandleScope scope(isolate);
- CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
- RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject());
- Handle<JSFunction> fun;
- if (object->IsJSFunction()) {
- fun = Handle<JSFunction>::cast(object);
- } else {
- fun = Handle<JSFunction>(
- Handle<JSGeneratorObject>::cast(object)->function(), isolate);
- }
- // When leaving the function, step out has been activated, but not performed
- // if we do not leave the builtin. To be able to step into the function
- // again, we need to clear the step out at this point.
- debug->ClearStepOut();
- debug->FloodWithOneShot(fun);
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPushPromise) {
- DCHECK(args.length() == 1);
- HandleScope scope(isolate);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
- isolate->PushPromise(promise);
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPopPromise) {
- DCHECK(args.length() == 0);
- SealHandleScope shs(isolate);
- isolate->PopPromise();
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) {
- DCHECK(args.length() == 1);
- HandleScope scope(isolate);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
- isolate->debug()->OnPromiseEvent(data);
- return isolate->heap()->undefined_value();
-}
-
-
RUNTIME_FUNCTION(Runtime_DebugPromiseRejectEvent) {
DCHECK(args.length() == 2);
HandleScope scope(isolate);
}
-RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) {
- DCHECK(args.length() == 1);
- HandleScope scope(isolate);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0);
- isolate->debug()->OnAsyncTaskEvent(data);
- return isolate->heap()->undefined_value();
-}
-
-
RUNTIME_FUNCTION(Runtime_DeleteProperty) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
}
-
-
-
-RUNTIME_FUNCTION(Runtime_DateMakeDay) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 2);
-
- CONVERT_SMI_ARG_CHECKED(year, 0);
- CONVERT_SMI_ARG_CHECKED(month, 1);
-
- int days = isolate->date_cache()->DaysFromYearMonth(year, month);
- RUNTIME_ASSERT(Smi::IsValid(days));
- return Smi::FromInt(days);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateSetValue) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 3);
-
- CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
- CONVERT_DOUBLE_ARG_CHECKED(time, 1);
- CONVERT_SMI_ARG_CHECKED(is_utc, 2);
-
- DateCache* date_cache = isolate->date_cache();
-
- Handle<Object> value;
- ;
- bool is_value_nan = false;
- if (std::isnan(time)) {
- value = isolate->factory()->nan_value();
- is_value_nan = true;
- } else if (!is_utc && (time < -DateCache::kMaxTimeBeforeUTCInMs ||
- time > DateCache::kMaxTimeBeforeUTCInMs)) {
- value = isolate->factory()->nan_value();
- is_value_nan = true;
- } else {
- time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
- if (time < -DateCache::kMaxTimeInMs || time > DateCache::kMaxTimeInMs) {
- value = isolate->factory()->nan_value();
- is_value_nan = true;
- } else {
- value = isolate->factory()->NewNumber(DoubleToInteger(time));
- }
- }
- date->SetValue(*value, is_value_nan);
- return *value;
-}
-
-
static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
Handle<JSFunction> callee,
Object** parameters,
}
-RUNTIME_FUNCTION(Runtime_ThrowNotDateError) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
-}
-
-
RUNTIME_FUNCTION(Runtime_StackGuard) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
}
-RUNTIME_FUNCTION(Runtime_DateCurrentTime) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
- if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent());
-
- // According to ECMA-262, section 15.9.1, page 117, the precision of
- // the number in a Date object representing a particular instant in
- // time is milliseconds. Therefore, we floor the result of getting
- // the OS time.
- double millis;
- if (FLAG_verify_predictable) {
- millis = 1388534400000.0; // Jan 1 2014 00:00:00 GMT+0000
- millis += Floor(isolate->heap()->synthetic_time());
- } else {
- millis = Floor(base::OS::TimeCurrentMillis());
- }
- return *isolate->factory()->NewNumber(millis);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateParseString) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
-
- RUNTIME_ASSERT(output->HasFastElements());
- JSObject::EnsureCanContainHeapObjectElements(output);
- RUNTIME_ASSERT(output->HasFastObjectElements());
- Handle<FixedArray> output_array(FixedArray::cast(output->elements()));
- RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
-
- str = String::Flatten(str);
- DisallowHeapAllocation no_gc;
-
- bool result;
- String::FlatContent str_content = str->GetFlatContent();
- if (str_content.IsOneByte()) {
- result = DateParser::Parse(str_content.ToOneByteVector(), *output_array,
- isolate->unicode_cache());
- } else {
- DCHECK(str_content.IsTwoByte());
- result = DateParser::Parse(str_content.ToUC16Vector(), *output_array,
- isolate->unicode_cache());
- }
-
- if (result) {
- return *output;
- } else {
- return isolate->heap()->null_value();
- }
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateLocalTimezone) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
-
- CONVERT_DOUBLE_ARG_CHECKED(x, 0);
- RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
- x <= DateCache::kMaxTimeBeforeUTCInMs);
- const char* zone =
- isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
- Handle<String> result =
- isolate->factory()->NewStringFromUtf8(CStrVector(zone)).ToHandleChecked();
- return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateToUTC) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
-
- CONVERT_DOUBLE_ARG_CHECKED(x, 0);
- RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
- x <= DateCache::kMaxTimeBeforeUTCInMs);
- int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
-
- return *isolate->factory()->NewNumber(static_cast<double>(time));
-}
-
-
-RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
- HandleScope hs(isolate);
- DCHECK(args.length() == 0);
- if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
- Handle<FixedArray> date_cache_version =
- isolate->factory()->NewFixedArray(1, TENURED);
- date_cache_version->set(0, Smi::FromInt(0));
- isolate->eternal_handles()->CreateSingleton(
- isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
- }
- Handle<FixedArray> date_cache_version =
- Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
- EternalHandles::DATE_CACHE_VERSION));
- // Return result as a JS array.
- Handle<JSObject> result =
- isolate->factory()->NewJSObject(isolate->array_function());
- JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version);
- return *result;
-}
-
-
RUNTIME_FUNCTION(Runtime_GlobalProxy) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
}
-RUNTIME_FUNCTION(Runtime_DebugBreak) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 0);
- isolate->debug()->HandleDebugBreak();
+// Collect the raw data for a stack trace. Returns an array of 4
+// element segments each containing a receiver, function, code and
+// native code offset.
+RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
+
+ if (!isolate->bootstrapper()->IsActive()) {
+ // Optionally capture a more detailed stack trace for the message.
+ isolate->CaptureAndSetDetailedStackTrace(error_object);
+ // Capture a simple stack trace for the stack property.
+ isolate->CaptureAndSetSimpleStackTrace(error_object, caller);
+ }
return isolate->heap()->undefined_value();
}
-// Helper functions for wrapping and unwrapping stack frame ids.
-static Smi* WrapFrameId(StackFrame::Id id) {
- DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
- return Smi::FromInt(id >> 2);
+RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
+ RUNTIME_ASSERT((index->value() & 1) == 1);
+ FieldIndex field_index =
+ FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
+ if (field_index.is_inobject()) {
+ RUNTIME_ASSERT(field_index.property_index() <
+ object->map()->inobject_properties());
+ } else {
+ RUNTIME_ASSERT(field_index.outobject_array_index() <
+ object->properties()->length());
+ }
+ Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
+ RUNTIME_ASSERT(raw_value->IsMutableHeapNumber());
+ return *Object::WrapForRead(isolate, raw_value, Representation::Double());
}
-static StackFrame::Id UnwrapFrameId(int wrapped) {
- return static_cast<StackFrame::Id>(wrapped << 2);
+RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+ if (!object->IsJSObject()) return Smi::FromInt(0);
+ Handle<JSObject> js_object = Handle<JSObject>::cast(object);
+ if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
+ // This call must not cause lazy deopts, because it's called from deferred
+ // code where we can't handle lazy deopts for lack of a suitable bailout
+ // ID. So we just try migration and signal failure if necessary,
+ // which will also trigger a deopt.
+ if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
+ return *object;
}
-// Adds a JavaScript function as a debug event listener.
-// args[0]: debug event listener function to set or null or undefined for
-// clearing the event listener function
-// args[1]: object supplied during callback
-RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
+RUNTIME_FUNCTION(Runtime_GetFromCache) {
SealHandleScope shs(isolate);
- DCHECK(args.length() == 2);
- RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() ||
- args[0]->IsNull());
- CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
- isolate->debug()->SetEventListener(callback, data);
+ // This is only called from codegen, so checks might be more lax.
+ CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
+ CONVERT_ARG_CHECKED(Object, key, 1);
- return isolate->heap()->undefined_value();
-}
+ {
+ DisallowHeapAllocation no_alloc;
+ int finger_index = cache->finger_index();
+ Object* o = cache->get(finger_index);
+ if (o == key) {
+ // The fastest case: hit the same place again.
+ return cache->get(finger_index + 1);
+ }
-RUNTIME_FUNCTION(Runtime_Break) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 0);
- isolate->stack_guard()->RequestDebugBreak();
- return isolate->heap()->undefined_value();
-}
+ for (int i = finger_index - 2; i >= JSFunctionResultCache::kEntriesIndex;
+ i -= 2) {
+ o = cache->get(i);
+ if (o == key) {
+ cache->set_finger_index(i);
+ return cache->get(i + 1);
+ }
+ }
+ int size = cache->size();
+ DCHECK(size <= cache->length());
-static Handle<Object> DebugGetProperty(LookupIterator* it,
- bool* has_caught = NULL) {
- 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::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->GetReceiver(), it->name(), it->GetHolder<JSObject>(),
- accessors);
- Handle<Object> result;
- if (!maybe_result.ToHandle(&result)) {
- result = handle(it->isolate()->pending_exception(), it->isolate());
- it->isolate()->clear_pending_exception();
- if (has_caught != NULL) *has_caught = true;
- }
- return result;
+ for (int i = size - 2; i > finger_index; i -= 2) {
+ o = cache->get(i);
+ if (o == key) {
+ cache->set_finger_index(i);
+ return cache->get(i + 1);
}
-
- case LookupIterator::DATA:
- return it->GetDataValue();
}
}
- return it->isolate()->factory()->undefined_value();
-}
-
-
-// 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(args.length() == 2);
-
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
- CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-
- // 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 occour, 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;
- 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,
- Runtime::GetElementOrCharAt(isolate, obj, index));
- details->set(0, *element_or_char);
- details->set(1,
- PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
- return *isolate->factory()->NewJSArrayWithElements(details);
- }
-
- LookupIterator it(obj, name, LookupIterator::HIDDEN);
- 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(NONE, NORMAL, 0)
- : it.property_details();
- details->set(1, d.AsSmi());
- details->set(
- 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR));
- if (has_js_accessors) {
- AccessorPair* accessors = AccessorPair::cast(*maybe_pair);
- details->set(3, isolate->heap()->ToBoolean(has_caught));
- details->set(4, accessors->GetComponent(ACCESSOR_GETTER));
- details->set(5, accessors->GetComponent(ACCESSOR_SETTER));
- }
-
- return *isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugGetProperty) {
- HandleScope scope(isolate);
-
- DCHECK(args.length() == 2);
-
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
- CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-
- LookupIterator it(obj, name);
- return *DebugGetProperty(&it);
-}
-
-
-// Return the property type calculated from the property details.
-// args[0]: smi with property details.
-RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 1);
- CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
- return Smi::FromInt(static_cast<int>(details.type()));
-}
-
-
-// Return the property attribute calculated from the property details.
-// args[0]: smi with property details.
-RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 1);
- CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
- return Smi::FromInt(static_cast<int>(details.attributes()));
-}
-
-
-// Return the property insertion index calculated from the property details.
-// args[0]: smi with property details.
-RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 1);
- CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
- // TODO(verwaest): Depends on the type of details.
- return Smi::FromInt(details.dictionary_index());
-}
-
-
-// Return property value from named interceptor.
-// args[0]: object
-// args[1]: property name
-RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
- RUNTIME_ASSERT(obj->HasNamedInterceptor());
- CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
-
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
- JSObject::GetProperty(obj, name));
- return *result;
-}
-
-
-// Return element value from indexed interceptor.
-// args[0]: object
-// args[1]: index
-RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
- RUNTIME_ASSERT(obj->HasIndexedInterceptor());
- CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index));
- return *result;
-}
-
-
-static bool CheckExecutionState(Isolate* isolate, int break_id) {
- return !isolate->debug()->debug_context().is_null() &&
- isolate->debug()->break_id() != 0 &&
- isolate->debug()->break_id() == break_id;
-}
-
-
-RUNTIME_FUNCTION(Runtime_CheckExecutionState) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 1);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
- return isolate->heap()->true_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFrameCount) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, 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::FromInt(0);
- }
-
- for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
- List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
- it.frame()->Summarize(&frames);
- for (int i = frames.length() - 1; i >= 0; i--) {
- // Omit functions from native scripts.
- if (!frames[i].function()->IsFromNativeScript()) n++;
- }
- }
- return Smi::FromInt(n);
-}
-
-
-class FrameInspector {
- public:
- FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index,
- Isolate* isolate)
- : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
- // Calculate the deoptimized frame.
- if (frame->is_optimized()) {
- deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
- frame, inlined_jsframe_index, isolate);
- }
- has_adapted_arguments_ = frame_->has_adapted_arguments();
- is_bottommost_ = inlined_jsframe_index == 0;
- is_optimized_ = frame_->is_optimized();
- }
-
- ~FrameInspector() {
- // Get rid of the calculated deoptimized frame if any.
- if (deoptimized_frame_ != NULL) {
- Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
- }
- }
-
- int GetParametersCount() {
- return is_optimized_ ? deoptimized_frame_->parameters_count()
- : frame_->ComputeParametersCount();
- }
- int expression_count() { return deoptimized_frame_->expression_count(); }
- Object* GetFunction() {
- return is_optimized_ ? deoptimized_frame_->GetFunction()
- : frame_->function();
- }
- Object* GetParameter(int index) {
- return is_optimized_ ? deoptimized_frame_->GetParameter(index)
- : frame_->GetParameter(index);
- }
- Object* GetExpression(int index) {
- return is_optimized_ ? deoptimized_frame_->GetExpression(index)
- : frame_->GetExpression(index);
- }
- int GetSourcePosition() {
- return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
- : frame_->LookupCode()->SourcePosition(frame_->pc());
- }
- bool IsConstructor() {
- return is_optimized_ && !is_bottommost_
- ? deoptimized_frame_->HasConstructStub()
- : frame_->IsConstructor();
- }
- Object* GetContext() {
- return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
- }
-
- // To inspect all the provided arguments the frame might need to be
- // replaced with the arguments frame.
- void SetArgumentsFrame(JavaScriptFrame* frame) {
- DCHECK(has_adapted_arguments_);
- frame_ = frame;
- is_optimized_ = frame_->is_optimized();
- DCHECK(!is_optimized_);
- }
-
- private:
- JavaScriptFrame* frame_;
- DeoptimizedFrameInfo* deoptimized_frame_;
- Isolate* isolate_;
- bool is_optimized_;
- bool is_bottommost_;
- bool has_adapted_arguments_;
-
- DISALLOW_COPY_AND_ASSIGN(FrameInspector);
-};
-
-
-static const int kFrameDetailsFrameIdIndex = 0;
-static const int kFrameDetailsReceiverIndex = 1;
-static const int kFrameDetailsFunctionIndex = 2;
-static const int kFrameDetailsArgumentCountIndex = 3;
-static const int kFrameDetailsLocalCountIndex = 4;
-static const int kFrameDetailsSourcePositionIndex = 5;
-static const int kFrameDetailsConstructCallIndex = 6;
-static const int kFrameDetailsAtReturnIndex = 7;
-static const int kFrameDetailsFlagsIndex = 8;
-static const int kFrameDetailsFirstDynamicIndex = 9;
-
-
-static SaveContext* FindSavedContextForFrame(Isolate* isolate,
- JavaScriptFrame* frame) {
- SaveContext* save = isolate->save_context();
- while (save != NULL && !save->IsBelowFrame(frame)) {
- save = save->prev();
- }
- DCHECK(save != NULL);
- return save;
-}
-
-
-// Advances the iterator to the frame that matches the index and returns the
-// inlined frame index, or -1 if not found. Skips native JS functions.
-static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) {
- int count = -1;
- for (; !it->done(); it->Advance()) {
- List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
- it->frame()->Summarize(&frames);
- for (int i = frames.length() - 1; i >= 0; i--) {
- // Omit functions from native scripts.
- if (frames[i].function()->IsFromNativeScript()) continue;
- if (++count == index) return i;
- }
- }
- return -1;
-}
-
-
-// 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: Argument count
-// 4: Local count
-// 5: Source position
-// 6: Constructor call
-// 7: Is at return
-// 8: Flags
-// Arguments name, value
-// Locals name, value
-// Return value if any
-RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, 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();
- }
-
- JavaScriptFrameIterator it(isolate, id);
- // Inlined frame index in optimized frame, starting from outer function.
- int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index);
- if (inlined_jsframe_index == -1) return heap->undefined_value();
-
- FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
- bool is_optimized = it.frame()->is_optimized();
-
- // Traverse the saved contexts chain to find the active context for the
- // selected frame.
- SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
-
- // Get the frame id.
- Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
-
- // Find source position in unoptimized code.
- int position = frame_inspector.GetSourcePosition();
-
- // Check for constructor frame.
- bool constructor = frame_inspector.IsConstructor();
-
- // Get scope info and read from it for local variable information.
- Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
- 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.
- int local_count = scope_info->LocalCount();
- for (int slot = 0; slot < scope_info->LocalCount(); ++slot) {
- // Hide compiler-introduced temporary variables, whether on the stack or on
- // the context.
- if (scope_info->LocalIsSynthetic(slot)) local_count--;
- }
-
- Handle<FixedArray> locals =
- isolate->factory()->NewFixedArray(local_count * 2);
-
- // Fill in the values of the locals.
- int local = 0;
- int i = 0;
- for (; i < scope_info->StackLocalCount(); ++i) {
- // Use the value from the stack.
- if (scope_info->LocalIsSynthetic(i)) continue;
- locals->set(local * 2, scope_info->LocalName(i));
- locals->set(local * 2 + 1, frame_inspector.GetExpression(i));
- local++;
- }
- if (local < local_count) {
- // Get the context containing declarations.
- Handle<Context> context(
- Context::cast(frame_inspector.GetContext())->declaration_context());
- for (; i < scope_info->LocalCount(); ++i) {
- if (scope_info->LocalIsSynthetic(i)) continue;
- Handle<String> name(scope_info->LocalName(i));
- VariableMode mode;
- InitializationFlag init_flag;
- MaybeAssignedFlag maybe_assigned_flag;
- locals->set(local * 2, *name);
- int context_slot_index = ScopeInfo::ContextSlotIndex(
- scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
- Object* value = context->get(context_slot_index);
- locals->set(local * 2 + 1, value);
- local++;
- }
- }
-
- // 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.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) {
- StackFrameIterator it2(isolate);
- Address internal_frame_sp = NULL;
- while (!it2.done()) {
- if (it2.frame()->is_internal()) {
- internal_frame_sp = it2.frame()->sp();
- } else {
- if (it2.frame()->is_java_script()) {
- if (it2.frame()->id() == it.frame()->id()) {
- // The internal frame just before the JavaScript frame contains the
- // value to return on top. A debug break at return will create an
- // internal frame to store the return value (eax/rax/r0) before
- // entering the debug break exit frame.
- if (internal_frame_sp != NULL) {
- return_value =
- Handle<Object>(Memory::Object_at(internal_frame_sp), isolate);
- break;
- }
- }
- }
-
- // Indicate that the previous frame was not an internal frame.
- internal_frame_sp = NULL;
- }
- it2.Advance();
- }
- }
-
- // 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_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
- it.AdvanceToArgumentsFrame();
- 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 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 != RelocInfo::kNoPosition) {
- 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_jsframe_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 (int i = 0; i < local_count * 2; i++) {
- details->set(details_index++, locals->get(i));
- }
-
- // Add the value being returned.
- if (at_return) {
- details->set(details_index++, *return_value);
- }
-
- // Add the receiver (same as in function frame).
- // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
- // THE FRAME ITERATOR TO WRAP THE RECEIVER.
- Handle<Object> receiver(it.frame()->receiver(), isolate);
- if (!receiver->IsJSObject() && shared->strict_mode() == SLOPPY &&
- !function->IsBuiltin()) {
- // If the receiver is not a JSObject and the function is not a
- // builtin or strict-mode we have hit an optimization where a
- // value object is not converted into a wrapped JS objects. To
- // hide this optimization from the debugger, we wrap the receiver
- // by creating correct wrapper object based on the calling frame's
- // native context.
- it.Advance();
- if (receiver->IsUndefined()) {
- receiver = handle(function->global_proxy());
- } else {
- Context* context = Context::cast(it.frame()->context());
- Handle<Context> native_context(Context::cast(context->native_context()));
- if (!Object::ToObject(isolate, receiver, native_context)
- .ToHandle(&receiver)) {
- // This only happens if the receiver is forcibly set in %_CallFunction.
- return heap->undefined_value();
- }
- }
- }
- details->set(kFrameDetailsReceiverIndex, *receiver);
-
- DCHECK_EQ(details_size, details_index);
- return *isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
- Handle<String> parameter_name) {
- VariableMode mode;
- InitializationFlag init_flag;
- MaybeAssignedFlag maybe_assigned_flag;
- return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
- &maybe_assigned_flag) != -1;
-}
-
-
-// Create a plain JSObject which materializes the local scope for the specified
-// frame.
-MUST_USE_RESULT
-static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector(
- Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
- FrameInspector* frame_inspector) {
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- // First fill all parameters.
- for (int i = 0; i < scope_info->ParameterCount(); ++i) {
- // Do not materialize the parameter if it is shadowed by a context local.
- Handle<String> name(scope_info->ParameterName(i));
- if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
-
- HandleScope scope(isolate);
- Handle<Object> value(i < frame_inspector->GetParametersCount()
- ? frame_inspector->GetParameter(i)
- : isolate->heap()->undefined_value(),
- isolate);
- DCHECK(!value->IsTheHole());
-
- RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
- isolate, target, name, value, SLOPPY),
- JSObject);
- }
-
- // Second fill all stack locals.
- for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- if (scope_info->LocalIsSynthetic(i)) continue;
- Handle<String> name(scope_info->StackLocalName(i));
- Handle<Object> value(frame_inspector->GetExpression(i), isolate);
- if (value->IsTheHole()) continue;
-
- RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
- isolate, target, name, value, SLOPPY),
- JSObject);
- }
-
- return target;
-}
-
-
-static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
- Handle<JSObject> target,
- Handle<JSFunction> function,
- JavaScriptFrame* frame,
- int inlined_jsframe_index) {
- if (inlined_jsframe_index != 0 || frame->is_optimized()) {
- // Optimized frames are not supported.
- // TODO(yangguo): make sure all code deoptimized when debugger is active
- // and assert that this cannot happen.
- return;
- }
-
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- // Parameters.
- for (int i = 0; i < scope_info->ParameterCount(); ++i) {
- // Shadowed parameters were not materialized.
- Handle<String> name(scope_info->ParameterName(i));
- if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
-
- DCHECK(!frame->GetParameter(i)->IsTheHole());
- HandleScope scope(isolate);
- Handle<Object> value =
- Object::GetPropertyOrElement(target, name).ToHandleChecked();
- frame->SetParameterValue(i, *value);
- }
-
- // Stack locals.
- for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- if (scope_info->LocalIsSynthetic(i)) continue;
- if (frame->GetExpression(i)->IsTheHole()) continue;
- HandleScope scope(isolate);
- Handle<Object> value = Object::GetPropertyOrElement(
- target, handle(scope_info->StackLocalName(i),
- isolate)).ToHandleChecked();
- frame->SetExpression(i, *value);
- }
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
- Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
- JavaScriptFrame* frame) {
- HandleScope scope(isolate);
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- if (!scope_info->HasContext()) return target;
-
- // Third fill all context locals.
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->declaration_context());
- if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context,
- target)) {
- return MaybeHandle<JSObject>();
- }
-
- // Finally copy any properties from the function context extension.
- // These will be variables introduced by eval.
- if (function_context->closure() == *function) {
- if (function_context->has_extension() &&
- !function_context->IsNativeContext()) {
- Handle<JSObject> ext(JSObject::cast(function_context->extension()));
- Handle<FixedArray> keys;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
- JSObject);
-
- for (int i = 0; i < keys->length(); i++) {
- // Names of variables introduced by eval are strings.
- DCHECK(keys->get(i)->IsString());
- Handle<String> key(String::cast(keys->get(i)));
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
- RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
- isolate, target, key, value, SLOPPY),
- JSObject);
- }
- }
- }
-
- return target;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
- Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) {
- FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
- Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
-
- Handle<JSObject> local_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, local_scope,
- MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function,
- &frame_inspector),
- JSObject);
-
- return MaterializeLocalContext(isolate, local_scope, function, frame);
-}
-
-
-// Set the context local variable value.
-static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info,
- Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
- Handle<String> next_name(scope_info->ContextLocalName(i));
- if (String::Equals(variable_name, next_name)) {
- VariableMode mode;
- InitializationFlag init_flag;
- MaybeAssignedFlag maybe_assigned_flag;
- int context_index = ScopeInfo::ContextSlotIndex(
- scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
- context->set(context_index, *new_value);
- return true;
- }
- }
-
- return false;
-}
-
-
-static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
- int inlined_jsframe_index,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- if (inlined_jsframe_index != 0 || frame->is_optimized()) {
- // Optimized frames are not supported.
- return false;
- }
-
- Handle<JSFunction> function(frame->function());
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- bool default_result = false;
-
- // Parameters.
- for (int i = 0; i < scope_info->ParameterCount(); ++i) {
- HandleScope scope(isolate);
- if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
- frame->SetParameterValue(i, *new_value);
- // Argument might be shadowed in heap context, don't stop here.
- default_result = true;
- }
- }
-
- // Stack locals.
- for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- HandleScope scope(isolate);
- if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
- frame->SetExpression(i, *new_value);
- return true;
- }
- }
-
- if (scope_info->HasContext()) {
- // Context locals.
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->declaration_context());
- if (SetContextLocalValue(isolate, scope_info, function_context,
- variable_name, new_value)) {
- return true;
- }
-
- // Function context extension. These are variables introduced by eval.
- if (function_context->closure() == *function) {
- if (function_context->has_extension() &&
- !function_context->IsNativeContext()) {
- Handle<JSObject> ext(JSObject::cast(function_context->extension()));
-
- Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
- DCHECK(maybe.has_value);
- if (maybe.value) {
- // We don't expect this to do anything except replacing
- // property value.
- Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
- SLOPPY).Assert();
- return true;
- }
- }
- }
- }
-
- return default_result;
-}
-
-
-// Create a plain JSObject which materializes the closure content for the
-// context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure(
- Isolate* isolate, Handle<Context> context) {
- DCHECK(context->IsFunctionContext());
-
- Handle<SharedFunctionInfo> shared(context->closure()->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- // Allocate and initialize a JSObject with all the content of this function
- // closure.
- Handle<JSObject> closure_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- // Fill all context locals to the context extension.
- if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
- closure_scope)) {
- return MaybeHandle<JSObject>();
- }
-
- // Finally copy any properties from the function context extension. This will
- // be variables introduced by eval.
- if (context->has_extension()) {
- Handle<JSObject> ext(JSObject::cast(context->extension()));
- Handle<FixedArray> keys;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
- JSObject);
-
- for (int i = 0; i < keys->length(); i++) {
- HandleScope scope(isolate);
- // Names of variables introduced by eval are strings.
- DCHECK(keys->get(i)->IsString());
- Handle<String> key(String::cast(keys->get(i)));
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
- RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
- closure_scope, key, value, NONE),
- JSObject);
- }
- }
-
- return closure_scope;
-}
-
-
-// This method copies structure of MaterializeClosure method above.
-static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- DCHECK(context->IsFunctionContext());
-
- Handle<SharedFunctionInfo> shared(context->closure()->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- // Context locals to the context extension.
- if (SetContextLocalValue(isolate, scope_info, context, variable_name,
- new_value)) {
- return true;
- }
-
- // Properties from the function context extension. This will
- // be variables introduced by eval.
- if (context->has_extension()) {
- Handle<JSObject> ext(JSObject::cast(context->extension()));
- Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
- DCHECK(maybe.has_value);
- if (maybe.value) {
- // We don't expect this to do anything except replacing property value.
- Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE)
- .Assert();
- return true;
- }
- }
-
- return false;
-}
-
-
-// Create a plain JSObject which materializes the scope for the specified
-// catch context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope(
- Isolate* isolate, Handle<Context> context) {
- DCHECK(context->IsCatchContext());
- Handle<String> name(String::cast(context->extension()));
- Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
- isolate);
- Handle<JSObject> catch_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
- RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
- catch_scope, name, thrown_object, NONE),
- JSObject);
- return catch_scope;
-}
-
-
-static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- DCHECK(context->IsCatchContext());
- Handle<String> name(String::cast(context->extension()));
- if (!String::Equals(name, variable_name)) {
- return false;
- }
- context->set(Context::THROWN_OBJECT_INDEX, *new_value);
- return true;
-}
-
-
-// Create a plain JSObject which materializes the block scope for the specified
-// block context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope(
- Isolate* isolate, Handle<Context> context) {
- DCHECK(context->IsBlockContext());
- Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
-
- // Allocate and initialize a JSObject with all the arguments, stack locals
- // heap locals and extension properties of the debugged function.
- Handle<JSObject> block_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- // Fill all context locals.
- if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
- block_scope)) {
- return MaybeHandle<JSObject>();
- }
-
- return block_scope;
-}
-
-
-// Create a plain JSObject which materializes the module scope for the specified
-// module context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
- Isolate* isolate, Handle<Context> context) {
- DCHECK(context->IsModuleContext());
- Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
-
- // Allocate and initialize a JSObject with all the members of the debugged
- // module.
- Handle<JSObject> module_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- // Fill all context locals.
- if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
- module_scope)) {
- return MaybeHandle<JSObject>();
- }
-
- return module_scope;
-}
-
-
-// Iterate over the actual scopes visible from a stack frame or from a closure.
-// The iteration proceeds from the innermost visible nested scope outwards.
-// All scopes are backed by an actual context except the local scope,
-// which is inserted "artificially" in the context chain.
-class ScopeIterator {
- public:
- enum ScopeType {
- ScopeTypeGlobal = 0,
- ScopeTypeLocal,
- ScopeTypeWith,
- ScopeTypeClosure,
- ScopeTypeCatch,
- ScopeTypeBlock,
- ScopeTypeModule
- };
-
- ScopeIterator(Isolate* isolate, JavaScriptFrame* frame,
- int inlined_jsframe_index, bool ignore_nested_scopes = false)
- : isolate_(isolate),
- frame_(frame),
- inlined_jsframe_index_(inlined_jsframe_index),
- function_(frame->function()),
- context_(Context::cast(frame->context())),
- nested_scope_chain_(4),
- failed_(false) {
- // Catch the case when the debugger stops in an internal function.
- Handle<SharedFunctionInfo> shared_info(function_->shared());
- Handle<ScopeInfo> scope_info(shared_info->scope_info());
- if (shared_info->script() == isolate->heap()->undefined_value()) {
- while (context_->closure() == *function_) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- return;
- }
-
- // Get the debug info (create it if it does not exist).
- if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
- // Return if ensuring debug info failed.
- return;
- }
-
- // Currently it takes too much time to find nested scopes due to script
- // parsing. Sometimes we want to run the ScopeIterator as fast as possible
- // (for example, while collecting async call stacks on every
- // addEventListener call), even if we drop some nested scopes.
- // Later we may optimize getting the nested scopes (cache the result?)
- // and include nested scopes into the "fast" iteration case as well.
- if (!ignore_nested_scopes) {
- Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
-
- // Find the break point where execution has stopped.
- BreakLocationIterator break_location_iterator(debug_info,
- ALL_BREAK_LOCATIONS);
- // pc points to the instruction after the current one, possibly a break
- // location as well. So the "- 1" to exclude it from the search.
- break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
-
- // Within the return sequence at the moment it is not possible to
- // get a source position which is consistent with the current scope chain.
- // Thus all nested with, catch and block contexts are skipped and we only
- // provide the function scope.
- ignore_nested_scopes = break_location_iterator.IsExit();
- }
-
- if (ignore_nested_scopes) {
- if (scope_info->HasContext()) {
- context_ = Handle<Context>(context_->declaration_context(), isolate_);
- } else {
- while (context_->closure() == *function_) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- }
- if (scope_info->scope_type() == FUNCTION_SCOPE) {
- nested_scope_chain_.Add(scope_info);
- }
- } else {
- // Reparse the code and analyze the scopes.
- Handle<Script> script(Script::cast(shared_info->script()));
- Scope* scope = NULL;
-
- // Check whether we are in global, eval or function code.
- Handle<ScopeInfo> scope_info(shared_info->scope_info());
- if (scope_info->scope_type() != FUNCTION_SCOPE) {
- // Global or eval code.
- CompilationInfoWithZone info(script);
- if (scope_info->scope_type() == GLOBAL_SCOPE) {
- info.MarkAsGlobal();
- } else {
- DCHECK(scope_info->scope_type() == EVAL_SCOPE);
- info.MarkAsEval();
- info.SetContext(Handle<Context>(function_->context()));
- }
- if (Parser::Parse(&info) && Scope::Analyze(&info)) {
- scope = info.function()->scope();
- }
- RetrieveScopeChain(scope, shared_info);
- } else {
- // Function code
- CompilationInfoWithZone info(shared_info);
- if (Parser::Parse(&info) && Scope::Analyze(&info)) {
- scope = info.function()->scope();
- }
- RetrieveScopeChain(scope, shared_info);
- }
- }
- }
-
- ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
- : isolate_(isolate),
- frame_(NULL),
- inlined_jsframe_index_(0),
- function_(function),
- context_(function->context()),
- failed_(false) {
- if (function->IsBuiltin()) {
- context_ = Handle<Context>();
- }
- }
-
- // More scopes?
- bool Done() {
- DCHECK(!failed_);
- return context_.is_null();
- }
-
- bool Failed() { return failed_; }
-
- // Move to the next scope.
- void Next() {
- DCHECK(!failed_);
- ScopeType scope_type = Type();
- if (scope_type == ScopeTypeGlobal) {
- // The global scope is always the last in the chain.
- DCHECK(context_->IsNativeContext());
- context_ = Handle<Context>();
- return;
- }
- if (nested_scope_chain_.is_empty()) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- } else {
- if (nested_scope_chain_.last()->HasContext()) {
- DCHECK(context_->previous() != NULL);
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- nested_scope_chain_.RemoveLast();
- }
- }
-
- // Return the type of the current scope.
- ScopeType Type() {
- DCHECK(!failed_);
- if (!nested_scope_chain_.is_empty()) {
- Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
- switch (scope_info->scope_type()) {
- case FUNCTION_SCOPE:
- DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
- return ScopeTypeLocal;
- case MODULE_SCOPE:
- DCHECK(context_->IsModuleContext());
- return ScopeTypeModule;
- case GLOBAL_SCOPE:
- DCHECK(context_->IsNativeContext());
- return ScopeTypeGlobal;
- case WITH_SCOPE:
- DCHECK(context_->IsWithContext());
- return ScopeTypeWith;
- case CATCH_SCOPE:
- DCHECK(context_->IsCatchContext());
- return ScopeTypeCatch;
- case BLOCK_SCOPE:
- DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
- return ScopeTypeBlock;
- case EVAL_SCOPE:
- UNREACHABLE();
- }
- }
- if (context_->IsNativeContext()) {
- DCHECK(context_->global_object()->IsGlobalObject());
- return ScopeTypeGlobal;
- }
- if (context_->IsFunctionContext()) {
- return ScopeTypeClosure;
- }
- if (context_->IsCatchContext()) {
- return ScopeTypeCatch;
- }
- if (context_->IsBlockContext()) {
- return ScopeTypeBlock;
- }
- if (context_->IsModuleContext()) {
- return ScopeTypeModule;
- }
- DCHECK(context_->IsWithContext());
- return ScopeTypeWith;
- }
-
- // Return the JavaScript object with the content of the current scope.
- MaybeHandle<JSObject> ScopeObject() {
- DCHECK(!failed_);
- switch (Type()) {
- case ScopeIterator::ScopeTypeGlobal:
- return Handle<JSObject>(CurrentContext()->global_object());
- case ScopeIterator::ScopeTypeLocal:
- // Materialize the content of the local scope into a JSObject.
- DCHECK(nested_scope_chain_.length() == 1);
- return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
- case ScopeIterator::ScopeTypeWith:
- // Return the with object.
- return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
- case ScopeIterator::ScopeTypeCatch:
- return MaterializeCatchScope(isolate_, CurrentContext());
- case ScopeIterator::ScopeTypeClosure:
- // Materialize the content of the closure scope into a JSObject.
- return MaterializeClosure(isolate_, CurrentContext());
- case ScopeIterator::ScopeTypeBlock:
- return MaterializeBlockScope(isolate_, CurrentContext());
- case ScopeIterator::ScopeTypeModule:
- return MaterializeModuleScope(isolate_, CurrentContext());
- }
- UNREACHABLE();
- return Handle<JSObject>();
- }
-
- bool SetVariableValue(Handle<String> variable_name,
- Handle<Object> new_value) {
- DCHECK(!failed_);
- switch (Type()) {
- case ScopeIterator::ScopeTypeGlobal:
- break;
- case ScopeIterator::ScopeTypeLocal:
- return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
- variable_name, new_value);
- case ScopeIterator::ScopeTypeWith:
- break;
- case ScopeIterator::ScopeTypeCatch:
- return SetCatchVariableValue(isolate_, CurrentContext(), variable_name,
- new_value);
- case ScopeIterator::ScopeTypeClosure:
- return SetClosureVariableValue(isolate_, CurrentContext(),
- variable_name, new_value);
- case ScopeIterator::ScopeTypeBlock:
- // TODO(2399): should we implement it?
- break;
- case ScopeIterator::ScopeTypeModule:
- // TODO(2399): should we implement it?
- break;
- }
- return false;
- }
-
- Handle<ScopeInfo> CurrentScopeInfo() {
- DCHECK(!failed_);
- if (!nested_scope_chain_.is_empty()) {
- return nested_scope_chain_.last();
- } else if (context_->IsBlockContext()) {
- return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
- } else if (context_->IsFunctionContext()) {
- return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
- }
- return Handle<ScopeInfo>::null();
- }
-
- // Return the context for this scope. For the local context there might not
- // be an actual context.
- Handle<Context> CurrentContext() {
- DCHECK(!failed_);
- if (Type() == ScopeTypeGlobal || nested_scope_chain_.is_empty()) {
- return context_;
- } else if (nested_scope_chain_.last()->HasContext()) {
- return context_;
- } else {
- return Handle<Context>();
- }
- }
-
-#ifdef DEBUG
- // Debug print of the content of the current scope.
- void DebugPrint() {
- OFStream os(stdout);
- DCHECK(!failed_);
- switch (Type()) {
- case ScopeIterator::ScopeTypeGlobal:
- os << "Global:\n";
- CurrentContext()->Print(os);
- break;
-
- case ScopeIterator::ScopeTypeLocal: {
- os << "Local:\n";
- function_->shared()->scope_info()->Print();
- if (!CurrentContext().is_null()) {
- CurrentContext()->Print(os);
- if (CurrentContext()->has_extension()) {
- Handle<Object> extension(CurrentContext()->extension(), isolate_);
- if (extension->IsJSContextExtensionObject()) {
- extension->Print(os);
- }
- }
- }
- break;
- }
-
- case ScopeIterator::ScopeTypeWith:
- os << "With:\n";
- CurrentContext()->extension()->Print(os);
- break;
-
- case ScopeIterator::ScopeTypeCatch:
- os << "Catch:\n";
- CurrentContext()->extension()->Print(os);
- CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
- break;
-
- case ScopeIterator::ScopeTypeClosure:
- os << "Closure:\n";
- CurrentContext()->Print(os);
- if (CurrentContext()->has_extension()) {
- Handle<Object> extension(CurrentContext()->extension(), isolate_);
- if (extension->IsJSContextExtensionObject()) {
- extension->Print(os);
- }
- }
- break;
-
- default:
- UNREACHABLE();
- }
- PrintF("\n");
- }
-#endif
-
- private:
- Isolate* isolate_;
- JavaScriptFrame* frame_;
- int inlined_jsframe_index_;
- Handle<JSFunction> function_;
- Handle<Context> context_;
- List<Handle<ScopeInfo> > nested_scope_chain_;
- bool failed_;
-
- void RetrieveScopeChain(Scope* scope,
- Handle<SharedFunctionInfo> shared_info) {
- if (scope != NULL) {
- int source_position = shared_info->code()->SourcePosition(frame_->pc());
- scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
- } else {
- // A failed reparse indicates that the preparser has diverged from the
- // parser or that the preparse data given to the initial parse has been
- // faulty. We fail in debug mode but in release mode we only provide the
- // information we get from the context chain but nothing about
- // completely stack allocated scopes or stack allocated locals.
- // Or it could be due to stack overflow.
- DCHECK(isolate_->has_pending_exception());
- failed_ = true;
- }
- }
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
-};
-
-
-RUNTIME_FUNCTION(Runtime_GetScopeCount) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
- CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-
- // Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
- JavaScriptFrameIterator it(isolate, id);
- JavaScriptFrame* frame = it.frame();
-
- // Count the visible scopes.
- int n = 0;
- for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
- n++;
- }
-
- return Smi::FromInt(n);
-}
-
-
-// Returns the list of step-in positions (text offset) in a function of the
-// stack frame in a range from the current debug break position to the end
-// of the corresponding statement.
-RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
- CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
-
- // Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
- JavaScriptFrameIterator frame_it(isolate, id);
- RUNTIME_ASSERT(!frame_it.done());
-
- JavaScriptFrame* frame = frame_it.frame();
-
- Handle<JSFunction> fun = Handle<JSFunction>(frame->function());
- Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
-
- if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
- return isolate->heap()->undefined_value();
- }
-
- Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
-
- int len = 0;
- Handle<JSArray> array(isolate->factory()->NewJSArray(10));
- // Find the break point where execution has stopped.
- BreakLocationIterator break_location_iterator(debug_info,
- ALL_BREAK_LOCATIONS);
-
- break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
- int current_statement_pos = break_location_iterator.statement_position();
-
- while (!break_location_iterator.Done()) {
- bool accept;
- if (break_location_iterator.pc() > frame->pc()) {
- accept = true;
- } else {
- StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
- // The break point is near our pc. Could be a step-in possibility,
- // that is currently taken by active debugger call.
- if (break_frame_id == StackFrame::NO_ID) {
- // We are not stepping.
- accept = false;
- } else {
- JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
- // If our frame is a top frame and we are stepping, we can do step-in
- // at this place.
- accept = additional_frame_it.frame()->id() == id;
- }
- }
- if (accept) {
- if (break_location_iterator.IsStepInLocation(isolate)) {
- Smi* position_value = Smi::FromInt(break_location_iterator.position());
- RETURN_FAILURE_ON_EXCEPTION(
- isolate, JSObject::SetElement(
- array, len, Handle<Object>(position_value, isolate),
- NONE, SLOPPY));
- len++;
- }
- }
- // Advance iterator.
- break_location_iterator.Next();
- if (current_statement_pos != break_location_iterator.statement_position()) {
- break;
- }
- }
- return *array;
-}
-
-
-static const int kScopeDetailsTypeIndex = 0;
-static const int kScopeDetailsObjectIndex = 1;
-static const int kScopeDetailsSize = 2;
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
- Isolate* isolate, ScopeIterator* it) {
- // Calculate the size of the result.
- int details_size = kScopeDetailsSize;
- Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
-
- // Fill in scope details.
- details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
- Handle<JSObject> scope_object;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(),
- JSObject);
- details->set(kScopeDetailsObjectIndex, *scope_object);
-
- return isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-// 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(args.length() == 4);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, 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 = UnwrapFrameId(wrapped_id);
- JavaScriptFrameIterator frame_it(isolate, id);
- JavaScriptFrame* frame = frame_it.frame();
-
- // Find the requested scope.
- int n = 0;
- ScopeIterator it(isolate, frame, inlined_jsframe_index);
- for (; !it.Done() && n < index; it.Next()) {
- n++;
- }
- if (it.Done()) {
- return isolate->heap()->undefined_value();
- }
- Handle<JSObject> details;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
- return *details;
-}
-
-
-// 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]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
- CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
- CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
-
- bool ignore_nested_scopes = false;
- if (args.length() == 4) {
- CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
- ignore_nested_scopes = flag;
- }
-
- // Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
- JavaScriptFrameIterator frame_it(isolate, id);
- JavaScriptFrame* frame = frame_it.frame();
-
- List<Handle<JSObject> > result(4);
- ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
- for (; !it.Done(); it.Next()) {
- Handle<JSObject> details;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
- result.Add(details);
- }
-
- Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length());
- for (int i = 0; i < result.length(); ++i) {
- array->set(i, *result[i]);
- }
- return *isolate->factory()->NewJSArrayWithElements(array);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
-
- // Check arguments.
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
-
- // Count the visible scopes.
- int n = 0;
- for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
- n++;
- }
-
- return Smi::FromInt(n);
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
-
- // 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();
- }
-
- Handle<JSObject> details;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
- return *details;
-}
-
-
-static bool SetScopeVariableValue(ScopeIterator* it, int index,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- for (int n = 0; !it->Done() && n < index; it->Next()) {
- n++;
- }
- if (it->Done()) {
- return false;
- }
- 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
-//
-// Return true if success and false otherwise
-RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 6);
-
- // 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]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, 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 = UnwrapFrameId(wrapped_id);
- JavaScriptFrameIterator frame_it(isolate, id);
- JavaScriptFrame* frame = frame_it.frame();
-
- ScopeIterator it(isolate, frame, inlined_jsframe_index);
- res = SetScopeVariableValue(&it, index, variable_name, new_value);
- } else {
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
- ScopeIterator it(isolate, fun);
- res = SetScopeVariableValue(&it, index, variable_name, new_value);
- }
-
- return isolate->heap()->ToBoolean(res);
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
-
-#ifdef DEBUG
- // Print the scopes for the top frame.
- StackFrameLocator locator(isolate);
- JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
- for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
- it.DebugPrint();
- }
-#endif
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetThreadCount) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
- // Count all archived V8 threads.
- int n = 0;
- for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
- thread != NULL; thread = thread->Next()) {
- n++;
- }
-
- // Total number of threads is current thread and archived threads.
- return Smi::FromInt(n + 1);
-}
-
-
-static const int kThreadDetailsCurrentThreadIndex = 0;
-static const int kThreadDetailsThreadIdIndex = 1;
-static const int kThreadDetailsSize = 2;
-
-// Return an array with thread details
-// args[0]: number: break id
-// args[1]: number: thread index
-//
-// The array returned contains the following information:
-// 0: Is current thread?
-// 1: Thread id
-RUNTIME_FUNCTION(Runtime_GetThreadDetails) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
- CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
-
- // Allocate array for result.
- Handle<FixedArray> details =
- isolate->factory()->NewFixedArray(kThreadDetailsSize);
-
- // Thread index 0 is current thread.
- if (index == 0) {
- // Fill the details.
- details->set(kThreadDetailsCurrentThreadIndex,
- isolate->heap()->true_value());
- details->set(kThreadDetailsThreadIdIndex,
- Smi::FromInt(ThreadId::Current().ToInteger()));
- } else {
- // Find the thread with the requested index.
- int n = 1;
- ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse();
- while (index != n && thread != NULL) {
- thread = thread->Next();
- n++;
- }
- if (thread == NULL) {
- return isolate->heap()->undefined_value();
- }
-
- // Fill the details.
- details->set(kThreadDetailsCurrentThreadIndex,
- isolate->heap()->false_value());
- details->set(kThreadDetailsThreadIdIndex,
- Smi::FromInt(thread->id().ToInteger()));
- }
-
- // Convert to JS array and return.
- return *isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
-// Sets the disable break state
-// args[0]: disable break state
-RUNTIME_FUNCTION(Runtime_SetDisableBreak) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
- isolate->debug()->set_disable_break(disable_break);
- return isolate->heap()->undefined_value();
-}
-
-
-static bool IsPositionAlignmentCodeCorrect(int alignment) {
- return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
-
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
- CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
-
- if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
- return isolate->ThrowIllegalOperation();
- }
- BreakPositionAlignment alignment =
- static_cast<BreakPositionAlignment>(statement_aligned_code);
-
- Handle<SharedFunctionInfo> shared(fun->shared());
- // Find the number of break points
- Handle<Object> break_locations =
- Debug::GetSourceBreakLocations(shared, alignment);
- if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
- // Return array as JS array
- return *isolate->factory()->NewJSArrayWithElements(
- Handle<FixedArray>::cast(break_locations));
-}
-
-
-// Set a break point in a function.
-// args[0]: function
-// args[1]: number: break source position (within the function source)
-// args[2]: number: break point object
-RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 3);
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
- CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
- RUNTIME_ASSERT(source_position >= function->shared()->start_position() &&
- source_position <= function->shared()->end_position());
- CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
-
- // Set break point.
- RUNTIME_ASSERT(isolate->debug()->SetBreakPoint(
- function, break_point_object_arg, &source_position));
-
- return Smi::FromInt(source_position);
-}
-
-
-// Changes the state of a break point in a script and returns source position
-// where break point was set. NOTE: Regarding performance see the NOTE for
-// GetScriptFromScriptData.
-// args[0]: script to set break point in
-// args[1]: number: break source position (within the script source)
-// args[2]: number, breakpoint position alignment
-// args[3]: number: break point object
-RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 4);
- CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
- CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
- RUNTIME_ASSERT(source_position >= 0);
- CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
- CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3);
-
- if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
- return isolate->ThrowIllegalOperation();
- }
- BreakPositionAlignment alignment =
- static_cast<BreakPositionAlignment>(statement_aligned_code);
-
- // Get the script from the script wrapper.
- RUNTIME_ASSERT(wrapper->value()->IsScript());
- Handle<Script> script(Script::cast(wrapper->value()));
-
- // Set break point.
- if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
- &source_position, alignment)) {
- return isolate->heap()->undefined_value();
- }
-
- return Smi::FromInt(source_position);
-}
-
-
-// Clear a break point
-// args[0]: number: break point object
-RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
-
- // Clear break point.
- isolate->debug()->ClearBreakPoint(break_point_object_arg);
-
- return isolate->heap()->undefined_value();
-}
-
-
-// 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(args.length() == 2);
- 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) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]);
-
- ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg);
- bool result = isolate->debug()->IsBreakOnException(type);
- 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(args.length() == 4);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
- if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
- return isolate->Throw(isolate->heap()->illegal_argument_string());
- }
-
- CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
-
- StackFrame::Id frame_id;
- if (wrapped_frame_id == 0) {
- frame_id = StackFrame::NO_ID;
- } else {
- frame_id = UnwrapFrameId(wrapped_frame_id);
- }
-
- // 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 && step_action != StepInMin &&
- step_action != StepMin) {
- return isolate->Throw(isolate->heap()->illegal_argument_string());
- }
-
- if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
- step_action != StepMin && step_action != StepOut) {
- return isolate->ThrowIllegalOperation();
- }
-
- // Get the number of steps.
- int step_count = NumberToInt32(args[2]);
- if (step_count < 1) {
- 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),
- step_count, frame_id);
- return isolate->heap()->undefined_value();
-}
-
-
-// Clear all stepping set by PrepareStep.
-RUNTIME_FUNCTION(Runtime_ClearStepping) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
- isolate->debug()->ClearStepping();
- return isolate->heap()->undefined_value();
-}
-
-
-// Helper function to find or create the arguments object for
-// Runtime_DebugEvaluate.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject(
- Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function) {
- // Do not materialize the arguments object for eval or top-level code.
- // Skip if "arguments" is already taken.
- if (!function->shared()->is_function()) return target;
- Maybe<bool> maybe = JSReceiver::HasOwnProperty(
- target, isolate->factory()->arguments_string());
- if (!maybe.has_value) return MaybeHandle<JSObject>();
- if (maybe.value) return target;
-
- // FunctionGetArguments can't throw an exception.
- Handle<JSObject> arguments =
- Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
- Handle<String> arguments_str = isolate->factory()->arguments_string();
- RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty(
- target, arguments_str, arguments, NONE),
- JSObject);
- return target;
-}
-
-
-// Compile and evaluate source for the given context.
-static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
- Handle<Context> context,
- Handle<Object> context_extension,
- Handle<Object> receiver,
- Handle<String> source) {
- if (context_extension->IsJSObject()) {
- Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
- Handle<JSFunction> closure(context->closure(), isolate);
- context = isolate->factory()->NewWithContext(closure, context, extension);
- }
-
- Handle<JSFunction> eval_fun;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, eval_fun, Compiler::GetFunctionFromEval(source, context, SLOPPY,
- NO_PARSE_RESTRICTION,
- RelocInfo::kNoPosition),
- Object);
-
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
- Object);
-
- // Skip the global proxy as it has no properties and always delegates to the
- // real global object.
- if (result->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, result);
- // TODO(verwaest): This will crash when the global proxy is detached.
- result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
- }
-
- // Clear the oneshot breakpoints so that the debugger does not step further.
- isolate->debug()->ClearStepping();
- return result;
-}
-
-
-static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
- Handle<JSObject> result =
- isolate->factory()->NewJSObject(isolate->object_function());
- Handle<Map> new_map = Map::Copy(Handle<Map>(result->map()));
- new_map->set_prototype(*isolate->factory()->null_value());
- JSObject::MigrateToMap(result, new_map);
- return result;
-}
-
-
-// Evaluate a piece of JavaScript in the context of a stack frame for
-// debugging. Things that need special attention are:
-// - Parameters and stack-allocated locals need to be materialized. Altered
-// values need to be written back to the stack afterwards.
-// - The arguments object needs to materialized.
-RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
- HandleScope scope(isolate);
-
- // Check the execution state and decode arguments frame and source to be
- // evaluated.
- DCHECK(args.length() == 6);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, 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(disable_break, 4);
- CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
-
- // Handle the processing of break.
- DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
- // Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
- JavaScriptFrameIterator it(isolate, id);
- JavaScriptFrame* frame = it.frame();
- FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
- Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
-
- // Traverse the saved contexts chain to find the active context for the
- // selected frame.
- SaveContext* save = FindSavedContextForFrame(isolate, frame);
-
- SaveContext savex(isolate);
- isolate->set_context(*(save->context()));
-
- // Materialize stack locals and the arguments object.
- Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate);
-
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, materialized,
- MaterializeStackLocalsWithFrameInspector(isolate, materialized, function,
- &frame_inspector));
-
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, materialized,
- MaterializeArgumentsObject(isolate, materialized, function));
-
- // At this point, the lookup chain may look like this:
- // [inner context] -> [function stack]+[function context] -> [outer context]
- // The function stack is not an actual context, it complements the function
- // context. In order to have the same lookup chain when debug-evaluating,
- // we materialize the stack and insert it into the context chain as a
- // with-context before the function context.
- // [inner context] -> [with context] -> [function context] -> [outer context]
- // Ordering the with-context before the function context forces a dynamic
- // lookup instead of a static lookup that could fail as the scope info is
- // outdated and may expect variables to still be stack-allocated.
- // Afterwards, we write changes to the with-context back to the stack
- // and remove it from the context chain.
- // This could cause lookup failures if debug-evaluate creates a closure that
- // uses this temporary context chain.
-
- Handle<Context> eval_context(Context::cast(frame_inspector.GetContext()));
- DCHECK(!eval_context.is_null());
- Handle<Context> function_context = eval_context;
- Handle<Context> outer_context(function->context(), isolate);
- Handle<Context> inner_context;
- // We iterate to find the function's context. If the function has no
- // context-allocated variables, we iterate until we hit the outer context.
- while (!function_context->IsFunctionContext() &&
- !function_context.is_identical_to(outer_context)) {
- inner_context = function_context;
- function_context = Handle<Context>(function_context->previous(), isolate);
- }
-
- Handle<Context> materialized_context = isolate->factory()->NewWithContext(
- function, function_context, materialized);
-
- if (inner_context.is_null()) {
- // No inner context. The with-context is now inner-most.
- eval_context = materialized_context;
- } else {
- inner_context->set_previous(*materialized_context);
- }
-
- Handle<Object> receiver(frame->receiver(), isolate);
- MaybeHandle<Object> maybe_result =
- DebugEvaluate(isolate, eval_context, context_extension, receiver, source);
-
- // Remove with-context if it was inserted in between.
- if (!inner_context.is_null()) inner_context->set_previous(*function_context);
-
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
-
- // Write back potential changes to materialized stack locals to the stack.
- UpdateStackLocalsFromMaterializedObject(isolate, materialized, function,
- frame, inlined_jsframe_index);
-
- return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
- HandleScope scope(isolate);
-
- // Check the execution state and decode arguments frame and source to be
- // evaluated.
- DCHECK(args.length() == 4);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, break_id));
-
- CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
- CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
- CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
-
- // Handle the processing of break.
- DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
- // Enter the top context from before the debugger was invoked.
- SaveContext save(isolate);
- SaveContext* top = &save;
- while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
- top = top->prev();
- }
- if (top != NULL) {
- isolate->set_context(*top->context());
- }
-
- // Get the native context now set to the top context from before the
- // debugger was invoked.
- Handle<Context> context = isolate->native_context();
- Handle<JSObject> receiver(context->global_proxy());
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result,
- DebugEvaluate(isolate, context, context_extension, receiver, source));
- return *result;
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
-
- // Fill the script objects.
- Handle<FixedArray> 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);
- }
-
- // Return result as a JS array.
- Handle<JSObject> result =
- isolate->factory()->NewJSObject(isolate->array_function());
- JSArray::SetContent(Handle<JSArray>::cast(result), instances);
- return *result;
-}
-
-
-// Helper function used by Runtime_DebugReferencedBy below.
-static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
- Object* instance_filter, int max_references,
- FixedArray* instances, int instances_size,
- JSFunction* arguments_function) {
- Isolate* isolate = target->GetIsolate();
- SealHandleScope shs(isolate);
- DisallowHeapAllocation no_allocation;
-
- // Iterate the heap.
- int count = 0;
- JSObject* last = NULL;
- HeapObject* heap_obj = NULL;
- while (((heap_obj = iterator->next()) != NULL) &&
- (max_references == 0 || count < max_references)) {
- // Only look at all JSObjects.
- if (heap_obj->IsJSObject()) {
- // Skip context extension objects and argument arrays as these are
- // checked in the context of functions using them.
- JSObject* obj = JSObject::cast(heap_obj);
- if (obj->IsJSContextExtensionObject() ||
- obj->map()->constructor() == arguments_function) {
- continue;
- }
-
- // Check if the JS object has a reference to the object looked for.
- if (obj->ReferencesObject(target)) {
- // Check instance filter if supplied. This is normally used to avoid
- // references from mirror objects (see Runtime_IsInPrototypeChain).
- if (!instance_filter->IsUndefined()) {
- for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
- iter.Advance()) {
- if (iter.GetCurrent() == instance_filter) {
- obj = NULL; // Don't add this object.
- break;
- }
- }
- }
-
- if (obj != NULL) {
- // Valid reference found add to instance array if supplied an update
- // count.
- if (instances != NULL && count < instances_size) {
- instances->set(count, obj);
- }
- last = obj;
- count++;
- }
- }
- }
- }
-
- // 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.
- if (count == 1 && last == target) {
- count = 0;
- }
-
- // Return the number of referencing objects found.
- return count;
-}
-
-
-// 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(args.length() == 3);
-
- // Check parameters.
- CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
- RUNTIME_ASSERT(instance_filter->IsUndefined() ||
- instance_filter->IsJSObject());
- CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
- RUNTIME_ASSERT(max_references >= 0);
-
-
- // Get the constructor function for context extension and arguments array.
- Handle<JSFunction> arguments_function(
- JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
-
- // Get the number of referencing objects.
- int count;
- // First perform a full GC in order to avoid dead objects and to make the heap
- // iterable.
- Heap* heap = isolate->heap();
- heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
- {
- HeapIterator heap_iterator(heap);
- count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
- max_references, NULL, 0, *arguments_function);
- }
-
- // Allocate an array to hold the result.
- Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
- // Fill the referencing objects.
- {
- HeapIterator heap_iterator(heap);
- count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
- max_references, *instances, count,
- *arguments_function);
- }
-
- // Return result as JS array.
- Handle<JSFunction> constructor = isolate->array_function();
-
- Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
- JSArray::SetContent(Handle<JSArray>::cast(result), instances);
- return *result;
-}
-
-
-// Helper function used by Runtime_DebugConstructedBy below.
-static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
- int max_references, FixedArray* instances,
- int instances_size) {
- DisallowHeapAllocation no_allocation;
-
- // Iterate the heap.
- int count = 0;
- HeapObject* heap_obj = NULL;
- while (((heap_obj = iterator->next()) != NULL) &&
- (max_references == 0 || count < max_references)) {
- // Only look at all JSObjects.
- if (heap_obj->IsJSObject()) {
- JSObject* obj = JSObject::cast(heap_obj);
- if (obj->map()->constructor() == constructor) {
- // Valid reference found add to instance array if supplied an update
- // count.
- if (instances != NULL && count < instances_size) {
- instances->set(count, obj);
- }
- count++;
- }
- }
- }
-
- // Return the number of referencing objects found.
- return count;
-}
-
-
-// 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(args.length() == 2);
-
-
- // Check parameters.
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
- CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
- RUNTIME_ASSERT(max_references >= 0);
-
- // Get the number of referencing objects.
- int count;
- // First perform a full GC in order to avoid dead objects and to make the heap
- // iterable.
- Heap* heap = isolate->heap();
- heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
- {
- HeapIterator heap_iterator(heap);
- count = DebugConstructedBy(&heap_iterator, *constructor, max_references,
- NULL, 0);
- }
-
- // Allocate an array to hold the result.
- Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
- // Fill the referencing objects.
- {
- HeapIterator heap_iterator2(heap);
- count = DebugConstructedBy(&heap_iterator2, *constructor, max_references,
- *instances, count);
- }
-
- // Return result as JS array.
- Handle<JSFunction> array_function = isolate->array_function();
- Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
- JSArray::SetContent(Handle<JSArray>::cast(result), instances);
- return *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(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
- return *GetPrototypeSkipHiddenPrototypes(isolate, obj);
-}
-
-
-// Patches script source (should be called upon BeforeCompile event).
-RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
-
- CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
- CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
-
- RUNTIME_ASSERT(script_wrapper->value()->IsScript());
- Handle<Script> script(Script::cast(script_wrapper->value()));
-
- int compilation_state = script->compilation_state();
- RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
- script->set_source(*source);
-
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) {
- HandleScope scope(isolate);
-#ifdef DEBUG
- DCHECK(args.length() == 1);
- // Get the function and make sure it is compiled.
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
- if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
- return isolate->heap()->exception();
- }
- OFStream os(stdout);
- func->code()->Print(os);
- os << endl;
-#endif // DEBUG
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) {
- HandleScope scope(isolate);
-#ifdef DEBUG
- DCHECK(args.length() == 1);
- // Get the function and make sure it is compiled.
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
- if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
- return isolate->heap()->exception();
- }
- OFStream os(stdout);
- func->shared()->construct_stub()->Print(os);
- os << endl;
-#endif // DEBUG
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 1);
-
- CONVERT_ARG_CHECKED(JSFunction, f, 0);
- return f->shared()->inferred_name();
-}
-
-
-static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
- Script* script,
- FixedArray* buffer) {
- DisallowHeapAllocation no_allocation;
- int counter = 0;
- int buffer_size = buffer->length();
- for (HeapObject* obj = iterator->next(); obj != NULL;
- obj = iterator->next()) {
- DCHECK(obj != NULL);
- if (!obj->IsSharedFunctionInfo()) {
- continue;
- }
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
- if (shared->script() != script) {
- continue;
- }
- if (counter < buffer_size) {
- buffer->set(counter, shared);
- }
- counter++;
- }
- return counter;
-}
-
-
-// For a script finds all SharedFunctionInfo's in the heap that points
-// to this script. Returns JSArray of SharedFunctionInfo wrapped
-// in OpaqueReferences.
-RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 1);
- CONVERT_ARG_CHECKED(JSValue, script_value, 0);
-
- RUNTIME_ASSERT(script_value->value()->IsScript());
- Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
-
- const int kBufferSize = 32;
-
- Handle<FixedArray> array;
- array = isolate->factory()->NewFixedArray(kBufferSize);
- int number;
- Heap* heap = isolate->heap();
- {
- HeapIterator heap_iterator(heap);
- Script* scr = *script;
- FixedArray* arr = *array;
- number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
- }
- if (number > kBufferSize) {
- array = isolate->factory()->NewFixedArray(number);
- HeapIterator heap_iterator(heap);
- Script* scr = *script;
- FixedArray* arr = *array;
- FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
- }
-
- Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
- result->set_length(Smi::FromInt(number));
-
- LiveEdit::WrapSharedFunctionInfos(result);
-
- return *result;
-}
-
-
-// For a script calculates compilation information about all its functions.
-// The script source is explicitly specified by the second argument.
-// The source of the actual script is not used, however it is important that
-// all generated code keeps references to this particular instance of script.
-// Returns a JSArray of compilation infos. The array is ordered so that
-// each function with all its descendant is always stored in a continues range
-// with the function itself going first. The root function is a script function.
-RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_ARG_CHECKED(JSValue, script, 0);
- CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
-
- RUNTIME_ASSERT(script->value()->IsScript());
- Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
-
- Handle<JSArray> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result, LiveEdit::GatherCompileInfo(script_handle, source));
- return *result;
-}
-
-
-// Changes the source of the script to a new_source.
-// If old_script_name is provided (i.e. is a String), also creates a copy of
-// the script with its original source and sends notification to debugger.
-RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 3);
- CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
- CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
- CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
-
- RUNTIME_ASSERT(original_script_value->value()->IsScript());
- Handle<Script> original_script(Script::cast(original_script_value->value()));
-
- Handle<Object> old_script = LiveEdit::ChangeScriptSource(
- original_script, new_source, old_script_name);
-
- if (old_script->IsScript()) {
- Handle<Script> script_handle = Handle<Script>::cast(old_script);
- return *Script::GetWrapper(script_handle);
- } else {
- return isolate->heap()->null_value();
- }
-}
-
-
-RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
- RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
-
- LiveEdit::FunctionSourceUpdated(shared_info);
- return isolate->heap()->undefined_value();
-}
-
-
-// Replaces code of SharedFunctionInfo with a new one.
-RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
- RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
-
- LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
- return isolate->heap()->undefined_value();
-}
-
-
-// Connects SharedFunctionInfo to another script.
-RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
-
- if (function_object->IsJSValue()) {
- Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
- if (script_object->IsJSValue()) {
- RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
- Script* script = Script::cast(JSValue::cast(*script_object)->value());
- script_object = Handle<Object>(script, isolate);
- }
- RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo());
- LiveEdit::SetFunctionScript(function_wrapper, script_object);
- } else {
- // Just ignore this. We may not have a SharedFunctionInfo for some functions
- // and we check it in this function.
- }
-
- return isolate->heap()->undefined_value();
-}
-
-
-// In a code of a parent function replaces original function as embedded object
-// with a substitution one.
-RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 3);
-
- CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
- CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
- RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo());
- RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo());
- RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo());
-
- LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
- subst_wrapper);
- return isolate->heap()->undefined_value();
-}
-
-
-// Updates positions of a shared function info (first parameter) according
-// to script source change. Text change is described in second parameter as
-// array of groups of 3 numbers:
-// (change_begin, change_end, change_end_new_position).
-// Each group describes a change in text; groups are sorted by change_begin.
-RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
- RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array))
-
- LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
- return isolate->heap()->undefined_value();
-}
-
-
-// For array of SharedFunctionInfo's (each wrapped in JSValue)
-// checks that none of them have activations on stacks (of any thread).
-// Returns array of the same length with corresponding results of
-// LiveEdit::FunctionPatchabilityStatus type.
-RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
- CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
- RUNTIME_ASSERT(shared_array->length()->IsSmi());
- RUNTIME_ASSERT(shared_array->HasFastElements())
- int array_length = Smi::cast(shared_array->length())->value();
- for (int i = 0; i < array_length; i++) {
- Handle<Object> element =
- Object::GetElement(isolate, shared_array, i).ToHandleChecked();
- RUNTIME_ASSERT(
- element->IsJSValue() &&
- Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo());
- }
-
- return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
-}
-
-
-// Compares 2 strings line-by-line, then token-wise and returns diff in form
-// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
-// of diff chunks.
-RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
- CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
-
- return *LiveEdit::CompareStrings(s1, s2);
-}
-
-
-// Restarts a call frame and completely drops all frames above.
-// Returns true if successful. Otherwise returns undefined or an error message.
-RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
- RUNTIME_ASSERT(CheckExecutionState(isolate, 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();
- }
-
- JavaScriptFrameIterator it(isolate, id);
- int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index);
- if (inlined_jsframe_index == -1) return heap->undefined_value();
- // We don't really care what the inlined frame index is, since we are
- // throwing away the entire frame anyways.
- const char* error_message = LiveEdit::RestartFrame(it.frame());
- if (error_message) {
- return *(isolate->factory()->InternalizeUtf8String(error_message));
- }
- return heap->true_value();
-}
-
-
-// A testing entry. Returns statement position which is the closest to
-// source_position.
-RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) {
- HandleScope scope(isolate);
- CHECK(isolate->debug()->live_edit_enabled());
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
- CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
-
- Handle<Code> code(function->code(), isolate);
-
- if (code->kind() != Code::FUNCTION &&
- code->kind() != Code::OPTIMIZED_FUNCTION) {
- return isolate->heap()->undefined_value();
- }
-
- RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
- int closest_pc = 0;
- int distance = kMaxInt;
- while (!it.done()) {
- int statement_position = static_cast<int>(it.rinfo()->data());
- // Check if this break point is closer that what was previously found.
- if (source_position <= statement_position &&
- statement_position - source_position < distance) {
- closest_pc =
- static_cast<int>(it.rinfo()->pc() - code->instruction_start());
- distance = statement_position - source_position;
- // Check whether we can't get any closer.
- if (distance == 0) break;
- }
- it.next();
- }
-
- return Smi::FromInt(closest_pc);
-}
-
-
-// Calls specified function with or without entering the debugger.
-// This is used in unit tests to run code as if debugger is entered or simply
-// to have a stack with C++ frame in the middle.
-RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
- CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
-
- MaybeHandle<Object> maybe_result;
- if (without_debugger) {
- maybe_result = Execution::Call(isolate, function,
- handle(function->global_proxy()), 0, NULL);
- } else {
- DebugScope debug_scope(isolate->debug());
- maybe_result = Execution::Call(isolate, function,
- handle(function->global_proxy()), 0, NULL);
- }
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
- return *result;
-}
-
-
-// Performs a GC.
-// Presently, it only does a full GC.
-RUNTIME_FUNCTION(Runtime_CollectGarbage) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 1);
- isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
- return isolate->heap()->undefined_value();
-}
-
-
-// Gets the current heap usage.
-RUNTIME_FUNCTION(Runtime_GetHeapUsage) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 0);
- int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
- if (!Smi::IsValid(usage)) {
- return *isolate->factory()->NewNumberFromInt(usage);
- }
- 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.
-static Handle<Object> Runtime_GetScriptFromScriptName(
- Handle<String> script_name) {
- // Scan the heap for Script objects to find the script with the requested
- // script data.
- Handle<Script> script;
- Factory* factory = script_name->GetIsolate()->factory();
- Heap* heap = script_name->GetHeap();
- HeapIterator iterator(heap);
- HeapObject* obj = NULL;
- while (script.is_null() && ((obj = iterator.next()) != NULL)) {
- // If a script is found check if it has the script data requested.
- if (obj->IsScript()) {
- if (Script::cast(obj)->name()->IsString()) {
- if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
- script = Handle<Script>(Script::cast(obj));
- }
- }
- }
- }
-
- // If no script with the requested script data is found return undefined.
- if (script.is_null()) return factory->undefined_value();
-
- // Return the script found.
- return Script::GetWrapper(script);
-}
-
-
-// Get the script object from script data. NOTE: Regarding performance
-// see the NOTE for GetScriptFromScriptData.
-// args[0]: script data for the script to find the source for
-RUNTIME_FUNCTION(Runtime_GetScript) {
- HandleScope scope(isolate);
-
- DCHECK(args.length() == 1);
-
- CONVERT_ARG_CHECKED(String, script_name, 0);
-
- // Find the requested script.
- Handle<Object> result =
- Runtime_GetScriptFromScriptName(Handle<String>(script_name));
- return *result;
-}
-
-
-// Collect the raw data for a stack trace. Returns an array of 4
-// element segments each containing a receiver, function, code and
-// native code offset.
-RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
-
- if (!isolate->bootstrapper()->IsActive()) {
- // Optionally capture a more detailed stack trace for the message.
- isolate->CaptureAndSetDetailedStackTrace(error_object);
- // Capture a simple stack trace for the stack property.
- isolate->CaptureAndSetSimpleStackTrace(error_object, caller);
- }
- return isolate->heap()->undefined_value();
-}
-
-
-// Returns V8 version as a string.
-RUNTIME_FUNCTION(Runtime_GetV8Version) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
-
- const char* version_string = v8::V8::GetVersion();
-
- return *isolate->factory()->NewStringFromAsciiChecked(version_string);
-}
-
-
-// Returns function of generator activation.
-RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
- return generator->function();
-}
-
-
-// Returns context of generator activation.
-RUNTIME_FUNCTION(Runtime_GeneratorGetContext) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
- return generator->context();
-}
-
-
-// Returns receiver of generator activation.
-RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
- return generator->receiver();
-}
-
-
-// Returns generator continuation as a PC offset, or the magic -1 or 0 values.
-RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
- return Smi::FromInt(generator->continuation());
-}
-
-
-RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
-
- if (generator->is_suspended()) {
- Handle<Code> code(generator->function()->code(), isolate);
- int offset = generator->continuation();
-
- RUNTIME_ASSERT(0 <= offset && offset < code->Size());
- Address pc = code->address() + offset;
-
- return Smi::FromInt(code->SourcePosition(pc));
- }
-
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
- CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
- RUNTIME_ASSERT((index->value() & 1) == 1);
- FieldIndex field_index =
- FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
- if (field_index.is_inobject()) {
- RUNTIME_ASSERT(field_index.property_index() <
- object->map()->inobject_properties());
- } else {
- RUNTIME_ASSERT(field_index.outobject_array_index() <
- object->properties()->length());
- }
- Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
- RUNTIME_ASSERT(raw_value->IsMutableHeapNumber());
- return *Object::WrapForRead(isolate, raw_value, Representation::Double());
-}
-
-
-RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
- if (!object->IsJSObject()) return Smi::FromInt(0);
- Handle<JSObject> js_object = Handle<JSObject>::cast(object);
- if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
- // This call must not cause lazy deopts, because it's called from deferred
- // code where we can't handle lazy deopts for lack of a suitable bailout
- // ID. So we just try migration and signal failure if necessary,
- // which will also trigger a deopt.
- if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
- return *object;
-}
-
-
-RUNTIME_FUNCTION(Runtime_GetFromCache) {
- SealHandleScope shs(isolate);
- // This is only called from codegen, so checks might be more lax.
- CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
- CONVERT_ARG_CHECKED(Object, key, 1);
-
- {
- DisallowHeapAllocation no_alloc;
-
- int finger_index = cache->finger_index();
- Object* o = cache->get(finger_index);
- if (o == key) {
- // The fastest case: hit the same place again.
- return cache->get(finger_index + 1);
- }
-
- for (int i = finger_index - 2; i >= JSFunctionResultCache::kEntriesIndex;
- i -= 2) {
- o = cache->get(i);
- if (o == key) {
- cache->set_finger_index(i);
- return cache->get(i + 1);
- }
- }
-
- int size = cache->size();
- DCHECK(size <= cache->length());
-
- for (int i = size - 2; i > finger_index; i -= 2) {
- o = cache->get(i);
- if (o == key) {
- cache->set_finger_index(i);
- return cache->get(i + 1);
- }
- }
- }
-
- // There is no value in the cache. Invoke the function and cache result.
+ // There is no value in the cache. Invoke the function and cache result.
HandleScope scope(isolate);
Handle<JSFunctionResultCache> cache_handle(cache);
}
-#ifdef DEBUG
-// ListNatives is ONLY used by the fuzz-natives.js in debug mode
-// Exclude the code in release mode.
-RUNTIME_FUNCTION(Runtime_ListNatives) {
- HandleScope scope(isolate);
- DCHECK(args.length() == 0);
-#define COUNT_ENTRY(Name, argc, ressize) +1
- int entry_count =
- 0 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) INLINE_FUNCTION_LIST(COUNT_ENTRY)
- INLINE_OPTIMIZED_FUNCTION_LIST(COUNT_ENTRY);
-#undef COUNT_ENTRY
- Factory* factory = isolate->factory();
- Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
- int index = 0;
- bool inline_runtime_functions = false;
-#define ADD_ENTRY(Name, argc, ressize) \
- { \
- HandleScope inner(isolate); \
- Handle<String> name; \
- /* Inline runtime functions have an underscore in front of the name. */ \
- if (inline_runtime_functions) { \
- name = factory->NewStringFromStaticChars("_" #Name); \
- } else { \
- name = factory->NewStringFromStaticChars(#Name); \
- } \
- Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
- pair_elements->set(0, *name); \
- pair_elements->set(1, Smi::FromInt(argc)); \
- Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
- elements->set(index++, *pair); \
- }
- inline_runtime_functions = false;
- RUNTIME_FUNCTION_LIST(ADD_ENTRY)
- INLINE_OPTIMIZED_FUNCTION_LIST(ADD_ENTRY)
- inline_runtime_functions = true;
- INLINE_FUNCTION_LIST(ADD_ENTRY)
-#undef ADD_ENTRY
- DCHECK_EQ(index, entry_count);
- Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
- return *result;
-}
-#endif
-
-
RUNTIME_FUNCTION(Runtime_IS_VAR) {
UNREACHABLE(); // implemented as macro in the parser
return NULL;
}
-#define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \
- RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \
- CONVERT_ARG_CHECKED(JSObject, obj, 0); \
- return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \
- }
-
-TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
-
-#undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
-
-
-#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
- RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \
- CONVERT_ARG_CHECKED(JSObject, obj, 0); \
- return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
- }
-
-TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
-
-#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
-
-
RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
}
-RUNTIME_FUNCTION(RuntimeReference_DateField) {
- SealHandleScope shs(isolate);
- DCHECK(args.length() == 2);
- CONVERT_ARG_CHECKED(Object, obj, 0);
- CONVERT_SMI_ARG_CHECKED(index, 1);
- if (!obj->IsJSDate()) {
- HandleScope scope(isolate);
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate,
- NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
- }
- JSDate* date = JSDate::cast(obj);
- if (index == 0) return date->value();
- return JSDate::GetField(date, Smi::FromInt(index));
-}
-
-
RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
}
-RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) {
- UNREACHABLE(); // Optimization disabled in SetUpGenerators().
- return NULL;
-}
-
-
-RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) {
- UNREACHABLE(); // Optimization disabled in SetUpGenerators().
- return NULL;
-}
-
-
RUNTIME_FUNCTION(RuntimeReference_ClassOf) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
}
-RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) {
- SealHandleScope shs(isolate);
- return Smi::FromInt(isolate->debug()->is_active());
-}
-
-
// ----------------------------------------------------------------------------
// Implementation of Runtime