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

Unified Diff: src/runtime.cc

Issue 379893002: Clean up and update const / var (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comment Created 6 years, 5 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.h ('k') | src/x64/full-codegen-x64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/runtime.cc
diff --git a/src/runtime.cc b/src/runtime.cc
index 28481383a5fbd846a6940deb9a1b08ee64dab56e..aba2d75ef5f40e1d5272ddf7b781db96246b7ce9 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -640,8 +640,8 @@ RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateSymbol) {
ASSERT(symbol->IsUndefined());
symbol = isolate->factory()->NewPrivateSymbol();
Handle<Symbol>::cast(symbol)->set_name(*name);
- JSObject::SetProperty(Handle<JSObject>::cast(privates),
- name, symbol, NONE, STRICT).Assert();
+ JSObject::SetProperty(Handle<JSObject>::cast(privates), name, symbol, NONE,
+ STRICT).Assert();
}
return *symbol;
}
@@ -2103,6 +2103,50 @@ static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
}
+// 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::CHECK_HIDDEN);
+ PropertyAttributes old_attributes = JSReceiver::GetPropertyAttributes(&it);
+
+ if (old_attributes != ABSENT) {
+ // 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();
+
+ ASSERT(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).
+ ASSERT((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);
ASSERT(args.length() == 3);
@@ -2117,181 +2161,42 @@ RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
for (int i = 0; i < length; i += 2) {
HandleScope scope(isolate);
Handle<String> name(String::cast(pairs->get(i)));
- Handle<Object> value(pairs->get(i + 1), isolate);
+ 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 = value->IsUndefined();
- bool is_const = value->IsTheHole();
- bool is_function = value->IsSharedFunctionInfo();
+ bool is_var = initial_value->IsUndefined();
+ bool is_const = initial_value->IsTheHole();
+ bool is_function = initial_value->IsSharedFunctionInfo();
ASSERT(is_var + is_const + is_function == 1);
- if (is_var || is_const) {
- // Lookup the property in the global object, and don't set the
- // value of the variable if the property is already there.
- // Do the lookup own properties only, see ES5 erratum.
- LookupResult lookup(isolate);
- global->LookupOwn(name, &lookup, true);
- if (lookup.IsFound()) {
- // We found an existing property. Unless it was an interceptor
- // that claims the property is absent, skip this declaration.
- if (!lookup.IsInterceptor()) continue;
- if (JSReceiver::GetPropertyAttributes(global, name) != ABSENT) continue;
- // Fall-through and introduce the absent property by using
- // SetProperty.
- }
- } else if (is_function) {
+ Handle<Object> value;
+ if (is_function) {
// Copy the function and update its context. Use it as value.
Handle<SharedFunctionInfo> shared =
- Handle<SharedFunctionInfo>::cast(value);
+ Handle<SharedFunctionInfo>::cast(initial_value);
Handle<JSFunction> function =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(
- shared, context, TENURED);
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
+ TENURED);
value = function;
+ } else {
+ value = isolate->factory()->undefined_value();
}
- LookupResult lookup(isolate);
- global->LookupOwn(name, &lookup, true);
-
// Compute the property attributes. According to ECMA-262,
// the property must be non-configurable except in eval.
- int attr = NONE;
- bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
- if (!is_eval) {
- attr |= DONT_DELETE;
- }
bool is_native = DeclareGlobalsNativeFlag::decode(flags);
- if (is_const || (is_native && is_function)) {
- attr |= READ_ONLY;
- }
-
- StrictMode strict_mode = DeclareGlobalsStrictMode::decode(flags);
-
- if (!lookup.IsFound() || is_function) {
- // If the own property exists, check that we can reconfigure it
- // as required for function declarations.
- if (lookup.IsFound() && lookup.IsDontDelete()) {
- if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
- lookup.IsPropertyCallbacks()) {
- return ThrowRedeclarationError(isolate, name);
- }
- // If the existing property is not configurable, keep its attributes.
- attr = lookup.GetAttributes();
- }
- // Define or redefine own property.
- RETURN_FAILURE_ON_EXCEPTION(isolate,
- JSObject::SetOwnPropertyIgnoreAttributes(
- global, name, value, static_cast<PropertyAttributes>(attr)));
- } else {
- // Do a [[Put]] on the existing (own) property.
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- JSObject::SetProperty(
- global, name, value, static_cast<PropertyAttributes>(attr),
- strict_mode));
- }
- }
-
- ASSERT(!isolate->has_pending_exception());
- return isolate->heap()->undefined_value();
-}
-
-
-RUNTIME_FUNCTION(Runtime_DeclareContextSlot) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 4);
-
- // Declarations are always made in a function or native 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(mode_arg, 2);
- PropertyAttributes mode = static_cast<PropertyAttributes>(mode_arg);
- RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
- CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
-
- int index;
- PropertyAttributes attributes;
- ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
- BindingFlags binding_flags;
- Handle<Object> holder =
- context->Lookup(name, flags, &index, &attributes, &binding_flags);
-
- if (attributes != ABSENT) {
- // The name was declared before; check for conflicting re-declarations.
- // Note: this is actually inconsistent with what happens for globals (where
- // we silently ignore such declarations).
- if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
- // Functions are not read-only.
- ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
- return ThrowRedeclarationError(isolate, name);
- }
-
- // Initialize it if necessary.
- if (*initial_value != NULL) {
- if (index >= 0) {
- ASSERT(holder.is_identical_to(context));
- if (((attributes & READ_ONLY) == 0) ||
- context->get(index)->IsTheHole()) {
- context->set(index, *initial_value);
- }
- } else {
- // Slow case: The property is in the context extension object of a
- // function context or the global object of a native context.
- Handle<JSObject> object = Handle<JSObject>::cast(holder);
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- JSReceiver::SetProperty(object, name, initial_value, mode, SLOPPY));
- }
- }
+ 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;
- } else {
- // The property is not in the function context. It needs to be
- // "declared" in the function context's extension context or as a
- // property of the the global object.
- Handle<JSObject> object;
- if (context->has_extension()) {
- object = Handle<JSObject>(JSObject::cast(context->extension()));
- } else {
- // Context extension objects are allocated lazily.
- ASSERT(context->IsFunctionContext());
- object = isolate->factory()->NewJSObject(
- isolate->context_extension_function());
- context->set_extension(*object);
- }
- ASSERT(*object != NULL);
-
- // Declare the property by setting it to the initial value if provided,
- // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
- // constant declarations).
- ASSERT(!JSReceiver::HasOwnProperty(object, name));
- Handle<Object> value(isolate->heap()->undefined_value(), isolate);
- if (*initial_value != NULL) value = initial_value;
- // Declaring a const context slot is a conflicting declaration if
- // there is a callback with that name in a prototype. It is
- // allowed to introduce const variables in
- // JSContextExtensionObjects. They are treated specially in
- // SetProperty and no setters are invoked for those since they are
- // not real JSObjects.
- if (initial_value->IsTheHole() &&
- !object->IsJSContextExtensionObject()) {
- LookupResult lookup(isolate);
- object->Lookup(name, &lookup);
- if (lookup.IsPropertyCallbacks()) {
- return ThrowRedeclarationError(isolate, name);
- }
- }
- if (object->IsJSGlobalObject()) {
- // Define own property on the global object.
- RETURN_FAILURE_ON_EXCEPTION(isolate,
- JSObject::SetOwnPropertyIgnoreAttributes(object, name, value, mode));
- } else {
- RETURN_FAILURE_ON_EXCEPTION(isolate,
- JSReceiver::SetProperty(object, name, value, mode, SLOPPY));
- }
+ 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();
@@ -2306,60 +2211,23 @@ RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
// Determine if we need to assign to the variable if it already
// exists (based on the number of arguments).
- RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
- bool assign = args.length() == 3;
+ 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);
- // According to ECMA-262, section 12.2, page 62, the property must
- // not be deletable.
- PropertyAttributes attributes = DONT_DELETE;
-
- // Lookup the property as own on the global object. If it isn't
- // there, there is a property with this name in the prototype chain.
- // We follow Safari and Firefox behavior and only set the property
- // if there is an explicit initialization value that we have
- // to assign to the property.
- // Note that objects can have hidden prototypes, so we need to traverse
- // the whole chain of hidden prototypes to do an 'own' lookup.
- LookupResult lookup(isolate);
- isolate->context()->global_object()->LookupOwn(name, &lookup, true);
- if (lookup.IsInterceptor()) {
- Handle<JSObject> holder(lookup.holder());
- PropertyAttributes intercepted =
- JSReceiver::GetPropertyAttributes(holder, name);
- if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
- // Found an interceptor that's not read only.
- if (assign) {
- CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result,
- JSObject::SetPropertyForResult(
- holder, &lookup, name, value, attributes, strict_mode));
- return *result;
- } else {
- return isolate->heap()->undefined_value();
- }
- }
- }
-
- if (assign) {
- CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
- Handle<GlobalObject> global(isolate->context()->global_object());
- Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result,
- JSReceiver::SetProperty(global, name, value, attributes, strict_mode));
- return *result;
- }
- return isolate->heap()->undefined_value();
+ Handle<GlobalObject> global(isolate->context()->global_object());
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ JSReceiver::SetProperty(global, name, value, NONE, strict_mode));
+ return *result;
}
RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
- SealHandleScope shs(isolate);
+ 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.
@@ -2367,71 +2235,112 @@ RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
- // Get the current global object from top.
- GlobalObject* global = isolate->context()->global_object();
+ Handle<GlobalObject> global = isolate->global_object();
- // According to ECMA-262, section 12.2, page 62, the property must
- // not be deletable. Since it's a const, it must be READ_ONLY too.
- PropertyAttributes attributes =
- static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
+ // Lookup the property as own on the global object.
+ LookupIterator it(global, name, LookupIterator::CHECK_HIDDEN);
+ PropertyAttributes old_attributes = JSReceiver::GetPropertyAttributes(&it);
- // Lookup the property as own on the global object. If it isn't
- // there, we add the property and take special precautions to always
- // add it even in case of callbacks in the prototype chain (this rules
- // out using SetProperty). We use SetOwnPropertyIgnoreAttributes instead
- LookupResult lookup(isolate);
- global->LookupOwn(name, &lookup);
- if (!lookup.IsFound()) {
- HandleScope handle_scope(isolate);
- Handle<GlobalObject> global(isolate->context()->global_object());
- JSObject::AddProperty(global, name, value, attributes);
- return *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.property_kind() == LookupIterator::ACCESSOR) {
+ return *value;
+ }
+ attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
+ }
}
- if (!lookup.IsReadOnly()) {
- // Restore global object from context (in case of GC) and continue
- // with setting the value.
- HandleScope handle_scope(isolate);
- Handle<GlobalObject> global(isolate->context()->global_object());
+ RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+ global, name, value, attr));
- // BUG 1213575: Handle the case where we have to set a read-only
- // property through an interceptor and only do it if it's
- // uninitialized, e.g. the hole. Nirk...
- // Passing sloppy mode because the property is writable.
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- JSReceiver::SetProperty(global, name, value, attributes, SLOPPY));
- return *value;
+ return *value;
+}
+
+
+RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
+ HandleScope scope(isolate);
+ ASSERT(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();
+ ASSERT(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);
}
- // Set the value, but only if we're assigning the initial value to a
- // constant. For now, we determine this by checking if the
- // current value is the hole.
- // Strict mode handling not needed (const is disallowed in strict mode).
- if (lookup.IsField()) {
- FixedArray* properties = global->properties();
- int index = lookup.GetFieldIndex().outobject_array_index();
- if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
- properties->set(index, *value);
+ if (attributes != ABSENT) {
+ // The name was declared before; check for conflicting re-declarations.
+ if (is_const || (attributes & READ_ONLY) != 0) {
+ return ThrowRedeclarationError(isolate, name);
}
- } else if (lookup.IsNormal()) {
- if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
- !lookup.IsReadOnly()) {
- HandleScope scope(isolate);
- JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value);
+
+ // Skip var re-declarations.
+ if (is_var) return isolate->heap()->undefined_value();
+
+ ASSERT(is_function);
+ if (index >= 0) {
+ ASSERT(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()));
+ ASSERT(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
} else {
- // Ignore re-initialization of constants that have already been
- // assigned a constant value.
- ASSERT(lookup.IsReadOnly() && lookup.IsConstant());
+ ASSERT(context->IsFunctionContext());
+ object =
+ isolate->factory()->NewJSObject(isolate->context_extension_function());
+ context->set_extension(*object);
}
- // Use the set value as the result of the operation.
- return *value;
+ RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
+ object, name, value, attr));
+
+ return isolate->heap()->undefined_value();
}
-RUNTIME_FUNCTION(Runtime_InitializeConstContextSlot) {
+RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
HandleScope scope(isolate);
ASSERT(args.length() == 3);
@@ -2444,86 +2353,56 @@ RUNTIME_FUNCTION(Runtime_InitializeConstContextSlot) {
int index;
PropertyAttributes attributes;
- ContextLookupFlags flags = FOLLOW_CHAINS;
+ ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
BindingFlags binding_flags;
Handle<Object> holder =
context->Lookup(name, flags, &index, &attributes, &binding_flags);
if (index >= 0) {
ASSERT(holder->IsContext());
- // Property was found in a context. Perform the assignment if we
- // found some non-constant or an uninitialized constant.
+ // Property was found in a context. Perform the assignment if the constant
+ // was uninitialized.
Handle<Context> context = Handle<Context>::cast(holder);
- if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
- context->set(index, *value);
- }
+ ASSERT((attributes & READ_ONLY) != 0);
+ if (context->get(index)->IsTheHole()) context->set(index, *value);
return *value;
}
- // The property could not be found, we introduce it as a property of the
- // global object.
- if (attributes == ABSENT) {
- Handle<JSObject> global = Handle<JSObject>(
- isolate->context()->global_object());
- // Strict mode not needed (const disallowed in strict mode).
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- JSReceiver::SetProperty(global, name, value, NONE, SLOPPY));
- return *value;
- }
+ PropertyAttributes attr =
+ static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
- // The property was present in some function's context extension object,
- // as a property on the subject of a with, or as a property of the global
- // object.
- //
- // In most situations, eval-introduced consts should still be present in
- // the context extension object. However, because declaration and
- // initialization are separate, the property might have been deleted
- // before we reach the initialization point.
- //
- // Example:
- //
- // function f() { eval("delete x; const x;"); }
- //
- // In that case, the initialization behaves like a normal assignment.
- Handle<JSObject> object = Handle<JSObject>::cast(holder);
+ // Strict mode handling not needed (legacy const is disallowed in strict
+ // mode).
- if (*object == context->extension()) {
- // This is the property that was introduced by the const declaration.
- // Set it if it hasn't been set before. NOTE: We cannot use
- // GetProperty() to get the current value as it 'unholes' the value.
- LookupResult lookup(isolate);
- object->LookupOwnRealNamedProperty(name, &lookup);
- ASSERT(lookup.IsFound()); // the property was declared
- ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
-
- if (lookup.IsField()) {
- FixedArray* properties = object->properties();
- FieldIndex index = lookup.GetFieldIndex();
- ASSERT(!index.is_inobject());
- if (properties->get(index.outobject_array_index())->IsTheHole()) {
- properties->set(index.outobject_array_index(), *value);
- }
- } else if (lookup.IsNormal()) {
- if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
- JSObject::SetNormalizedProperty(object, &lookup, value);
- }
- } else {
- // We should not reach here. Any real, named property should be
- // either a field or a dictionary slot.
- UNREACHABLE();
- }
+ // The declared const was configurable, and may have been deleted in the
+ // meanwhile. If so, re-introduce the variable in the context extension.
+ ASSERT(context_arg->has_extension());
+ if (attributes == ABSENT) {
+ holder = handle(context_arg->extension(), isolate);
} else {
- // The property was found on some other object. Set it if it is not a
- // read-only property.
- if ((attributes & READ_ONLY) == 0) {
- // Strict mode not needed (const disallowed in strict mode).
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- JSReceiver::SetProperty(object, name, value, attributes, SLOPPY));
+ // 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.
+ ASSERT(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
+
+ LookupIterator it(holder, name, LookupIterator::CHECK_HIDDEN);
+ PropertyAttributes old_attributes = JSReceiver::GetPropertyAttributes(&it);
+
+ // Ignore if we can't reconfigure the value.
+ if ((old_attributes & DONT_DELETE) != 0) {
+ if ((old_attributes & READ_ONLY) != 0 ||
+ it.property_kind() == 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;
}
@@ -9322,7 +9201,7 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadContextSlotNoReferenceError) {
}
-RUNTIME_FUNCTION(Runtime_StoreContextSlot) {
+RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
HandleScope scope(isolate);
ASSERT(args.length() == 4);
@@ -9340,22 +9219,13 @@ RUNTIME_FUNCTION(Runtime_StoreContextSlot) {
&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) {
- // The property was found in a context slot.
- Handle<Context> context = Handle<Context>::cast(holder);
- if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
- context->get(index)->IsTheHole()) {
- Handle<Object> error =
- isolate->factory()->NewReferenceError("not_defined",
- HandleVector(&name, 1));
- return isolate->Throw(*error);
- }
- // Ignore if read_only variable.
if ((attributes & READ_ONLY) == 0) {
- // Context is a fixed array and set cannot fail.
- context->set(index, *value);
+ Handle<Context>::cast(holder)->set(index, *value);
} else if (strict_mode == STRICT) {
// Setting read only property in strict mode.
Handle<Object> error =
@@ -9370,39 +9240,22 @@ RUNTIME_FUNCTION(Runtime_StoreContextSlot) {
// context extension object, a property of the subject of a with, or a
// property of the global object.
Handle<JSReceiver> object;
-
- if (!holder.is_null()) {
+ 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.
+ Handle<Object> error = isolate->factory()->NewReferenceError(
+ "not_defined", HandleVector(&name, 1));
+ return isolate->Throw(*error);
} else {
- // The property was not found.
- ASSERT(attributes == ABSENT);
-
- if (strict_mode == STRICT) {
- // Throw in strict mode (assignment to undefined variable).
- Handle<Object> error =
- isolate->factory()->NewReferenceError(
- "not_defined", HandleVector(&name, 1));
- return isolate->Throw(*error);
- }
- // In sloppy mode, the property is added to the global object.
- attributes = NONE;
- object = Handle<JSReceiver>(isolate->context()->global_object());
+ // If absent in sloppy mode: add the property to the global object.
+ object = Handle<JSReceiver>(context->global_object());
}
- // Set the property if it's not read only or doesn't yet exist.
- if ((attributes & READ_ONLY) == 0 ||
- (JSReceiver::GetOwnPropertyAttributes(object, name) == ABSENT)) {
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
- } else if (strict_mode == STRICT && (attributes & READ_ONLY) != 0) {
- // Setting read only property in strict mode.
- Handle<Object> error =
- isolate->factory()->NewTypeError(
- "strict_cannot_assign", HandleVector(&name, 1));
- return isolate->Throw(*error);
- }
+ RETURN_FAILURE_ON_EXCEPTION(
+ isolate, JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
+
return *value;
}
« no previous file with comments | « src/runtime.h ('k') | src/x64/full-codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698