Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1125)

Unified Diff: src/runtime/runtime-scopes.cc

Issue 612383002: Split yet more runtime functions into separate files. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/runtime/runtime-regexp.cc ('k') | src/runtime/runtime-symbol.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/runtime/runtime-scopes.cc
diff --git a/src/runtime/runtime-scopes.cc b/src/runtime/runtime-scopes.cc
new file mode 100644
index 0000000000000000000000000000000000000000..454536996ab5c766c92e6822658b79eae1bad917
--- /dev/null
+++ b/src/runtime/runtime-scopes.cc
@@ -0,0 +1,1029 @@
+// 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/frames-inl.h"
+#include "src/runtime/runtime.h"
+#include "src/runtime/runtime-utils.h"
+#include "src/scopeinfo.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
+ HandleScope scope(isolate);
+ Handle<Object> args[1] = {name};
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewTypeError("var_redeclaration", HandleVector(args, 1)));
+}
+
+
+// May throw a RedeclarationError.
+static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
+ Handle<String> name, Handle<Object> value,
+ PropertyAttributes attr, bool is_var,
+ bool is_const, bool is_function) {
+ // Do the lookup own properties only, see ES5 erratum.
+ LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ if (!maybe.has_value) return isolate->heap()->exception();
+
+ if (it.IsFound()) {
+ PropertyAttributes old_attributes = maybe.value;
+ // The name was declared before; check for conflicting re-declarations.
+ if (is_const) return ThrowRedeclarationError(isolate, name);
+
+ // Skip var re-declarations.
+ if (is_var) return isolate->heap()->undefined_value();
+
+ DCHECK(is_function);
+ if ((old_attributes & DONT_DELETE) != 0) {
+ // Only allow reconfiguring globals to functions in user code (no
+ // natives, which are marked as read-only).
+ DCHECK((attr & READ_ONLY) == 0);
+
+ // Check whether we can reconfigure the existing property into a
+ // function.
+ PropertyDetails old_details = it.property_details();
+ // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo,
+ // which are actually data properties, not accessor properties.
+ if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
+ old_details.type() == CALLBACKS) {
+ return ThrowRedeclarationError(isolate, name);
+ }
+ // If the existing property is not configurable, keep its attributes. Do
+ attr = old_attributes;
+ }
+ }
+
+ // Define or redefine own property.
+ RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+ global, name, value, attr));
+
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ Handle<GlobalObject> global(isolate->global_object());
+
+ CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
+ CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
+ CONVERT_SMI_ARG_CHECKED(flags, 2);
+
+ // Traverse the name/value pairs and set the properties.
+ int length = pairs->length();
+ for (int i = 0; i < length; i += 2) {
+ HandleScope scope(isolate);
+ Handle<String> name(String::cast(pairs->get(i)));
+ Handle<Object> initial_value(pairs->get(i + 1), isolate);
+
+ // We have to declare a global const property. To capture we only
+ // assign to it when evaluating the assignment for "const x =
+ // <expr>" the initial value is the hole.
+ bool is_var = initial_value->IsUndefined();
+ bool is_const = initial_value->IsTheHole();
+ bool is_function = initial_value->IsSharedFunctionInfo();
+ DCHECK(is_var + is_const + is_function == 1);
+
+ Handle<Object> value;
+ if (is_function) {
+ // Copy the function and update its context. Use it as value.
+ Handle<SharedFunctionInfo> shared =
+ Handle<SharedFunctionInfo>::cast(initial_value);
+ Handle<JSFunction> function =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
+ TENURED);
+ value = function;
+ } else {
+ value = isolate->factory()->undefined_value();
+ }
+
+ // Compute the property attributes. According to ECMA-262,
+ // the property must be non-configurable except in eval.
+ bool is_native = DeclareGlobalsNativeFlag::decode(flags);
+ bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
+ int attr = NONE;
+ if (is_const) attr |= READ_ONLY;
+ if (is_function && is_native) attr |= READ_ONLY;
+ if (!is_const && !is_eval) attr |= DONT_DELETE;
+
+ Object* result = DeclareGlobals(isolate, global, name, value,
+ static_cast<PropertyAttributes>(attr),
+ is_var, is_const, is_function);
+ if (isolate->has_pending_exception()) return result;
+ }
+
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
+ HandleScope scope(isolate);
+ // args[0] == name
+ // args[1] == language_mode
+ // args[2] == value (optional)
+
+ // Determine if we need to assign to the variable if it already
+ // exists (based on the number of arguments).
+ RUNTIME_ASSERT(args.length() == 3);
+
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+ CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
+
+ Handle<GlobalObject> global(isolate->context()->global_object());
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result, Object::SetProperty(global, name, value, strict_mode));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
+ HandleScope handle_scope(isolate);
+ // All constants are declared with an initial value. The name
+ // of the constant is the first argument and the initial value
+ // is the second.
+ RUNTIME_ASSERT(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
+
+ Handle<GlobalObject> global = isolate->global_object();
+
+ // Lookup the property as own on the global object.
+ LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ DCHECK(maybe.has_value);
+ PropertyAttributes old_attributes = maybe.value;
+
+ PropertyAttributes attr =
+ static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
+ // Set the value if the property is either missing, or the property attributes
+ // allow setting the value without invoking an accessor.
+ if (it.IsFound()) {
+ // Ignore if we can't reconfigure the value.
+ if ((old_attributes & DONT_DELETE) != 0) {
+ if ((old_attributes & READ_ONLY) != 0 ||
+ it.state() == LookupIterator::ACCESSOR) {
+ return *value;
+ }
+ attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
+ }
+ }
+
+ RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+ global, name, value, attr));
+
+ return *value;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 4);
+
+ // Declarations are always made in a function, native, or global context. In
+ // the case of eval code, the context passed is the context of the caller,
+ // which may be some nested context and not the declaration context.
+ CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
+ Handle<Context> context(context_arg->declaration_context());
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
+ CONVERT_SMI_ARG_CHECKED(attr_arg, 2);
+ PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg);
+ RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE);
+ CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
+
+ // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
+ bool is_var = *initial_value == NULL;
+ bool is_const = initial_value->IsTheHole();
+ bool is_function = initial_value->IsJSFunction();
+ DCHECK(is_var + is_const + is_function == 1);
+
+ int index;
+ PropertyAttributes attributes;
+ ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+ BindingFlags binding_flags;
+ Handle<Object> holder =
+ context->Lookup(name, flags, &index, &attributes, &binding_flags);
+
+ Handle<JSObject> object;
+ Handle<Object> value =
+ is_function ? initial_value
+ : Handle<Object>::cast(isolate->factory()->undefined_value());
+
+ // TODO(verwaest): This case should probably not be covered by this function,
+ // but by DeclareGlobals instead.
+ if ((attributes != ABSENT && holder->IsJSGlobalObject()) ||
+ (context_arg->has_extension() &&
+ context_arg->extension()->IsJSGlobalObject())) {
+ return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
+ value, attr, is_var, is_const, is_function);
+ }
+
+ if (attributes != ABSENT) {
+ // The name was declared before; check for conflicting re-declarations.
+ if (is_const || (attributes & READ_ONLY) != 0) {
+ return ThrowRedeclarationError(isolate, name);
+ }
+
+ // Skip var re-declarations.
+ if (is_var) return isolate->heap()->undefined_value();
+
+ DCHECK(is_function);
+ if (index >= 0) {
+ DCHECK(holder.is_identical_to(context));
+ context->set(index, *initial_value);
+ return isolate->heap()->undefined_value();
+ }
+
+ object = Handle<JSObject>::cast(holder);
+
+ } else if (context->has_extension()) {
+ object = handle(JSObject::cast(context->extension()));
+ DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
+ } else {
+ DCHECK(context->IsFunctionContext());
+ object =
+ isolate->factory()->NewJSObject(isolate->context_extension_function());
+ context->set_extension(*object);
+ }
+
+ RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+ object, name, value, attr));
+
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
+ DCHECK(!value->IsTheHole());
+ // Initializations are always done in a function or native context.
+ CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
+ Handle<Context> context(context_arg->declaration_context());
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
+
+ int index;
+ PropertyAttributes attributes;
+ ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
+ BindingFlags binding_flags;
+ Handle<Object> holder =
+ context->Lookup(name, flags, &index, &attributes, &binding_flags);
+
+ if (index >= 0) {
+ DCHECK(holder->IsContext());
+ // Property was found in a context. Perform the assignment if the constant
+ // was uninitialized.
+ Handle<Context> context = Handle<Context>::cast(holder);
+ DCHECK((attributes & READ_ONLY) != 0);
+ if (context->get(index)->IsTheHole()) context->set(index, *value);
+ return *value;
+ }
+
+ PropertyAttributes attr =
+ static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
+
+ // Strict mode handling not needed (legacy const is disallowed in strict
+ // mode).
+
+ // The declared const was configurable, and may have been deleted in the
+ // meanwhile. If so, re-introduce the variable in the context extension.
+ DCHECK(context_arg->has_extension());
+ if (attributes == ABSENT) {
+ holder = handle(context_arg->extension(), isolate);
+ } else {
+ // For JSContextExtensionObjects, the initializer can be run multiple times
+ // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
+ // first assignment should go through. For JSGlobalObjects, additionally any
+ // code can run in between that modifies the declared property.
+ DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
+
+ LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ if (!maybe.has_value) return isolate->heap()->exception();
+ PropertyAttributes old_attributes = maybe.value;
+
+ // Ignore if we can't reconfigure the value.
+ if ((old_attributes & DONT_DELETE) != 0) {
+ if ((old_attributes & READ_ONLY) != 0 ||
+ it.state() == LookupIterator::ACCESSOR) {
+ return *value;
+ }
+ attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
+ }
+ }
+
+ RETURN_FAILURE_ON_EXCEPTION(
+ isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+ Handle<JSObject>::cast(holder), name, value, attr));
+
+ return *value;
+}
+
+
+static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
+ Handle<JSFunction> callee,
+ Object** parameters,
+ int argument_count) {
+ Handle<JSObject> result =
+ isolate->factory()->NewArgumentsObject(callee, argument_count);
+
+ // Allocate the elements if needed.
+ int parameter_count = callee->shared()->formal_parameter_count();
+ if (argument_count > 0) {
+ if (parameter_count > 0) {
+ int mapped_count = Min(argument_count, parameter_count);
+ Handle<FixedArray> parameter_map =
+ isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
+ parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
+
+ Handle<Map> map = Map::Copy(handle(result->map()));
+ map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
+
+ result->set_map(*map);
+ result->set_elements(*parameter_map);
+
+ // Store the context and the arguments array at the beginning of the
+ // parameter map.
+ Handle<Context> context(isolate->context());
+ Handle<FixedArray> arguments =
+ isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
+ parameter_map->set(0, *context);
+ parameter_map->set(1, *arguments);
+
+ // Loop over the actual parameters backwards.
+ int index = argument_count - 1;
+ while (index >= mapped_count) {
+ // These go directly in the arguments array and have no
+ // corresponding slot in the parameter map.
+ arguments->set(index, *(parameters - index - 1));
+ --index;
+ }
+
+ Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
+ while (index >= 0) {
+ // Detect duplicate names to the right in the parameter list.
+ Handle<String> name(scope_info->ParameterName(index));
+ int context_local_count = scope_info->ContextLocalCount();
+ bool duplicate = false;
+ for (int j = index + 1; j < parameter_count; ++j) {
+ if (scope_info->ParameterName(j) == *name) {
+ duplicate = true;
+ break;
+ }
+ }
+
+ if (duplicate) {
+ // This goes directly in the arguments array with a hole in the
+ // parameter map.
+ arguments->set(index, *(parameters - index - 1));
+ parameter_map->set_the_hole(index + 2);
+ } else {
+ // The context index goes in the parameter map with a hole in the
+ // arguments array.
+ int context_index = -1;
+ for (int j = 0; j < context_local_count; ++j) {
+ if (scope_info->ContextLocalName(j) == *name) {
+ context_index = j;
+ break;
+ }
+ }
+ DCHECK(context_index >= 0);
+ arguments->set_the_hole(index);
+ parameter_map->set(
+ index + 2,
+ Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
+ }
+
+ --index;
+ }
+ } else {
+ // If there is no aliasing, the arguments object elements are not
+ // special in any way.
+ Handle<FixedArray> elements =
+ isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
+ result->set_elements(*elements);
+ for (int i = 0; i < argument_count; ++i) {
+ elements->set(i, *(parameters - i - 1));
+ }
+ }
+ }
+ return result;
+}
+
+
+static Handle<JSObject> NewStrictArguments(Isolate* isolate,
+ Handle<JSFunction> callee,
+ Object** parameters,
+ int argument_count) {
+ Handle<JSObject> result =
+ isolate->factory()->NewArgumentsObject(callee, argument_count);
+
+ if (argument_count > 0) {
+ Handle<FixedArray> array =
+ isolate->factory()->NewUninitializedFixedArray(argument_count);
+ DisallowHeapAllocation no_gc;
+ WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
+ for (int i = 0; i < argument_count; i++) {
+ array->set(i, *--parameters, mode);
+ }
+ result->set_elements(*array);
+ }
+ return result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewArguments) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
+ JavaScriptFrameIterator it(isolate);
+
+ // Find the frame that holds the actual arguments passed to the function.
+ it.AdvanceToArgumentsFrame();
+ JavaScriptFrame* frame = it.frame();
+
+ // Determine parameter location on the stack and dispatch on language mode.
+ int argument_count = frame->GetArgumentsLength();
+ Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
+ return callee->shared()->strict_mode() == STRICT
+ ? *NewStrictArguments(isolate, callee, parameters, argument_count)
+ : *NewSloppyArguments(isolate, callee, parameters, argument_count);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
+ Object** parameters = reinterpret_cast<Object**>(args[1]);
+ CONVERT_SMI_ARG_CHECKED(argument_count, 2);
+ return *NewSloppyArguments(isolate, callee, parameters, argument_count);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
+ Object** parameters = reinterpret_cast<Object**>(args[1]);
+ CONVERT_SMI_ARG_CHECKED(argument_count, 2);
+ return *NewStrictArguments(isolate, callee, parameters, argument_count);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
+ Handle<Context> context(isolate->context());
+ PretenureFlag pretenure_flag = NOT_TENURED;
+ return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
+ pretenure_flag);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewClosure) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
+ CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
+ CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
+
+ // The caller ensures that we pretenure closures that are assigned
+ // directly to properties.
+ PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
+ return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
+ pretenure_flag);
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewGlobalContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
+ Handle<Context> result =
+ isolate->factory()->NewGlobalContext(function, scope_info);
+
+ DCHECK(function->context() == isolate->context());
+ DCHECK(function->context()->global_object() == result->global_object());
+ result->global_object()->set_global_context(*result);
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+
+ DCHECK(function->context() == isolate->context());
+ int length = function->shared()->scope_info()->ContextLength();
+ return *isolate->factory()->NewFunctionContext(length, function);
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushWithContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ Handle<JSReceiver> extension_object;
+ if (args[0]->IsJSReceiver()) {
+ extension_object = args.at<JSReceiver>(0);
+ } else {
+ // Try to convert the object to a proper JavaScript object.
+ MaybeHandle<JSReceiver> maybe_object =
+ Object::ToObject(isolate, args.at<Object>(0));
+ if (!maybe_object.ToHandle(&extension_object)) {
+ Handle<Object> handle = args.at<Object>(0);
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewTypeError("with_expression", HandleVector(&handle, 1)));
+ }
+ }
+
+ Handle<JSFunction> function;
+ if (args[1]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the native context.
+ function = handle(isolate->native_context()->closure());
+ } else {
+ function = args.at<JSFunction>(1);
+ }
+
+ Handle<Context> current(isolate->context());
+ Handle<Context> context =
+ isolate->factory()->NewWithContext(function, current, extension_object);
+ isolate->set_context(*context);
+ return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushCatchContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
+ Handle<JSFunction> function;
+ if (args[2]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the native context.
+ function = handle(isolate->native_context()->closure());
+ } else {
+ function = args.at<JSFunction>(2);
+ }
+ Handle<Context> current(isolate->context());
+ Handle<Context> context = isolate->factory()->NewCatchContext(
+ function, current, name, thrown_object);
+ isolate->set_context(*context);
+ return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushBlockContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
+ Handle<JSFunction> function;
+ if (args[1]->IsSmi()) {
+ // A smi sentinel indicates a context nested inside global code rather
+ // than some function. There is a canonical empty function that can be
+ // gotten from the native context.
+ function = handle(isolate->native_context()->closure());
+ } else {
+ function = args.at<JSFunction>(1);
+ }
+ Handle<Context> current(isolate->context());
+ Handle<Context> context =
+ isolate->factory()->NewBlockContext(function, current, scope_info);
+ isolate->set_context(*context);
+ return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsJSModule) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_CHECKED(Object, obj, 0);
+ return isolate->heap()->ToBoolean(obj->IsJSModule());
+}
+
+
+RUNTIME_FUNCTION(Runtime_PushModuleContext) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_SMI_ARG_CHECKED(index, 0);
+
+ if (!args[1]->IsScopeInfo()) {
+ // Module already initialized. Find hosting context and retrieve context.
+ Context* host = Context::cast(isolate->context())->global_context();
+ Context* context = Context::cast(host->get(index));
+ DCHECK(context->previous() == isolate->context());
+ isolate->set_context(context);
+ return context;
+ }
+
+ CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
+
+ // Allocate module context.
+ HandleScope scope(isolate);
+ Factory* factory = isolate->factory();
+ Handle<Context> context = factory->NewModuleContext(scope_info);
+ Handle<JSModule> module = factory->NewJSModule(context, scope_info);
+ context->set_module(*module);
+ Context* previous = isolate->context();
+ context->set_previous(previous);
+ context->set_closure(previous->closure());
+ context->set_global_object(previous->global_object());
+ isolate->set_context(*context);
+
+ // Find hosting scope and initialize internal variable holding module there.
+ previous->global_context()->set(index, *context);
+
+ return *context;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeclareModules) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
+ Context* host_context = isolate->context();
+
+ for (int i = 0; i < descriptions->length(); ++i) {
+ Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
+ int host_index = description->host_index();
+ Handle<Context> context(Context::cast(host_context->get(host_index)));
+ Handle<JSModule> module(context->module());
+
+ for (int j = 0; j < description->length(); ++j) {
+ Handle<String> name(description->name(j));
+ VariableMode mode = description->mode(j);
+ int index = description->index(j);
+ switch (mode) {
+ case VAR:
+ case LET:
+ case CONST:
+ case CONST_LEGACY: {
+ PropertyAttributes attr =
+ IsImmutableVariableMode(mode) ? FROZEN : SEALED;
+ Handle<AccessorInfo> info =
+ Accessors::MakeModuleExport(name, index, attr);
+ Handle<Object> result =
+ JSObject::SetAccessor(module, info).ToHandleChecked();
+ DCHECK(!result->IsUndefined());
+ USE(result);
+ break;
+ }
+ case MODULE: {
+ Object* referenced_context = Context::cast(host_context)->get(index);
+ Handle<JSModule> value(Context::cast(referenced_context)->module());
+ JSObject::SetOwnPropertyIgnoreAttributes(module, name, value, FROZEN)
+ .Assert();
+ break;
+ }
+ case INTERNAL:
+ case TEMPORARY:
+ case DYNAMIC:
+ case DYNAMIC_GLOBAL:
+ case DYNAMIC_LOCAL:
+ UNREACHABLE();
+ }
+ }
+
+ JSObject::PreventExtensions(module).Assert();
+ }
+
+ DCHECK(!isolate->has_pending_exception());
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+
+ CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
+
+ int index;
+ PropertyAttributes attributes;
+ ContextLookupFlags flags = FOLLOW_CHAINS;
+ BindingFlags binding_flags;
+ Handle<Object> holder =
+ context->Lookup(name, flags, &index, &attributes, &binding_flags);
+
+ // If the slot was not found the result is true.
+ if (holder.is_null()) {
+ return isolate->heap()->true_value();
+ }
+
+ // If the slot was found in a context, it should be DONT_DELETE.
+ if (holder->IsContext()) {
+ return isolate->heap()->false_value();
+ }
+
+ // The slot was found in a JSObject, either a context extension object,
+ // the global object, or the subject of a with. Try to delete it
+ // (respecting DONT_DELETE).
+ Handle<JSObject> object = Handle<JSObject>::cast(holder);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+ JSReceiver::DeleteProperty(object, name));
+ return *result;
+}
+
+
+static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) {
+ DCHECK(!holder->IsGlobalObject());
+ Context* top = isolate->context();
+ // Get the context extension function.
+ JSFunction* context_extension_function =
+ top->native_context()->context_extension_function();
+ // If the holder isn't a context extension object, we just return it
+ // as the receiver. This allows arguments objects to be used as
+ // receivers, but only if they are put in the context scope chain
+ // explicitly via a with-statement.
+ Object* constructor = holder->map()->constructor();
+ if (constructor != context_extension_function) return holder;
+ // Fall back to using the global object as the implicit receiver if
+ // the property turns out to be a local variable allocated in a
+ // context extension object - introduced via eval.
+ return isolate->heap()->undefined_value();
+}
+
+
+static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
+ bool throw_error) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(2, args.length());
+
+ if (!args[0]->IsContext() || !args[1]->IsString()) {
+ return MakePair(isolate->ThrowIllegalOperation(), NULL);
+ }
+ Handle<Context> context = args.at<Context>(0);
+ Handle<String> name = args.at<String>(1);
+
+ int index;
+ PropertyAttributes attributes;
+ ContextLookupFlags flags = FOLLOW_CHAINS;
+ BindingFlags binding_flags;
+ Handle<Object> holder =
+ context->Lookup(name, flags, &index, &attributes, &binding_flags);
+ if (isolate->has_pending_exception()) {
+ return MakePair(isolate->heap()->exception(), NULL);
+ }
+
+ // If the index is non-negative, the slot has been found in a context.
+ if (index >= 0) {
+ DCHECK(holder->IsContext());
+ // If the "property" we were looking for is a local variable, the
+ // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
+ Handle<Object> receiver = isolate->factory()->undefined_value();
+ Object* value = Context::cast(*holder)->get(index);
+ // Check for uninitialized bindings.
+ switch (binding_flags) {
+ case MUTABLE_CHECK_INITIALIZED:
+ case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
+ if (value->IsTheHole()) {
+ Handle<Object> error;
+ MaybeHandle<Object> maybe_error =
+ isolate->factory()->NewReferenceError("not_defined",
+ HandleVector(&name, 1));
+ if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
+ return MakePair(isolate->heap()->exception(), NULL);
+ }
+ // FALLTHROUGH
+ case MUTABLE_IS_INITIALIZED:
+ case IMMUTABLE_IS_INITIALIZED:
+ case IMMUTABLE_IS_INITIALIZED_HARMONY:
+ DCHECK(!value->IsTheHole());
+ return MakePair(value, *receiver);
+ case IMMUTABLE_CHECK_INITIALIZED:
+ if (value->IsTheHole()) {
+ DCHECK((attributes & READ_ONLY) != 0);
+ value = isolate->heap()->undefined_value();
+ }
+ return MakePair(value, *receiver);
+ case MISSING_BINDING:
+ UNREACHABLE();
+ return MakePair(NULL, NULL);
+ }
+ }
+
+ // Otherwise, if the slot was found the holder is a context extension
+ // object, subject of a with, or a global object. We read the named
+ // property from it.
+ if (!holder.is_null()) {
+ Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
+#ifdef DEBUG
+ if (!object->IsJSProxy()) {
+ Maybe<bool> maybe = JSReceiver::HasProperty(object, name);
+ DCHECK(maybe.has_value);
+ DCHECK(maybe.value);
+ }
+#endif
+ // GetProperty below can cause GC.
+ Handle<Object> receiver_handle(
+ object->IsGlobalObject()
+ ? Object::cast(isolate->heap()->undefined_value())
+ : object->IsJSProxy() ? static_cast<Object*>(*object)
+ : ComputeReceiverForNonGlobal(
+ isolate, JSObject::cast(*object)),
+ isolate);
+
+ // No need to unhole the value here. This is taken care of by the
+ // GetProperty function.
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, value, Object::GetProperty(object, name),
+ MakePair(isolate->heap()->exception(), NULL));
+ return MakePair(*value, *receiver_handle);
+ }
+
+ if (throw_error) {
+ // The property doesn't exist - throw exception.
+ Handle<Object> error;
+ MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError(
+ "not_defined", HandleVector(&name, 1));
+ if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
+ return MakePair(isolate->heap()->exception(), NULL);
+ } else {
+ // The property doesn't exist - return undefined.
+ return MakePair(isolate->heap()->undefined_value(),
+ isolate->heap()->undefined_value());
+ }
+}
+
+
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
+ return LoadLookupSlotHelper(args, isolate, true);
+}
+
+
+RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
+ return LoadLookupSlotHelper(args, isolate, false);
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 4);
+
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
+ CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
+ CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3);
+
+ int index;
+ PropertyAttributes attributes;
+ ContextLookupFlags flags = FOLLOW_CHAINS;
+ BindingFlags binding_flags;
+ Handle<Object> holder =
+ context->Lookup(name, flags, &index, &attributes, &binding_flags);
+ // In case of JSProxy, an exception might have been thrown.
+ if (isolate->has_pending_exception()) return isolate->heap()->exception();
+
+ // The property was found in a context slot.
+ if (index >= 0) {
+ if ((attributes & READ_ONLY) == 0) {
+ Handle<Context>::cast(holder)->set(index, *value);
+ } else if (strict_mode == STRICT) {
+ // Setting read only property in strict mode.
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate,
+ NewTypeError("strict_cannot_assign", HandleVector(&name, 1)));
+ }
+ return *value;
+ }
+
+ // Slow case: The property is not in a context slot. It is either in a
+ // context extension object, a property of the subject of a with, or a
+ // property of the global object.
+ Handle<JSReceiver> object;
+ if (attributes != ABSENT) {
+ // The property exists on the holder.
+ object = Handle<JSReceiver>::cast(holder);
+ } else if (strict_mode == STRICT) {
+ // If absent in strict mode: throw.
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
+ } else {
+ // If absent in sloppy mode: add the property to the global object.
+ object = Handle<JSReceiver>(context->global_object());
+ }
+
+ RETURN_FAILURE_ON_EXCEPTION(
+ isolate, Object::SetProperty(object, name, value, strict_mode));
+
+ return *value;
+}
+
+
+RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
+
+ // Compute the frame holding the arguments.
+ JavaScriptFrameIterator it(isolate);
+ it.AdvanceToArgumentsFrame();
+ JavaScriptFrame* frame = it.frame();
+
+ // Get the actual number of provided arguments.
+ const uint32_t n = frame->ComputeParametersCount();
+
+ // Try to convert the key to an index. If successful and within
+ // index return the the argument from the frame.
+ uint32_t index;
+ if (raw_key->ToArrayIndex(&index) && index < n) {
+ return frame->GetParameter(index);
+ }
+
+ HandleScope scope(isolate);
+ if (raw_key->IsSymbol()) {
+ Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
+ if (symbol->Equals(isolate->native_context()->iterator_symbol())) {
+ return isolate->native_context()->array_values_iterator();
+ }
+ // Lookup in the initial Object.prototype object.
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ Object::GetProperty(isolate->initial_object_prototype(),
+ Handle<Symbol>::cast(raw_key)));
+ return *result;
+ }
+
+ // Convert the key to a string.
+ Handle<Object> converted;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
+ Execution::ToString(isolate, raw_key));
+ Handle<String> key = Handle<String>::cast(converted);
+
+ // Try to convert the string key into an array index.
+ if (key->AsArrayIndex(&index)) {
+ if (index < n) {
+ return frame->GetParameter(index);
+ } else {
+ Handle<Object> initial_prototype(isolate->initial_object_prototype());
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ Object::GetElement(isolate, initial_prototype, index));
+ return *result;
+ }
+ }
+
+ // Handle special arguments properties.
+ if (String::Equals(isolate->factory()->length_string(), key)) {
+ return Smi::FromInt(n);
+ }
+ if (String::Equals(isolate->factory()->callee_string(), key)) {
+ JSFunction* function = frame->function();
+ if (function->shared()->strict_mode() == STRICT) {
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewTypeError("strict_arguments_callee",
+ HandleVector<Object>(NULL, 0)));
+ }
+ return function;
+ }
+
+ // Lookup in the initial Object.prototype object.
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ Object::GetProperty(isolate->initial_object_prototype(), key));
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 0);
+ JavaScriptFrameIterator it(isolate);
+ JavaScriptFrame* frame = it.frame();
+ return Smi::FromInt(frame->GetArgumentsLength());
+}
+
+
+RUNTIME_FUNCTION(RuntimeReference_Arguments) {
+ SealHandleScope shs(isolate);
+ return __RT_impl_Runtime_GetArgumentsProperty(args, isolate);
+}
+}
+} // namespace v8::internal
« no previous file with comments | « src/runtime/runtime-regexp.cc ('k') | src/runtime/runtime-symbol.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698