__ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value.
__ Push(cp, r2, r1, r0);
}
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
__ Push(cp, r2, r1);
// Push initial value for function declaration.
VisitForStackValue(declaration->fun());
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
}
-void FullCodeGenerator::EmitCallStoreContextSlot(
- Handle<String> name, StrictMode strict_mode) {
- __ push(r0); // Value.
- __ mov(r1, Operand(name));
- __ mov(r0, Operand(Smi::FromInt(strict_mode)));
- __ Push(cp, r1, r0); // Context, name, strict mode.
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
-}
-
-
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) {
if (var->IsUnallocated()) {
// Global var, const, or let.
__ push(r0);
__ mov(r0, Operand(var->name()));
__ Push(cp, r0); // Context and name.
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+ __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
Label skip;
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
- if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
- } else {
- ASSERT(var->IsStackAllocated() || var->IsContextSlot());
- Label assign;
- MemOperand location = VarOperand(var, r1);
- __ ldr(r3, location);
- __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
- __ b(ne, &assign);
- __ mov(r3, Operand(var->name()));
- __ push(r3);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- EmitStoreToStackLocalOrContextSlot(var, location);
- }
+ ASSERT(!var->IsLookupSlot());
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, r1);
+ __ ldr(r3, location);
+ __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+ __ b(ne, &assign);
+ __ mov(r3, Operand(var->name()));
+ __ push(r3);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ // Perform the assignment.
+ __ bind(&assign);
+ EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
- // Assignment to var or initializing assignment to let/const
- // in harmony mode.
if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
+ ASSERT(op == Token::ASSIGN || op == Token::INIT_VAR ||
+ op == Token::ASSIGN_ADD);
+ // Assignment to var.
+ __ push(r0); // Value.
+ __ mov(r1, Operand(var->name()));
+ __ mov(r0, Operand(Smi::FromInt(strict_mode())));
+ __ Push(cp, r1, r0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreLookupSlot, 4);
} else {
+ // Assignment to var or initializing assignment to let/const in harmony
+ // mode.
ASSERT((var->IsStackAllocated() || var->IsContextSlot()));
MemOperand location = VarOperand(var, r1);
if (generate_debug_code_ && op == Token::INIT_LET) {
// Pushing 0 (xzr) indicates no initial value.
__ Push(cp, x2, x1, xzr);
}
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
__ Push(cp, x2, x1);
// Push initial value for function declaration.
VisitForStackValue(declaration->fun());
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
}
-void FullCodeGenerator::EmitCallStoreContextSlot(
- Handle<String> name, StrictMode strict_mode) {
- __ Mov(x11, Operand(name));
- __ Mov(x10, Smi::FromInt(strict_mode));
- // jssp[0] : mode.
- // jssp[8] : name.
- // jssp[16] : context.
- // jssp[24] : value.
- __ Push(x0, cp, x11, x10);
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
-}
-
-
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment");
if (var->IsLookupSlot()) {
__ Mov(x1, Operand(var->name()));
__ Push(x0, cp, x1);
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+ __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
ASSERT(var->IsStackLocal() || var->IsContextSlot());
Label skip;
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
- if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
- } else {
- ASSERT(var->IsStackAllocated() || var->IsContextSlot());
- Label assign;
- MemOperand location = VarOperand(var, x1);
- __ Ldr(x10, location);
- __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &assign);
- __ Mov(x10, Operand(var->name()));
- __ Push(x10);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ Bind(&assign);
- EmitStoreToStackLocalOrContextSlot(var, location);
- }
+ ASSERT(!var->IsLookupSlot());
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, x1);
+ __ Ldr(x10, location);
+ __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &assign);
+ __ Mov(x10, Operand(var->name()));
+ __ Push(x10);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ // Perform the assignment.
+ __ Bind(&assign);
+ EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
- // Assignment to var or initializing assignment to let/const
- // in harmony mode.
if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
+ ASSERT(op == Token::ASSIGN || op == Token::INIT_VAR ||
+ op == Token::ASSIGN_ADD);
+ // Assignment to var.
+ __ Mov(x11, Operand(var->name()));
+ __ Mov(x10, Smi::FromInt(strict_mode()));
+ // jssp[0] : mode.
+ // jssp[8] : name.
+ // jssp[16] : context.
+ // jssp[24] : value.
+ __ Push(x0, cp, x11, x10);
+ __ CallRuntime(Runtime::kStoreLookupSlot, 4);
} else {
+ // Assignment to var or initializing assignment to let/const in harmony
+ // mode.
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, x1);
if (FLAG_debug_code && op == Token::INIT_LET) {
// Helper functions to EmitVariableAssignment
void EmitStoreToStackLocalOrContextSlot(Variable* var,
MemOperand location);
- void EmitCallStoreContextSlot(Handle<String> name, StrictMode strict_mode);
// Complete a named property assignment. The receiver is expected on top
// of the stack and the right-hand-side value in the accumulator.
} else {
__ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
}
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
__ push(Immediate(variable->name()));
__ push(Immediate(Smi::FromInt(NONE)));
VisitForStackValue(declaration->fun());
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
}
-void FullCodeGenerator::EmitCallStoreContextSlot(
- Handle<String> name, StrictMode strict_mode) {
- __ push(eax); // Value.
- __ push(esi); // Context.
- __ push(Immediate(name));
- __ push(Immediate(Smi::FromInt(strict_mode)));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
-}
-
-
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
if (var->IsUnallocated()) {
__ push(eax);
__ push(esi);
__ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+ __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
ASSERT(var->IsStackLocal() || var->IsContextSlot());
Label skip;
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
- if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
- } else {
- ASSERT(var->IsStackAllocated() || var->IsContextSlot());
- Label assign;
- MemOperand location = VarOperand(var, ecx);
- __ mov(edx, location);
- __ cmp(edx, isolate()->factory()->the_hole_value());
- __ j(not_equal, &assign, Label::kNear);
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- __ bind(&assign);
- EmitStoreToStackLocalOrContextSlot(var, location);
- }
+ ASSERT(!var->IsLookupSlot());
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, ecx);
+ __ mov(edx, location);
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ j(not_equal, &assign, Label::kNear);
+ __ push(Immediate(var->name()));
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&assign);
+ EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
- // Assignment to var or initializing assignment to let/const
- // in harmony mode.
if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
+ ASSERT(op == Token::ASSIGN || op == Token::INIT_VAR ||
+ op == Token::ASSIGN_ADD);
+ // Assignment to var.
+ __ push(eax); // Value.
+ __ push(esi); // Context.
+ __ push(Immediate(var->name()));
+ __ push(Immediate(Smi::FromInt(strict_mode())));
+ __ CallRuntime(Runtime::kStoreLookupSlot, 4);
} else {
+ // Assignment to var or initializing assignment to let/const in harmony
+ // mode.
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, ecx);
if (generate_debug_code_ && op == Token::INIT_LET) {
// same variable if it is declared several times. This is not a
// semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated
- // RuntimeHidden_DeclareContextSlot calls.
+ // RuntimeHidden_DeclareLookupSlot calls.
declaration_scope->AddDeclaration(declaration);
if (mode == CONST_LEGACY && declaration_scope->is_global_scope()) {
declaration_scope->strict_mode() == SLOPPY) {
// For variable declarations in a sloppy eval scope the proxy is bound
// to a lookup variable to force a dynamic declaration using the
- // DeclareContextSlot runtime function.
+ // DeclareLookupSlot runtime function.
Variable::Kind kind = Variable::NORMAL;
var = new(zone()) Variable(
declaration_scope, name, mode, true, kind,
if (value != NULL && !inside_with()) {
arguments->Add(value, zone());
value = NULL; // zap the value to avoid the unnecessary assignment
+ // Construct the call to Runtime_InitializeVarGlobal
+ // and add it to the initialization statement block.
+ initialize = factory()->NewCallRuntime(
+ ast_value_factory_->initialize_var_global_string(),
+ Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
+ pos);
+ } else {
+ initialize = NULL;
}
-
- // Construct the call to Runtime_InitializeVarGlobal
- // and add it to the initialization statement block.
- // Note that the function does different things depending on
- // the number of arguments (2 or 3).
- initialize = factory()->NewCallRuntime(
- ast_value_factory_->initialize_var_global_string(),
- Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
- arguments, pos);
}
- block->AddStatement(
- factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition),
- zone());
+ if (initialize != NULL) {
+ block->AddStatement(factory()->NewExpressionStatement(
+ initialize, RelocInfo::kNoPosition),
+ zone());
+ }
} else if (needs_init) {
// Constant initializations always assign to the declared constant which
// is always at the function scope level. This is only relevant for
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;
}
}
+// 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);
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();
// 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.
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);
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;
}
}
-RUNTIME_FUNCTION(Runtime_StoreContextSlot) {
+RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
HandleScope scope(isolate);
ASSERT(args.length() == 4);
&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 =
// 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;
}
F(IsValidSmi, 1, 1)
-#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
- /* Reflection */ \
- F(FunctionSetInstanceClassName, 2, 1) \
- F(FunctionSetLength, 2, 1) \
- F(FunctionSetPrototype, 2, 1) \
- F(FunctionGetName, 1, 1) \
- F(FunctionSetName, 2, 1) \
- F(FunctionNameShouldPrintAsAnonymous, 1, 1) \
- F(FunctionMarkNameShouldPrintAsAnonymous, 1, 1) \
- F(FunctionIsGenerator, 1, 1) \
- F(FunctionBindArguments, 4, 1) \
- F(BoundFunctionGetBindings, 1, 1) \
- F(FunctionRemovePrototype, 1, 1) \
- F(FunctionGetSourceCode, 1, 1) \
- F(FunctionGetScript, 1, 1) \
- F(FunctionGetScriptSourcePosition, 1, 1) \
- F(FunctionGetPositionForOffset, 2, 1) \
- F(FunctionIsAPIFunction, 1, 1) \
- F(FunctionIsBuiltin, 1, 1) \
- F(GetScript, 1, 1) \
- F(CollectStackTrace, 2, 1) \
- F(GetV8Version, 0, 1) \
- \
- F(SetCode, 2, 1) \
- \
- F(CreateApiFunction, 2, 1) \
- F(IsTemplate, 1, 1) \
- F(GetTemplateField, 2, 1) \
- F(DisableAccessChecks, 1, 1) \
- F(EnableAccessChecks, 1, 1) \
- \
- /* Dates */ \
- F(DateCurrentTime, 0, 1) \
- F(DateParseString, 2, 1) \
- F(DateLocalTimezone, 1, 1) \
- F(DateToUTC, 1, 1) \
- F(DateMakeDay, 2, 1) \
- F(DateSetValue, 3, 1) \
- F(DateCacheVersion, 0, 1) \
- \
- /* Globals */ \
- F(CompileString, 2, 1) \
- \
- /* Eval */ \
- F(GlobalProxy, 1, 1) \
- F(IsAttachedGlobal, 1, 1) \
- \
- F(AddProperty, 4, 1) \
- F(AddPropertyForTemplate, 4, 1) \
- F(SetProperty, 4, 1) \
- F(DefineDataPropertyUnchecked, 4, 1) \
- F(DefineAccessorPropertyUnchecked, 5, 1) \
- F(GetDataProperty, 2, 1) \
- F(SetHiddenProperty, 3, 1) \
- \
- /* Arrays */ \
- F(RemoveArrayHoles, 2, 1) \
- F(GetArrayKeys, 2, 1) \
- F(MoveArrayContents, 2, 1) \
- F(EstimateNumberOfElements, 1, 1) \
- \
- /* Getters and Setters */ \
- F(LookupAccessor, 3, 1) \
- \
- /* ES5 */ \
- F(ObjectFreeze, 1, 1) \
- \
- /* Harmony modules */ \
- F(IsJSModule, 1, 1) \
- \
- /* Harmony symbols */ \
- F(CreateSymbol, 1, 1) \
- F(CreatePrivateSymbol, 1, 1) \
- F(CreateGlobalPrivateSymbol, 1, 1) \
- F(NewSymbolWrapper, 1, 1) \
- F(SymbolDescription, 1, 1) \
- F(SymbolRegistry, 0, 1) \
- F(SymbolIsPrivate, 1, 1) \
- \
- /* Harmony proxies */ \
- F(CreateJSProxy, 2, 1) \
- F(CreateJSFunctionProxy, 4, 1) \
- F(IsJSProxy, 1, 1) \
- F(IsJSFunctionProxy, 1, 1) \
- F(GetHandler, 1, 1) \
- F(GetCallTrap, 1, 1) \
- F(GetConstructTrap, 1, 1) \
- F(Fix, 1, 1) \
- \
- /* Harmony sets */ \
- F(SetInitialize, 1, 1) \
- F(SetAdd, 2, 1) \
- F(SetHas, 2, 1) \
- F(SetDelete, 2, 1) \
- F(SetClear, 1, 1) \
- F(SetGetSize, 1, 1) \
- \
- F(SetIteratorInitialize, 3, 1) \
- F(SetIteratorNext, 2, 1) \
- \
- /* Harmony maps */ \
- F(MapInitialize, 1, 1) \
- F(MapGet, 2, 1) \
- F(MapHas, 2, 1) \
- F(MapDelete, 2, 1) \
- F(MapClear, 1, 1) \
- F(MapSet, 3, 1) \
- F(MapGetSize, 1, 1) \
- \
- F(MapIteratorInitialize, 3, 1) \
- F(MapIteratorNext, 2, 1) \
- \
- /* Harmony weak maps and sets */ \
- F(WeakCollectionInitialize, 1, 1) \
- F(WeakCollectionGet, 2, 1) \
- F(WeakCollectionHas, 2, 1) \
- F(WeakCollectionDelete, 2, 1) \
- F(WeakCollectionSet, 3, 1) \
- \
- /* Harmony events */ \
- F(EnqueueMicrotask, 1, 1) \
- F(RunMicrotasks, 0, 1) \
- \
- /* Harmony observe */ \
- F(IsObserved, 1, 1) \
- F(SetIsObserved, 1, 1) \
- F(GetObservationState, 0, 1) \
- F(ObservationWeakMapCreate, 0, 1) \
- F(ObserverObjectAndRecordHaveSameOrigin, 3, 1) \
- F(ObjectWasCreatedInCurrentOrigin, 1, 1) \
- F(GetObjectContextObjectObserve, 1, 1) \
- F(GetObjectContextObjectGetNotifier, 1, 1) \
- F(GetObjectContextNotifierPerformChange, 1, 1) \
- \
- /* Harmony typed arrays */ \
- F(ArrayBufferInitialize, 2, 1)\
- F(ArrayBufferSliceImpl, 3, 1) \
- F(ArrayBufferIsView, 1, 1) \
- F(ArrayBufferNeuter, 1, 1) \
- \
- F(TypedArrayInitializeFromArrayLike, 4, 1) \
- F(TypedArrayGetBuffer, 1, 1) \
- F(TypedArraySetFastCases, 3, 1) \
- \
- F(DataViewGetBuffer, 1, 1) \
- F(DataViewGetInt8, 3, 1) \
- F(DataViewGetUint8, 3, 1) \
- F(DataViewGetInt16, 3, 1) \
- F(DataViewGetUint16, 3, 1) \
- F(DataViewGetInt32, 3, 1) \
- F(DataViewGetUint32, 3, 1) \
- F(DataViewGetFloat32, 3, 1) \
- F(DataViewGetFloat64, 3, 1) \
- \
- F(DataViewSetInt8, 4, 1) \
- F(DataViewSetUint8, 4, 1) \
- F(DataViewSetInt16, 4, 1) \
- F(DataViewSetUint16, 4, 1) \
- F(DataViewSetInt32, 4, 1) \
- F(DataViewSetUint32, 4, 1) \
- F(DataViewSetFloat32, 4, 1) \
- F(DataViewSetFloat64, 4, 1) \
- \
- /* Statements */ \
- F(NewObjectFromBound, 1, 1) \
- \
- /* Declarations and initialization */ \
- F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \
- F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
- \
- /* Debugging */ \
- F(DebugPrint, 1, 1) \
- F(GlobalPrint, 1, 1) \
- F(DebugTrace, 0, 1) \
- F(TraceEnter, 0, 1) \
- F(TraceExit, 1, 1) \
- F(Abort, 1, 1) \
- F(AbortJS, 1, 1) \
- /* ES5 */ \
- F(OwnKeys, 1, 1) \
- \
- /* Message objects */ \
- F(MessageGetStartPosition, 1, 1) \
- F(MessageGetScript, 1, 1) \
- \
+#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
+ /* Reflection */ \
+ F(FunctionSetInstanceClassName, 2, 1) \
+ F(FunctionSetLength, 2, 1) \
+ F(FunctionSetPrototype, 2, 1) \
+ F(FunctionGetName, 1, 1) \
+ F(FunctionSetName, 2, 1) \
+ F(FunctionNameShouldPrintAsAnonymous, 1, 1) \
+ F(FunctionMarkNameShouldPrintAsAnonymous, 1, 1) \
+ F(FunctionIsGenerator, 1, 1) \
+ F(FunctionBindArguments, 4, 1) \
+ F(BoundFunctionGetBindings, 1, 1) \
+ F(FunctionRemovePrototype, 1, 1) \
+ F(FunctionGetSourceCode, 1, 1) \
+ F(FunctionGetScript, 1, 1) \
+ F(FunctionGetScriptSourcePosition, 1, 1) \
+ F(FunctionGetPositionForOffset, 2, 1) \
+ F(FunctionIsAPIFunction, 1, 1) \
+ F(FunctionIsBuiltin, 1, 1) \
+ F(GetScript, 1, 1) \
+ F(CollectStackTrace, 2, 1) \
+ F(GetV8Version, 0, 1) \
+ \
+ F(SetCode, 2, 1) \
+ \
+ F(CreateApiFunction, 2, 1) \
+ F(IsTemplate, 1, 1) \
+ F(GetTemplateField, 2, 1) \
+ F(DisableAccessChecks, 1, 1) \
+ F(EnableAccessChecks, 1, 1) \
+ \
+ /* Dates */ \
+ F(DateCurrentTime, 0, 1) \
+ F(DateParseString, 2, 1) \
+ F(DateLocalTimezone, 1, 1) \
+ F(DateToUTC, 1, 1) \
+ F(DateMakeDay, 2, 1) \
+ F(DateSetValue, 3, 1) \
+ F(DateCacheVersion, 0, 1) \
+ \
+ /* Globals */ \
+ F(CompileString, 2, 1) \
+ \
+ /* Eval */ \
+ F(GlobalProxy, 1, 1) \
+ F(IsAttachedGlobal, 1, 1) \
+ \
+ F(AddProperty, 4, 1) \
+ F(AddPropertyForTemplate, 4, 1) \
+ F(SetProperty, 4, 1) \
+ F(DefineDataPropertyUnchecked, 4, 1) \
+ F(DefineAccessorPropertyUnchecked, 5, 1) \
+ F(GetDataProperty, 2, 1) \
+ F(SetHiddenProperty, 3, 1) \
+ \
+ /* Arrays */ \
+ F(RemoveArrayHoles, 2, 1) \
+ F(GetArrayKeys, 2, 1) \
+ F(MoveArrayContents, 2, 1) \
+ F(EstimateNumberOfElements, 1, 1) \
+ \
+ /* Getters and Setters */ \
+ F(LookupAccessor, 3, 1) \
+ \
+ /* ES5 */ \
+ F(ObjectFreeze, 1, 1) \
+ \
+ /* Harmony modules */ \
+ F(IsJSModule, 1, 1) \
+ \
+ /* Harmony symbols */ \
+ F(CreateSymbol, 1, 1) \
+ F(CreatePrivateSymbol, 1, 1) \
+ F(CreateGlobalPrivateSymbol, 1, 1) \
+ F(NewSymbolWrapper, 1, 1) \
+ F(SymbolDescription, 1, 1) \
+ F(SymbolRegistry, 0, 1) \
+ F(SymbolIsPrivate, 1, 1) \
+ \
+ /* Harmony proxies */ \
+ F(CreateJSProxy, 2, 1) \
+ F(CreateJSFunctionProxy, 4, 1) \
+ F(IsJSProxy, 1, 1) \
+ F(IsJSFunctionProxy, 1, 1) \
+ F(GetHandler, 1, 1) \
+ F(GetCallTrap, 1, 1) \
+ F(GetConstructTrap, 1, 1) \
+ F(Fix, 1, 1) \
+ \
+ /* Harmony sets */ \
+ F(SetInitialize, 1, 1) \
+ F(SetAdd, 2, 1) \
+ F(SetHas, 2, 1) \
+ F(SetDelete, 2, 1) \
+ F(SetClear, 1, 1) \
+ F(SetGetSize, 1, 1) \
+ \
+ F(SetIteratorInitialize, 3, 1) \
+ F(SetIteratorNext, 2, 1) \
+ \
+ /* Harmony maps */ \
+ F(MapInitialize, 1, 1) \
+ F(MapGet, 2, 1) \
+ F(MapHas, 2, 1) \
+ F(MapDelete, 2, 1) \
+ F(MapClear, 1, 1) \
+ F(MapSet, 3, 1) \
+ F(MapGetSize, 1, 1) \
+ \
+ F(MapIteratorInitialize, 3, 1) \
+ F(MapIteratorNext, 2, 1) \
+ \
+ /* Harmony weak maps and sets */ \
+ F(WeakCollectionInitialize, 1, 1) \
+ F(WeakCollectionGet, 2, 1) \
+ F(WeakCollectionHas, 2, 1) \
+ F(WeakCollectionDelete, 2, 1) \
+ F(WeakCollectionSet, 3, 1) \
+ \
+ /* Harmony events */ \
+ F(EnqueueMicrotask, 1, 1) \
+ F(RunMicrotasks, 0, 1) \
+ \
+ /* Harmony observe */ \
+ F(IsObserved, 1, 1) \
+ F(SetIsObserved, 1, 1) \
+ F(GetObservationState, 0, 1) \
+ F(ObservationWeakMapCreate, 0, 1) \
+ F(ObserverObjectAndRecordHaveSameOrigin, 3, 1) \
+ F(ObjectWasCreatedInCurrentOrigin, 1, 1) \
+ F(GetObjectContextObjectObserve, 1, 1) \
+ F(GetObjectContextObjectGetNotifier, 1, 1) \
+ F(GetObjectContextNotifierPerformChange, 1, 1) \
+ \
+ /* Harmony typed arrays */ \
+ F(ArrayBufferInitialize, 2, 1) \
+ F(ArrayBufferSliceImpl, 3, 1) \
+ F(ArrayBufferIsView, 1, 1) \
+ F(ArrayBufferNeuter, 1, 1) \
+ \
+ F(TypedArrayInitializeFromArrayLike, 4, 1) \
+ F(TypedArrayGetBuffer, 1, 1) \
+ F(TypedArraySetFastCases, 3, 1) \
+ \
+ F(DataViewGetBuffer, 1, 1) \
+ F(DataViewGetInt8, 3, 1) \
+ F(DataViewGetUint8, 3, 1) \
+ F(DataViewGetInt16, 3, 1) \
+ F(DataViewGetUint16, 3, 1) \
+ F(DataViewGetInt32, 3, 1) \
+ F(DataViewGetUint32, 3, 1) \
+ F(DataViewGetFloat32, 3, 1) \
+ F(DataViewGetFloat64, 3, 1) \
+ \
+ F(DataViewSetInt8, 4, 1) \
+ F(DataViewSetUint8, 4, 1) \
+ F(DataViewSetInt16, 4, 1) \
+ F(DataViewSetUint16, 4, 1) \
+ F(DataViewSetInt32, 4, 1) \
+ F(DataViewSetUint32, 4, 1) \
+ F(DataViewSetFloat32, 4, 1) \
+ F(DataViewSetFloat64, 4, 1) \
+ \
+ /* Statements */ \
+ F(NewObjectFromBound, 1, 1) \
+ \
+ /* Declarations and initialization */ \
+ F(InitializeVarGlobal, 3, 1) \
+ F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
+ \
+ /* Debugging */ \
+ F(DebugPrint, 1, 1) \
+ F(GlobalPrint, 1, 1) \
+ F(DebugTrace, 0, 1) \
+ F(TraceEnter, 0, 1) \
+ F(TraceExit, 1, 1) \
+ F(Abort, 1, 1) \
+ F(AbortJS, 1, 1) \
+ /* ES5 */ \
+ F(OwnKeys, 1, 1) \
+ \
+ /* Message objects */ \
+ F(MessageGetStartPosition, 1, 1) \
+ F(MessageGetScript, 1, 1) \
+ \
/* Pseudo functions - handled as macros by parser */ \
- F(IS_VAR, 1, 1) \
- \
- /* expose boolean functions from objects-inl.h */ \
- F(HasFastSmiElements, 1, 1) \
- F(HasFastSmiOrObjectElements, 1, 1) \
- F(HasFastObjectElements, 1, 1) \
- F(HasFastDoubleElements, 1, 1) \
- F(HasFastHoleyElements, 1, 1) \
- F(HasDictionaryElements, 1, 1) \
- F(HasSloppyArgumentsElements, 1, 1) \
- F(HasExternalUint8ClampedElements, 1, 1) \
- F(HasExternalArrayElements, 1, 1) \
- F(HasExternalInt8Elements, 1, 1) \
- F(HasExternalUint8Elements, 1, 1) \
- F(HasExternalInt16Elements, 1, 1) \
- F(HasExternalUint16Elements, 1, 1) \
- F(HasExternalInt32Elements, 1, 1) \
- F(HasExternalUint32Elements, 1, 1) \
- F(HasExternalFloat32Elements, 1, 1) \
- F(HasExternalFloat64Elements, 1, 1) \
- F(HasFixedUint8ClampedElements, 1, 1) \
- F(HasFixedInt8Elements, 1, 1) \
- F(HasFixedUint8Elements, 1, 1) \
- F(HasFixedInt16Elements, 1, 1) \
- F(HasFixedUint16Elements, 1, 1) \
- F(HasFixedInt32Elements, 1, 1) \
- F(HasFixedUint32Elements, 1, 1) \
- F(HasFixedFloat32Elements, 1, 1) \
- F(HasFixedFloat64Elements, 1, 1) \
- F(HasFastProperties, 1, 1) \
- F(TransitionElementsKind, 2, 1) \
- F(HaveSameMap, 2, 1) \
+ F(IS_VAR, 1, 1) \
+ \
+ /* expose boolean functions from objects-inl.h */ \
+ F(HasFastSmiElements, 1, 1) \
+ F(HasFastSmiOrObjectElements, 1, 1) \
+ F(HasFastObjectElements, 1, 1) \
+ F(HasFastDoubleElements, 1, 1) \
+ F(HasFastHoleyElements, 1, 1) \
+ F(HasDictionaryElements, 1, 1) \
+ F(HasSloppyArgumentsElements, 1, 1) \
+ F(HasExternalUint8ClampedElements, 1, 1) \
+ F(HasExternalArrayElements, 1, 1) \
+ F(HasExternalInt8Elements, 1, 1) \
+ F(HasExternalUint8Elements, 1, 1) \
+ F(HasExternalInt16Elements, 1, 1) \
+ F(HasExternalUint16Elements, 1, 1) \
+ F(HasExternalInt32Elements, 1, 1) \
+ F(HasExternalUint32Elements, 1, 1) \
+ F(HasExternalFloat32Elements, 1, 1) \
+ F(HasExternalFloat64Elements, 1, 1) \
+ F(HasFixedUint8ClampedElements, 1, 1) \
+ F(HasFixedInt8Elements, 1, 1) \
+ F(HasFixedUint8Elements, 1, 1) \
+ F(HasFixedInt16Elements, 1, 1) \
+ F(HasFixedUint16Elements, 1, 1) \
+ F(HasFixedInt32Elements, 1, 1) \
+ F(HasFixedUint32Elements, 1, 1) \
+ F(HasFixedFloat32Elements, 1, 1) \
+ F(HasFixedFloat64Elements, 1, 1) \
+ F(HasFastProperties, 1, 1) \
+ F(TransitionElementsKind, 2, 1) \
+ F(HaveSameMap, 2, 1) \
F(IsJSGlobalProxy, 1, 1)
-#define RUNTIME_FUNCTION_LIST_ALWAYS_3(F) \
- /* String and Regexp */ \
- F(NumberToStringRT, 1, 1) \
- F(RegExpConstructResult, 3, 1) \
- F(RegExpExecRT, 4, 1) \
- F(StringAdd, 2, 1) \
- F(SubString, 3, 1) \
- F(InternalizeString, 1, 1) \
- F(StringCompare, 2, 1) \
- F(StringCharCodeAtRT, 2, 1) \
- F(GetFromCache, 2, 1) \
- \
- /* Compilation */ \
- F(CompileUnoptimized, 1, 1) \
- F(CompileOptimized, 2, 1) \
- F(TryInstallOptimizedCode, 1, 1) \
- F(NotifyDeoptimized, 1, 1) \
- F(NotifyStubFailure, 0, 1) \
- \
- /* Utilities */ \
- F(AllocateInNewSpace, 1, 1) \
- F(AllocateInTargetSpace, 2, 1) \
- F(AllocateHeapNumber, 0, 1) \
- F(NumberToSmi, 1, 1) \
- F(NumberToStringSkipCache, 1, 1) \
- \
- F(NewSloppyArguments, 3, 1) \
- F(NewStrictArguments, 3, 1) \
- \
- /* Harmony generators */ \
- F(CreateJSGeneratorObject, 0, 1) \
- F(SuspendJSGeneratorObject, 1, 1) \
- F(ResumeJSGeneratorObject, 3, 1) \
- F(ThrowGeneratorStateError, 1, 1) \
- \
- /* Arrays */ \
- F(ArrayConstructor, -1, 1) \
- F(InternalArrayConstructor, -1, 1) \
- \
- /* Literals */ \
- F(MaterializeRegExpLiteral, 4, 1)\
- F(CreateObjectLiteral, 4, 1) \
- F(CreateArrayLiteral, 4, 1) \
- F(CreateArrayLiteralStubBailout, 3, 1) \
- \
- /* Statements */ \
- F(NewClosure, 3, 1) \
- F(NewClosureFromStubFailure, 1, 1) \
- F(NewObject, 1, 1) \
- F(NewObjectWithAllocationSite, 2, 1) \
- F(FinalizeInstanceSize, 1, 1) \
- F(Throw, 1, 1) \
- F(ReThrow, 1, 1) \
- F(ThrowReferenceError, 1, 1) \
- F(ThrowNotDateError, 0, 1) \
- F(StackGuard, 0, 1) \
- F(Interrupt, 0, 1) \
- F(PromoteScheduledException, 0, 1) \
- \
- /* Contexts */ \
- F(NewGlobalContext, 2, 1) \
- F(NewFunctionContext, 1, 1) \
- F(PushWithContext, 2, 1) \
- F(PushCatchContext, 3, 1) \
- F(PushBlockContext, 2, 1) \
- F(PushModuleContext, 2, 1) \
- F(DeleteContextSlot, 2, 1) \
- F(LoadContextSlot, 2, 2) \
+#define RUNTIME_FUNCTION_LIST_ALWAYS_3(F) \
+ /* String and Regexp */ \
+ F(NumberToStringRT, 1, 1) \
+ F(RegExpConstructResult, 3, 1) \
+ F(RegExpExecRT, 4, 1) \
+ F(StringAdd, 2, 1) \
+ F(SubString, 3, 1) \
+ F(InternalizeString, 1, 1) \
+ F(StringCompare, 2, 1) \
+ F(StringCharCodeAtRT, 2, 1) \
+ F(GetFromCache, 2, 1) \
+ \
+ /* Compilation */ \
+ F(CompileUnoptimized, 1, 1) \
+ F(CompileOptimized, 2, 1) \
+ F(TryInstallOptimizedCode, 1, 1) \
+ F(NotifyDeoptimized, 1, 1) \
+ F(NotifyStubFailure, 0, 1) \
+ \
+ /* Utilities */ \
+ F(AllocateInNewSpace, 1, 1) \
+ F(AllocateInTargetSpace, 2, 1) \
+ F(AllocateHeapNumber, 0, 1) \
+ F(NumberToSmi, 1, 1) \
+ F(NumberToStringSkipCache, 1, 1) \
+ \
+ F(NewSloppyArguments, 3, 1) \
+ F(NewStrictArguments, 3, 1) \
+ \
+ /* Harmony generators */ \
+ F(CreateJSGeneratorObject, 0, 1) \
+ F(SuspendJSGeneratorObject, 1, 1) \
+ F(ResumeJSGeneratorObject, 3, 1) \
+ F(ThrowGeneratorStateError, 1, 1) \
+ \
+ /* Arrays */ \
+ F(ArrayConstructor, -1, 1) \
+ F(InternalArrayConstructor, -1, 1) \
+ \
+ /* Literals */ \
+ F(MaterializeRegExpLiteral, 4, 1) \
+ F(CreateObjectLiteral, 4, 1) \
+ F(CreateArrayLiteral, 4, 1) \
+ F(CreateArrayLiteralStubBailout, 3, 1) \
+ \
+ /* Statements */ \
+ F(NewClosure, 3, 1) \
+ F(NewClosureFromStubFailure, 1, 1) \
+ F(NewObject, 1, 1) \
+ F(NewObjectWithAllocationSite, 2, 1) \
+ F(FinalizeInstanceSize, 1, 1) \
+ F(Throw, 1, 1) \
+ F(ReThrow, 1, 1) \
+ F(ThrowReferenceError, 1, 1) \
+ F(ThrowNotDateError, 0, 1) \
+ F(StackGuard, 0, 1) \
+ F(Interrupt, 0, 1) \
+ F(PromoteScheduledException, 0, 1) \
+ \
+ /* Contexts */ \
+ F(NewGlobalContext, 2, 1) \
+ F(NewFunctionContext, 1, 1) \
+ F(PushWithContext, 2, 1) \
+ F(PushCatchContext, 3, 1) \
+ F(PushBlockContext, 2, 1) \
+ F(PushModuleContext, 2, 1) \
+ F(DeleteContextSlot, 2, 1) \
+ F(LoadContextSlot, 2, 2) \
F(LoadContextSlotNoReferenceError, 2, 2) \
- F(StoreContextSlot, 4, 1) \
- \
- /* Declarations and initialization */ \
- F(DeclareGlobals, 3, 1) \
- F(DeclareModules, 1, 1) \
- F(DeclareContextSlot, 4, 1) \
- F(InitializeConstGlobal, 2, 1) \
- F(InitializeConstContextSlot, 3, 1) \
- \
- /* Eval */ \
- F(ResolvePossiblyDirectEval, 5, 2) \
- \
- /* Maths */ \
- F(MathPowSlow, 2, 1) \
+ F(StoreLookupSlot, 4, 1) \
+ \
+ /* Declarations and initialization */ \
+ F(DeclareGlobals, 3, 1) \
+ F(DeclareModules, 1, 1) \
+ F(DeclareLookupSlot, 4, 1) \
+ F(InitializeConstGlobal, 2, 1) \
+ F(InitializeLegacyConstLookupSlot, 3, 1) \
+ \
+ /* Eval */ \
+ F(ResolvePossiblyDirectEval, 5, 2) \
+ \
+ /* Maths */ \
+ F(MathPowSlow, 2, 1) \
F(MathPowRT, 2, 1)
} else {
__ Push(Smi::FromInt(0)); // Indicates no initial value.
}
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
__ Push(variable->name());
__ Push(Smi::FromInt(NONE));
VisitForStackValue(declaration->fun());
- __ CallRuntime(Runtime::kDeclareContextSlot, 4);
+ __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
break;
}
}
}
-void FullCodeGenerator::EmitCallStoreContextSlot(
- Handle<String> name, StrictMode strict_mode) {
- __ Push(rax); // Value.
- __ Push(rsi); // Context.
- __ Push(name);
- __ Push(Smi::FromInt(strict_mode));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
-}
-
-
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
if (var->IsUnallocated()) {
__ Push(rax);
__ Push(rsi);
__ Push(var->name());
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+ __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
} else {
ASSERT(var->IsStackLocal() || var->IsContextSlot());
Label skip;
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
- if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
- } else {
- ASSERT(var->IsStackAllocated() || var->IsContextSlot());
- Label assign;
- MemOperand location = VarOperand(var, rcx);
- __ movp(rdx, location);
- __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &assign, Label::kNear);
- __ Push(var->name());
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- __ bind(&assign);
- EmitStoreToStackLocalOrContextSlot(var, location);
- }
+ ASSERT(!var->IsLookupSlot());
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, rcx);
+ __ movp(rdx, location);
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &assign, Label::kNear);
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&assign);
+ EmitStoreToStackLocalOrContextSlot(var, location);
} else if (!var->is_const_mode() || op == Token::INIT_CONST) {
- // Assignment to var or initializing assignment to let/const
- // in harmony mode.
if (var->IsLookupSlot()) {
- EmitCallStoreContextSlot(var->name(), strict_mode());
+ ASSERT(op == Token::ASSIGN || op == Token::INIT_VAR ||
+ op == Token::ASSIGN_ADD);
+ // Assignment to var.
+ __ Push(rax); // Value.
+ __ Push(rsi); // Context.
+ __ Push(var->name());
+ __ Push(Smi::FromInt(strict_mode()));
+ __ CallRuntime(Runtime::kStoreLookupSlot, 4);
} else {
+ // Assignment to var or initializing assignment to let/const in harmony
+ // mode.
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, rcx);
if (generate_debug_code_ && op == Token::INIT_LET) {
{ DeclarationContext context;
context.Check("var x; x",
1, // access
- 1, // declaration
- 2, // declaration + initialization
- EXPECT_RESULT, Undefined(CcTest::isolate()));
+ 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
}
{ DeclarationContext context;
context.Check("var x = 0; x",
1, // access
- 2, // declaration + initialization
- 2, // declaration + initialization
- EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
+ 1, // initialization
+ 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
}
{ DeclarationContext context;
{ DeclarationContext context;
context.Check("const x; x",
1, // access
- 2, // declaration + initialization
- 1, // declaration
- EXPECT_RESULT, Undefined(CcTest::isolate()));
+ 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
}
{ DeclarationContext context;
- // SB 0 - BUG 1213579
context.Check("const x = 0; x",
1, // access
- 2, // declaration + initialization
- 1, // declaration
- EXPECT_RESULT, Undefined(CcTest::isolate()));
- }
-}
-
-
-
-class PresentPropertyContext: public DeclarationContext {
- protected:
- virtual v8::Handle<Integer> Query(Local<String> key) {
- return Integer::New(isolate(), v8::None);
- }
-};
-
-
-
-TEST(Present) {
- HandleScope scope(CcTest::isolate());
-
- { PresentPropertyContext context;
- context.Check("var x; x",
- 1, // access
- 0,
- 2, // declaration + initialization
- EXPECT_EXCEPTION); // x is not defined!
- }
-
- { PresentPropertyContext context;
- context.Check("var x = 0; x",
- 1, // access
- 1, // initialization
- 2, // declaration + initialization
- EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
- }
-
- { PresentPropertyContext context;
- context.Check("function x() { }; x",
- 1, // access
0,
0,
- EXPECT_RESULT);
- }
-
- { PresentPropertyContext context;
- context.Check("const x; x",
- 1, // access
- 1, // initialization
- 1, // (re-)declaration
- EXPECT_RESULT, Undefined(CcTest::isolate()));
- }
-
- { PresentPropertyContext context;
- context.Check("const x = 0; x",
- 1, // access
- 1, // initialization
- 1, // (re-)declaration
EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
}
}
-
class AbsentPropertyContext: public DeclarationContext {
protected:
virtual v8::Handle<Integer> Query(Local<String> key) {
{ AbsentPropertyContext context;
context.Check("var x; x",
1, // access
- 1, // declaration
- 2, // declaration + initialization
- EXPECT_RESULT, Undefined(isolate));
+ 0, 0, EXPECT_RESULT, Undefined(isolate));
}
{ AbsentPropertyContext context;
context.Check("var x = 0; x",
1, // access
- 2, // declaration + initialization
- 2, // declaration + initialization
- EXPECT_RESULT, Number::New(isolate, 0));
+ 1, // initialization
+ 0, EXPECT_RESULT, Number::New(isolate, 0));
}
{ AbsentPropertyContext context;
{ AbsentPropertyContext context;
context.Check("const x; x",
1, // access
- 2, // declaration + initialization
- 1, // declaration
- EXPECT_RESULT, Undefined(isolate));
+ 0, 0, EXPECT_RESULT, Undefined(isolate));
}
{ AbsentPropertyContext context;
context.Check("const x = 0; x",
1, // access
- 2, // declaration + initialization
- 1, // declaration
- EXPECT_RESULT, Undefined(isolate)); // SB 0 - BUG 1213579
+ 0, 0, EXPECT_RESULT, Number::New(isolate, 0));
}
{ AbsentPropertyContext context;
context.Check("if (false) { var x = 0 }; x",
1, // access
- 1, // declaration
- 1, // declaration + initialization
- EXPECT_RESULT, Undefined(isolate));
+ 0, 0, EXPECT_RESULT, Undefined(isolate));
}
}
{ AppearingPropertyContext context;
context.Check("var x; x",
1, // access
- 1, // declaration
- 2, // declaration + initialization
- EXPECT_RESULT, Undefined(CcTest::isolate()));
+ 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
}
{ AppearingPropertyContext context;
context.Check("var x = 0; x",
1, // access
- 2, // declaration + initialization
- 2, // declaration + initialization
- EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
+ 1, // initialization
+ 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
}
{ AppearingPropertyContext context;
{ AppearingPropertyContext context;
context.Check("const x; x",
1, // access
- 2, // declaration + initialization
- 1, // declaration
- EXPECT_RESULT, Undefined(CcTest::isolate()));
+ 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate()));
}
{ AppearingPropertyContext context;
context.Check("const x = 0; x",
1, // access
- 2, // declaration + initialization
- 1, // declaration
- EXPECT_RESULT, Undefined(CcTest::isolate()));
- // Result is undefined because declaration succeeded but
- // initialization to 0 failed (due to context behavior).
- }
-}
-
-
-
-class ReappearingPropertyContext: public DeclarationContext {
- public:
- enum State {
- DECLARE,
- DONT_DECLARE,
- INITIALIZE,
- UNKNOWN
- };
-
- ReappearingPropertyContext() : state_(DECLARE) { }
-
- protected:
- virtual v8::Handle<Integer> Query(Local<String> key) {
- switch (state_) {
- case DECLARE:
- // Force the first declaration by returning that
- // the property is absent.
- state_ = DONT_DECLARE;
- return Handle<Integer>();
- case DONT_DECLARE:
- // Ignore the second declaration by returning
- // that the property is already there.
- state_ = INITIALIZE;
- return Integer::New(isolate(), v8::None);
- case INITIALIZE:
- // Force an initialization by returning that
- // the property is absent. This will make sure
- // that the setter is called and it will not
- // lead to redeclaration conflicts (yet).
- state_ = UNKNOWN;
- return Handle<Integer>();
- default:
- CHECK(state_ == UNKNOWN);
- break;
- }
- // Do the lookup in the object.
- return Handle<Integer>();
- }
-
- private:
- State state_;
-};
-
-
-TEST(Reappearing) {
- v8::V8::Initialize();
- HandleScope scope(CcTest::isolate());
-
- { ReappearingPropertyContext context;
- context.Check("const x; var x = 0",
- 0,
- 3, // const declaration+initialization, var initialization
- 3, // 2 x declaration + var initialization
- EXPECT_RESULT, Undefined(CcTest::isolate()));
+ 0, 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
}
}
HandleScope scope(CcTest::isolate());
{ ExistsInHiddenPrototypeContext context;
- context.Check("var x; x",
- 1, // access
- 0,
- 2, // declaration + initialization
- EXPECT_EXCEPTION); // x is not defined!
+ context.Check("var x; x", 0, 0, 0, EXPECT_RESULT,
+ Undefined(CcTest::isolate()));
}
{ ExistsInHiddenPrototypeContext context;
- context.Check("var x = 0; x",
- 1, // access
- 1, // initialization
- 2, // declaration + initialization
- EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
+ context.Check("var x = 0; x", 0, 0, 0, EXPECT_RESULT,
+ Number::New(CcTest::isolate(), 0));
}
{ ExistsInHiddenPrototypeContext context;
// TODO(mstarzinger): The semantics of global const is vague.
{ ExistsInHiddenPrototypeContext context;
- context.Check("const x; x",
- 0,
- 0,
- 1, // (re-)declaration
- EXPECT_RESULT, Undefined(CcTest::isolate()));
+ context.Check("const x; x", 0, 0, 0, EXPECT_RESULT,
+ Undefined(CcTest::isolate()));
}
// TODO(mstarzinger): The semantics of global const is vague.
{ ExistsInHiddenPrototypeContext context;
- context.Check("const x = 0; x",
- 0,
- 0,
- 1, // (re-)declaration
- EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
+ context.Check("const x = 0; x", 0, 0, 0, EXPECT_RESULT,
+ Number::New(CcTest::isolate(), 0));
}
}
EXPECT_RESULT, Number::New(isolate, 1));
context.Check("var x = 2; x",
EXPECT_RESULT, Number::New(isolate, 2));
- context.Check("const x = 3; x",
- EXPECT_RESULT, Number::New(isolate, 3));
- context.Check("const x = 4; x",
- EXPECT_RESULT, Number::New(isolate, 4));
+ context.Check("const x = 3; x", EXPECT_EXCEPTION);
+ context.Check("const x = 4; x", EXPECT_EXCEPTION);
context.Check("x = 5; x",
EXPECT_RESULT, Number::New(isolate, 5));
context.Check("var x = 6; x",
EXPECT_RESULT, Number::New(isolate, 1));
context.Check("var x = 2; x", // assignment ignored
EXPECT_RESULT, Number::New(isolate, 1));
- context.Check("const x = 3; x",
- EXPECT_RESULT, Number::New(isolate, 1));
+ context.Check("const x = 3; x", EXPECT_EXCEPTION);
context.Check("x = 4; x", // assignment ignored
EXPECT_RESULT, Number::New(isolate, 1));
context.Check("var x = 5; x", // assignment ignored
var source =
// Deleting 'x' removes the local const property.
"delete x;" +
- // Initialization turns into assignment to global 'x'.
+ // Initialization redefines global 'x'.
"const x = 3; assertEquals(3, x);" +
- // No constness of the global 'x'.
- "x = 4; assertEquals(4, x);";
+ // Test constness of the global 'x'.
+ "x = 4; assertEquals(3, x);";
eval(source);
}
testIntroduceGlobal();
-assertEquals(4, x);
+assertEquals("undefined", typeof x);
function testAssignExistingGlobal() {
var source =
// Delete 'x' to remove the local const property.
"delete x;" +
- // Initialization turns into assignment to global 'x'.
+ // Initialization redefines global 'x'.
"const x = 5; assertEquals(5, x);" +
- // No constness of the global 'x'.
- "x = 6; assertEquals(6, x);";
+ // Test constness of the global 'x'.
+ "x = 6; assertEquals(5, x);";
eval(source);
}
testAssignExistingGlobal();
-assertEquals(6, x);
+assertEquals("undefined", typeof x);
function testAssignmentArgument(x) {
function local() {
eval(source);
}
local();
- assertEquals(7, x);
+ assertEquals("undefined", typeof x);
}
for (var i = 0; i < 5; i++) {
}
%OptimizeFunctionOnNextCall(testAssignmentArgument);
testAssignmentArgument();
-assertEquals(6, x);
+assertEquals("undefined", typeof x);
__defineSetter__('x', function() { throw 42; });
-function testAssignGlobalThrows() {
- // Initialization turns into assignment to global 'x' which
- // throws an exception.
- var source = "delete x; const x = 8";
+var finished = false;
+function testRedefineGlobal() {
+ // Initialization redefines global 'x'.
+ var source = "delete x; const x = 8; finished = true;";
eval(source);
}
-assertThrows("testAssignGlobalThrows()");
+testRedefineGlobal();
+assertTrue(finished);
function testInitFastCaseExtension() {
var source = "const x = 9; assertEquals(9, x); x = 10; assertEquals(9, x)";
eval(source);
}
local();
- assertEquals(13, x);
+ assertEquals(12, x);
}
testAssignSurroundingContextSlot();
}
-// NOTE: TestGlobal usually only tests the given string in the context
-// of a global object in dictionary mode. This is because we use
-// delete to get rid of any added properties.
-function TestGlobal(s,e) {
- // Collect the global properties before the call.
- var properties = [];
- for (var key in this) properties.push(key);
- // Compute the result.
- var result;
- try {
- var code = s + (e ? "; $$$result=" + e : "");
- if (this.execScript) {
- execScript(code);
- } else {
- this.eval(code);
- }
- // Avoid issues if $$$result is not defined by
- // reading it through this.
- result = this.$$$result;
- } catch (x) {
- result = CheckException(x);
- }
- // Get rid of any introduced global properties before
- // returning the result.
- for (var key in this) {
- if (properties.indexOf(key) == -1) delete this[key];
- }
- return result;
-}
-
-
function TestContext(s,e) {
try {
// Use a with-statement to force the system to do dynamic
var msg = s;
if (opt_e) { e = opt_e; msg += "; " + opt_e; }
assertEquals(expected, TestLocal(s,e), "local:'" + msg + "'");
- // Redeclarations of global consts do not throw, they are silently ignored.
- assertEquals(42, TestGlobal(s, 42), "global:'" + msg + "'");
assertEquals(expected, TestContext(s,e), "context:'" + msg + "'");
}
// Eval first definition.
TestAll("TypeError", 'eval("' + def0 +'"); ' + def1);
// Eval second definition.
- TestAll("TypeError", def0 + '; eval("' + def1 + '")');
+ TestAll("TypeError", def0 + '; eval("' + def1 +'")');
// Eval both definitions separately.
TestAll("TypeError", 'eval("' + def0 +'"); eval("' + def1 + '")');
}
assertEquals(original_undef, undefined, "undefined got overwritten");
undefined = original_undef;
-var a; const a; const a = 1;
-assertEquals(1, a, "a has wrong value");
-a = 2;
-assertEquals(2, a, "a should be writable");
-
-var b = 1; const b = 2;
-assertEquals(2, b, "b has wrong value");
-
-var c = 1; const c = 2; const c = 3;
-assertEquals(3, c, "c has wrong value");
-
-const d = 1; const d = 2;
-assertEquals(1, d, "d has wrong value");
-
-const e = 1; var e = 2;
+const e = 1; eval('var e = 2');
assertEquals(1, e, "e has wrong value");
-const f = 1; const f;
-assertEquals(1, f, "f has wrong value");
-
-var g; const g = 1;
-assertEquals(1, g, "g has wrong value");
-g = 2;
-assertEquals(2, g, "g should be writable");
-
-const h; var h = 1;
-assertEquals(undefined,h, "h has wrong value");
+const h; eval('var h = 1');
+assertEquals(undefined, h, "h has wrong value");
eval("Object.defineProperty(this, 'i', { writable: true });"
+ "const i = 7;"
+ "assertEquals(7, i, \"i has wrong value\");");
var global = this;
-assertThrows(function() {
- Object.defineProperty(global, 'j', { writable: true })
-}, TypeError);
-const j = 2; // This is what makes the function above throw, because the
-// const declaration gets hoisted and makes the property non-configurable.
+Object.defineProperty(global, 'j', { value: 100, writable: true });
+assertEquals(100, j);
+// The const declaration stays configurable, so the declaration above goes
+// through even though the const declaration is hoisted above.
+const j = 2;
assertEquals(2, j, "j has wrong value");
-var k = 1; const k;
-// You could argue about the expected result here. For now, the winning
-// argument is that "const k;" is equivalent to "const k = undefined;".
-assertEquals(undefined, k, "k has wrong value");
+var k = 1;
+try { eval('const k'); } catch(e) { }
+assertEquals(1, k, "k has wrong value");
+try { eval('const k = 10'); } catch(e) { }
+assertEquals(1, k, "k has wrong value");
assertEquals(0, b);
try { eval("var b = 1"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
assertEquals(0, b);
+assertEquals(0, caught);
eval("var c");
try { eval("const c"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
assertTrue(typeof c == 'undefined');
+assertEquals(1, caught);
try { eval("const c = 1"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
-assertEquals(1, c);
+assertEquals(undefined, c);
+assertEquals(2, caught);
eval("var d = 0");
try { eval("const d"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
-assertEquals(undefined, d);
+assertEquals(0, d);
+assertEquals(3, caught);
try { eval("const d = 1"); } catch (e) { caught++; assertTrue(e instanceof TypeError); }
-assertEquals(1, d);
-
-assertEquals(0, caught);
+assertEquals(0, d);
+assertEquals(4, caught);
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --es52_globals
-
var setter_value = 0;
this.__defineSetter__("a", function(v) { setter_value = v; });
assertFalse("value" in Object.getOwnPropertyDescriptor(this, "a"));
eval("with({}) { eval('var a = 2') }");
-assertEquals(2, setter_value);
+assertTrue("get" in Object.getOwnPropertyDescriptor(this, "a"));
assertFalse("value" in Object.getOwnPropertyDescriptor(this, "a"));
+assertEquals(2, setter_value);
// Function declarations are treated specially to match Safari. We do
// not call setters for them.
this.__defineSetter__("b", function(v) { setter_value = v; });
try {
eval("const b = 3");
-} catch(e) {
- assertUnreachable();
-}
-assertEquals(3, setter_value);
+} catch(e) { }
+assertEquals(2, setter_value);
try {
eval("with({}) { eval('const b = 23') }");
assertTrue(e instanceof TypeError);
caught = true;
}
-assertFalse(caught);
+assertTrue(caught);
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-__defineSetter__('x', function() { });
+Object.defineProperty(this, 'x', {set: function() { }});
Object.freeze(this);
-eval('const x = 1');
+eval('"use strict"; x = 20;');
# We do not correctly handle assignments within "with"
'ecma_3/Statements/12.10-01': [FAIL],
- # We do not throw an exception when a const is redeclared.
- # (We only fail section 1 of the test.)
- 'js1_5/Regress/regress-103602': [FAIL],
-
##################### MOZILLA EXTENSION TESTS #####################
'ecma/extensions/15.1.2.1-1': [FAIL_OK],
# to parse them!
EXPECTED_FUNCTION_COUNT = 417
EXPECTED_FUZZABLE_COUNT = 332
-EXPECTED_CCTEST_COUNT = 6
+EXPECTED_CCTEST_COUNT = 9
EXPECTED_UNKNOWN_COUNT = 4
EXPECTED_BUILTINS_COUNT = 810