MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
Handle<Object> prototype) {
- DCHECK(function->should_have_prototype());
+ DCHECK(function->IsConstructor());
Isolate* isolate = function->GetIsolate();
return SetFunctionPrototype(isolate, function, prototype);
}
// Mark instance as callable in the map.
if (!obj->instance_call_handler()->IsUndefined()) {
map->set_is_callable();
+ map->set_is_constructor(true);
}
// Recursively copy parent instance templates' accessors,
}
+// static
+void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- r0 : the number of arguments (not including the receiver)
+ // -- r1 : the constructor to call (checked to be a JSFunctionProxy)
+ // -- r3 : the original constructor (either the same as the constructor or
+ // the JSFunction on which new was invoked initially)
+ // -----------------------------------
+
+ // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+ __ ldr(r1, FieldMemOperand(r1, JSFunctionProxy::kConstructTrapOffset));
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+}
+
+
// static
void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// the JSFunction on which new was invoked initially)
// -----------------------------------
- Label non_callable, non_function;
- __ JumpIfSmi(r1, &non_callable);
- __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
+ // Check if target has a [[Construct]] internal method.
+ Label non_constructor;
+ __ JumpIfSmi(r1, &non_constructor);
+ __ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldrb(r2, FieldMemOperand(r4, Map::kBitFieldOffset));
+ __ tst(r2, Operand(1 << Map::kIsConstructor));
+ __ b(eq, &non_constructor);
+
+ // Dispatch based on instance type.
+ __ CompareInstanceType(r4, r5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq);
__ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
- __ b(ne, &non_function);
-
- // 1. Construct of function proxy.
- // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
- __ ldr(r1, FieldMemOperand(r1, JSFunctionProxy::kConstructTrapOffset));
- __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+ __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
+ eq);
- // 2. Construct of something that else, which might have a [[Construct]]
- // internal method (if not we raise an exception).
- __ bind(&non_function);
- // Check if target has a [[Call]] internal method.
- // TODO(bmeurer): This shoud use IsConstructor once available.
- __ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset));
- __ tst(r4, Operand(1 << Map::kIsCallable));
- __ b(eq, &non_callable);
- // Overwrite the original receiver the (original) target.
- __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
- // Let the "call_as_constructor_delegate" take care of the rest.
- __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r1);
- __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+ // Called Construct on an exotic Object with a [[Construct]] internal method.
+ {
+ // Overwrite the original receiver with the (original) target.
+ __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+ // Let the "call_as_constructor_delegate" take care of the rest.
+ __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, r1);
+ __ Jump(masm->isolate()->builtins()->CallFunction(),
+ RelocInfo::CODE_TARGET);
+ }
- // 3. Construct of something that is not callable.
- __ bind(&non_callable);
+ // Called Construct on an Object that doesn't have a [[Construct]] internal
+ // method.
+ __ bind(&non_constructor);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r1);
}
+// static
+void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- x0 : the number of arguments (not including the receiver)
+ // -- x1 : the constructor to call (checked to be a JSFunctionProxy)
+ // -- x3 : the original constructor (either the same as the constructor or
+ // the JSFunction on which new was invoked initially)
+ // -----------------------------------
+
+ // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+ __ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kConstructTrapOffset));
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+}
+
+
// static
void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// the JSFunction on which new was invoked initially)
// -----------------------------------
- Label non_callable, non_function;
- __ JumpIfSmi(x1, &non_callable);
- __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
+ // Check if target has a [[Construct]] internal method.
+ Label non_constructor;
+ __ JumpIfSmi(x1, &non_constructor);
+ __ Ldr(x4, FieldMemOperand(x1, HeapObject::kMapOffset));
+ __ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
+ __ TestAndBranchIfAllClear(x2, 1 << Map::kIsConstructor, &non_constructor);
+
+ // Dispatch based on instance type.
+ __ CompareInstanceType(x4, x5, JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq);
__ Cmp(x5, JS_FUNCTION_PROXY_TYPE);
- __ B(ne, &non_function);
-
- // 1. Construct of function proxy.
- // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
- __ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kConstructTrapOffset));
- __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+ __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
+ eq);
- // 2. Construct of something that else, which might have a [[Construct]]
- // internal method (if not we raise an exception).
- __ Bind(&non_function);
- // Check if target has a [[Call]] internal method.
- // TODO(bmeurer): This shoud use IsConstructor once available.
- __ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset));
- __ TestAndBranchIfAllClear(x4, 1 << Map::kIsCallable, &non_callable);
- // Overwrite the original receiver with the (original) target.
- __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
- // Let the "call_as_constructor_delegate" take care of the rest.
- __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1);
- __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+ // Called Construct on an exotic Object with a [[Construct]] internal method.
+ {
+ // Overwrite the original receiver with the (original) target.
+ __ Poke(x1, Operand(x0, LSL, kXRegSizeLog2));
+ // Let the "call_as_constructor_delegate" take care of the rest.
+ __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, x1);
+ __ Jump(masm->isolate()->builtins()->CallFunction(),
+ RelocInfo::CODE_TARGET);
+ }
- // 3. Construct of something that is not callable.
- __ bind(&non_callable);
+ // Called Construct on an Object that doesn't have a [[Construct]] internal
+ // method.
+ __ bind(&non_constructor);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(x1);
Handle<Map> Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetFunctionInstanceDescriptor(map, function_mode);
- map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
+ map->set_is_constructor(IsFunctionModeWithPrototype(function_mode));
map->set_is_callable();
return map;
}
FunctionMode function_mode, Handle<JSFunction> empty_function) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetStrictFunctionInstanceDescriptor(map, function_mode);
- map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
+ map->set_is_constructor(IsFunctionModeWithPrototype(function_mode));
map->set_is_callable();
Map::SetPrototype(map, empty_function);
return map;
Handle<JSFunction> empty_function, bool is_constructor) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
SetStrongFunctionInstanceDescriptor(map);
- map->set_function_with_prototype(is_constructor);
+ map->set_is_constructor(is_constructor);
Map::SetPrototype(map, empty_function);
map->set_is_callable();
map->set_is_extensible(is_constructor);
}
// @@iterator method is added later.
- map->set_function_with_prototype(true);
map->SetInObjectProperties(2);
native_context()->set_sloppy_arguments_map(*map);
}
// @@iterator method is added later.
- map->set_function_with_prototype(true);
DCHECK_EQ(native_context()->object_function()->prototype(),
*isolate->initial_object_prototype());
Map::SetPrototype(map, isolate->initial_object_prototype());
V(Call, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(ConstructFunction, BUILTIN, UNINITIALIZED, kNoExtraICState) \
+ V(ConstructProxy, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(Construct, BUILTIN, UNINITIALIZED, kNoExtraICState) \
\
V(PushArgsAndCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \
// ES6 section 9.2.2 [[Construct]] ( argumentsList, newTarget)
static void Generate_ConstructFunction(MacroAssembler* masm);
+ // ES6 section 9.5.14 [[Construct]] ( argumentsList, newTarget)
+ static void Generate_ConstructProxy(MacroAssembler* masm);
// ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget])
static void Generate_Construct(MacroAssembler* masm);
: SLOPPY_GENERATOR_FUNCTION_MAP_INDEX;
}
- if (IsConstructor(kind)) {
+ if (IsClassConstructor(kind)) {
// Use strict function map (no own "caller" / "arguments")
return is_strong(language_mode) ? STRONG_CONSTRUCTOR_MAP_INDEX
: STRICT_FUNCTION_MAP_INDEX;
Handle<Map> map = NewMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
Map::SetPrototype(map, prototype);
map->set_is_callable();
+ map->set_is_constructor(construct_trap->IsCallable());
// Allocate the proxy object.
Handle<JSFunctionProxy> result = New<JSFunctionProxy>(map, NEW_SPACE);
// Functions require some minimal initialization.
if (type == JS_FUNCTION_TYPE) {
- map->set_function_with_prototype(true);
+ map->set_is_constructor(true);
map->set_is_callable();
Handle<JSFunction> js_function = Handle<JSFunction>::cast(proxy);
InitializeFunction(js_function, shared.ToHandleChecked(), context);
}
-inline bool IsConstructor(FunctionKind kind) {
+inline bool IsClassConstructor(FunctionKind kind) {
DCHECK(IsValidFunctionKind(kind));
return kind &
(FunctionKind::kBaseConstructor | FunctionKind::kSubclassConstructor |
if (!CanInlinePropertyAccess(map_)) return false;
if (IsJSObjectFieldAccessor()) return IsLoad();
if (IsJSArrayBufferViewFieldAccessor()) return IsLoad();
- if (map_->function_with_prototype() && !map_->has_non_instance_prototype() &&
+ if (map_->IsJSFunctionMap() && map_->is_constructor() &&
+ !map_->has_non_instance_prototype() &&
name_.is_identical_to(isolate()->factory()->prototype_string())) {
return IsLoad();
}
}
if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
- info->map()->function_with_prototype()) {
+ info->map()->IsJSFunctionMap() && info->map()->is_constructor()) {
DCHECK(!info->map()->has_non_instance_prototype());
return New<HLoadFunctionPrototype>(checked_object);
}
}
+// static
+void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : the number of arguments (not including the receiver)
+ // -- edx : the original constructor (either the same as the constructor or
+ // the JSFunction on which new was invoked initially)
+ // -- edi : the constructor to call (checked to be a JSFunctionProxy)
+ // -----------------------------------
+
+ // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+ __ mov(edi, FieldOperand(edi, JSFunctionProxy::kConstructTrapOffset));
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+}
+
+
// static
void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- edi : the constructor to call (can be any Object)
// -----------------------------------
- Label non_callable, non_function;
- __ JumpIfSmi(edi, &non_callable);
- __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
+ // Check if target has a [[Construct]] internal method.
+ Label non_constructor;
+ __ JumpIfSmi(edi, &non_constructor, Label::kNear);
+ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
+ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
+ __ j(zero, &non_constructor, Label::kNear);
+
+ // Dispatch based on instance type.
+ __ CmpInstanceType(ecx, JS_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
- __ j(not_equal, &non_function, Label::kNear);
-
- // 1. Construct of function proxy.
- // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
- __ mov(edi, FieldOperand(edi, JSFunctionProxy::kConstructTrapOffset));
- __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+ __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
+ RelocInfo::CODE_TARGET);
- // 2. Construct of something else, which might have a [[Construct]] internal
- // method (if not we raise an exception).
- __ bind(&non_function);
- // Check if target has a [[Call]] internal method.
- // TODO(bmeurer): This shoud use IsConstructor once available.
- __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
- __ j(zero, &non_callable, Label::kNear);
- // Overwrite the original receiver with the (original) target.
- __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
- // Let the "call_as_constructor_delegate" take care of the rest.
- __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
- __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+ // Called Construct on an exotic Object with a [[Construct]] internal method.
+ {
+ // Overwrite the original receiver with the (original) target.
+ __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
+ // Let the "call_as_constructor_delegate" take care of the rest.
+ __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
+ __ Jump(masm->isolate()->builtins()->CallFunction(),
+ RelocInfo::CODE_TARGET);
+ }
- // 3. Construct of something that is not callable.
- __ bind(&non_callable);
+ // Called Construct on an Object that doesn't have a [[Construct]] internal
+ // method.
+ __ bind(&non_constructor);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(edi);
// Use specialized code for getting prototype of functions.
if (receiver->IsJSFunction() &&
Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
- Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
+ receiver->IsConstructor() &&
!Handle<JSFunction>::cast(receiver)
->map()
->has_non_instance_prototype()) {
}
+// static
+void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : the number of arguments (not including the receiver)
+ // -- a1 : the constructor to call (checked to be a JSFunctionProxy)
+ // -- a3 : the original constructor (either the same as the constructor or
+ // the JSFunction on which new was invoked initially)
+ // -----------------------------------
+
+ // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+ __ lw(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+}
+
+
// static
void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// the JSFunction on which new was invoked initially)
// -----------------------------------
- Label non_callable, non_function;
- __ JumpIfSmi(a1, &non_callable);
- __ GetObjectType(a1, t1, t2);
+ // Check if target has a [[Construct]] internal method.
+ Label non_constructor;
+ __ JumpIfSmi(a1, &non_constructor);
+ __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
+ __ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
+ __ And(t2, t2, Operand(1 << Map::kIsCallable));
+ __ Branch(&non_constructor, eq, t2, Operand(zero_reg));
+
+ // Dispatch based on instance type.
+ __ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
- __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
-
- // 1. Construct of function proxy.
- // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
- __ lw(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
- __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+ __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
+ eq, t2, Operand(JS_FUNCTION_PROXY_TYPE));
- // 2. Construct of something that else, which might have a [[Construct]]
- // internal method (if not we raise an exception).
- __ bind(&non_function);
- // Check if target has a [[Call]] internal method.
- // TODO(bmeurer): This shoud use IsConstructor once available.
- __ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
- __ And(t1, t1, Operand(1 << Map::kIsCallable));
- __ Branch(&non_callable, eq, t1, Operand(zero_reg));
- // Overwrite the original receiver with the (original) target.
- __ sll(at, a0, kPointerSizeLog2);
- __ addu(at, sp, at);
- __ sw(a1, MemOperand(at));
- // Let the "call_as_constructor_delegate" take care of the rest.
- __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
- __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+ // Called Construct on an exotic Object with a [[Construct]] internal method.
+ {
+ // Overwrite the original receiver with the (original) target.
+ __ sll(at, a0, kPointerSizeLog2);
+ __ addu(at, sp, at);
+ __ sw(a1, MemOperand(at));
+ // Let the "call_as_constructor_delegate" take care of the rest.
+ __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
+ __ Jump(masm->isolate()->builtins()->CallFunction(),
+ RelocInfo::CODE_TARGET);
+ }
- // 3. Construct of something that is not callable.
- __ bind(&non_callable);
+ // Called Construct on an Object that doesn't have a [[Construct]] internal
+ // method.
+ __ bind(&non_constructor);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
}
+// static
+void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : the number of arguments (not including the receiver)
+ // -- a1 : the constructor to call (checked to be a JSFunctionProxy)
+ // -- a3 : the original constructor (either the same as the constructor or
+ // the JSFunction on which new was invoked initially)
+ // -----------------------------------
+
+ // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+ __ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+}
+
+
// static
void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// the JSFunction on which new was invoked initially)
// -----------------------------------
- Label non_callable, non_function;
- __ JumpIfSmi(a1, &non_callable);
- __ GetObjectType(a1, t1, t2);
+ // Check if target has a [[Construct]] internal method.
+ Label non_constructor;
+ __ JumpIfSmi(a1, &non_constructor);
+ __ ld(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
+ __ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
+ __ And(t2, t2, Operand(1 << Map::kIsCallable));
+ __ Branch(&non_constructor, eq, t2, Operand(zero_reg));
+
+ // Dispatch based on instance type.
+ __ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
- __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE));
-
- // 1. Construct of function proxy.
- // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
- __ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
- __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+ __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
+ eq, t2, Operand(JS_FUNCTION_PROXY_TYPE));
- // 2. Construct of something that else, which might have a [[Construct]]
- // internal method (if not we raise an exception).
- __ bind(&non_function);
- // Check if target has a [[Call]] internal method.
- // TODO(bmeurer): This shoud use IsConstructor once available.
- __ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
- __ And(t1, t1, Operand(1 << Map::kIsCallable));
- __ Branch(&non_callable, eq, t1, Operand(zero_reg));
- // Overwrite the original receiver with the (original) target.
- __ dsll(at, a0, kPointerSizeLog2);
- __ daddu(at, sp, at);
- __ sd(a1, MemOperand(at));
- // Let the "call_as_constructor_delegate" take care of the rest.
- __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
- __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+ // Called Construct on an exotic Object with a [[Construct]] internal method.
+ {
+ // Overwrite the original receiver with the (original) target.
+ __ dsll(at, a0, kPointerSizeLog2);
+ __ daddu(at, sp, at);
+ __ sd(a1, MemOperand(at));
+ // Let the "call_as_constructor_delegate" take care of the rest.
+ __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, a1);
+ __ Jump(masm->isolate()->builtins()->CallFunction(),
+ RelocInfo::CODE_TARGET);
+ }
- // 3. Construct of something that is not callable.
- __ bind(&non_callable);
+ // Called Construct on an Object that doesn't have a [[Construct]] internal
+ // method.
+ __ bind(&non_constructor);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
} else {
HeapObject::cast(this)->HeapObjectVerify();
}
+ CHECK(!IsConstructor() || IsCallable());
}
void Smi::SmiVerify() {
CHECK(IsSmi());
CHECK(!IsCallable());
+ CHECK(!IsConstructor());
}
}
+bool Object::IsConstructor() const {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map()->is_constructor();
+}
+
+
bool Object::IsSpecObject() const {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() >= FIRST_SPEC_OBJECT_TYPE;
}
-void Map::set_function_with_prototype(bool value) {
- set_bit_field(FunctionWithPrototype::update(bit_field(), value));
+void Map::set_is_constructor(bool value) {
+ if (value) {
+ set_bit_field(bit_field() | (1 << kIsConstructor));
+ } else {
+ set_bit_field(bit_field() & ~(1 << kIsConstructor));
+ }
}
-bool Map::function_with_prototype() {
- return FunctionWithPrototype::decode(bit_field());
+bool Map::is_constructor() const {
+ return ((1 << kIsConstructor) & bit_field()) != 0;
}
return instance_type() >= FIRST_JS_OBJECT_TYPE;
}
bool Map::IsJSArrayMap() { return instance_type() == JS_ARRAY_TYPE; }
+bool Map::IsJSFunctionMap() { return instance_type() == JS_FUNCTION_TYPE; }
bool Map::IsStringMap() { return instance_type() < FIRST_NONSTRING_TYPE; }
bool Map::IsJSProxyMap() {
InstanceType type = instance_type();
}
-bool JSFunction::should_have_prototype() {
- return map()->function_with_prototype();
-}
-
-
bool JSFunction::is_compiled() {
Builtins* builtins = GetIsolate()->builtins();
return code() != builtins->builtin(Builtins::kCompileLazy) &&
if (has_indexed_interceptor()) os << " - indexed_interceptor\n";
if (is_undetectable()) os << " - undetectable\n";
if (is_callable()) os << " - callable\n";
+ if (is_constructor()) os << " - constructor\n";
if (is_access_check_needed()) os << " - access_check_needed\n";
if (!is_extensible()) os << " - non-extensible\n";
if (is_observed()) os << " - observed\n";
void JSFunction::SetPrototype(Handle<JSFunction> function,
Handle<Object> value) {
- DCHECK(function->should_have_prototype());
+ DCHECK(function->IsConstructor());
Handle<Object> construct_prototype = value;
// If the value is not a JSReceiver, store the value in the map's
// ES6, section 7.2.3 IsCallable.
INLINE(bool IsCallable() const);
+ // ES6, section 7.2.4 IsConstructor.
+ INLINE(bool IsConstructor() const);
+
INLINE(bool IsSpecObject()) const;
INLINE(bool IsTemplateInfo()) const;
INLINE(bool IsNameDictionary() const);
inline void set_non_instance_prototype(bool value);
inline bool has_non_instance_prototype();
- // Tells whether function has special prototype property. If not, prototype
- // property will not be created when accessed (will return undefined),
- // and construction from this function will not be allowed.
- inline void set_function_with_prototype(bool value);
- inline bool function_with_prototype();
+ // Tells whether the instance has a [[Construct]] internal method.
+ // This property is implemented according to ES6, section 7.2.4.
+ inline void set_is_constructor(bool value);
+ inline bool is_constructor() const;
// Tells whether the instance with this map should be ignored by the
// Object.getPrototypeOf() function and the __proto__ accessor.
inline void set_is_observed();
inline bool is_observed();
- // Tells whether the instance has a [[Call]] internal field.
+ // Tells whether the instance has a [[Call]] internal method.
// This property is implemented according to ES6, section 7.2.3.
inline void set_is_callable();
inline bool is_callable() const;
inline bool IsPrimitiveMap();
inline bool IsJSObjectMap();
inline bool IsJSArrayMap();
+ inline bool IsJSFunctionMap();
inline bool IsStringMap();
inline bool IsJSProxyMap();
inline bool IsJSGlobalProxyMap();
static const int kIsUndetectable = 4;
static const int kIsObserved = 5;
static const int kIsAccessCheckNeeded = 6;
- class FunctionWithPrototype: public BitField<bool, 7, 1> {};
+ static const int kIsConstructor = 7;
// Bit positions for bit field 2
static const int kIsExtensible = 0;
// After prototype is removed, it will not be created when accessed, and
// [[Construct]] from this function will not be allowed.
bool RemovePrototype();
- inline bool should_have_prototype();
// Accessor for this function's initial map's [[class]]
// property. This is primarily used by ECMA native functions. This
Scanner::Location old_super_loc = function_state_->super_location();
Statement* stat = ParseStatementListItem(CHECK_OK);
- if (is_strong(language_mode()) &&
- scope_->is_function_scope() &&
- i::IsConstructor(function_state_->kind())) {
+ if (is_strong(language_mode()) && scope_->is_function_scope() &&
+ IsClassConstructor(function_state_->kind())) {
Scanner::Location this_loc = function_state_->this_location();
Scanner::Location super_loc = function_state_->super_location();
if (this_loc.beg_pos != old_this_loc.beg_pos &&
if (use_strong_found) {
scope_->SetLanguageMode(
static_cast<LanguageMode>(scope_->language_mode() | STRONG));
- if (i::IsConstructor(function_state_->kind())) {
+ if (IsClassConstructor(function_state_->kind())) {
// "use strong" cannot occur in a class constructor body, to avoid
// unintuitive strong class object semantics.
ParserTraits::ReportMessageAt(
// Fall through.
case Token::SUPER:
if (is_strong(language_mode()) &&
- i::IsConstructor(function_state_->kind())) {
+ IsClassConstructor(function_state_->kind())) {
bool is_this = peek() == Token::THIS;
Expression* expr;
ExpressionClassifier classifier;
}
} else {
if (is_strong(language_mode()) &&
- i::IsConstructor(function_state_->kind())) {
+ IsClassConstructor(function_state_->kind())) {
int pos = peek_position();
ReportMessageAt(Scanner::Location(pos, pos + 1),
MessageTemplate::kStrongConstructorReturnValue);
// For concise constructors, check that they are constructed,
// not called.
- if (i::IsConstructor(kind)) {
+ if (IsClassConstructor(kind)) {
AddAssertIsConstruct(result, pos);
}
Statement statement = ParseStatementListItem(ok);
if (!*ok) return;
- if (is_strong(language_mode()) &&
- scope_->is_function_scope() &&
- i::IsConstructor(function_state_->kind())) {
+ if (is_strong(language_mode()) && scope_->is_function_scope() &&
+ IsClassConstructor(function_state_->kind())) {
Scanner::Location this_loc = function_state_->this_location();
Scanner::Location super_loc = function_state_->super_location();
if (this_loc.beg_pos != old_this_loc.beg_pos &&
} else if (use_strong_found) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
scope_->language_mode() | STRONG));
- if (i::IsConstructor(function_state_->kind())) {
+ if (IsClassConstructor(function_state_->kind())) {
// "use strong" cannot occur in a class constructor body, to avoid
// unintuitive strong class object semantics.
PreParserTraits::ReportMessageAt(
// Fall through.
case Token::SUPER:
if (is_strong(language_mode()) &&
- i::IsConstructor(function_state_->kind())) {
+ IsClassConstructor(function_state_->kind())) {
bool is_this = peek() == Token::THIS;
Expression expr = Expression::Default();
ExpressionClassifier classifier;
tok != Token::RBRACE &&
tok != Token::EOS) {
if (is_strong(language_mode()) &&
- i::IsConstructor(function_state_->kind())) {
+ IsClassConstructor(function_state_->kind())) {
int pos = peek_position();
ReportMessageAt(Scanner::Location(pos, pos + 1),
MessageTemplate::kStrongConstructorReturnValue);
if (FLAG_strong_this && is_strong(language_mode())) {
// Constructors' usages of 'this' in strong mode are parsed separately.
// TODO(rossberg): this does not work with arrow functions yet.
- if (i::IsConstructor(function_state_->kind())) {
+ if (IsClassConstructor(function_state_->kind())) {
ReportMessage(MessageTemplate::kStrongConstructorThis);
*ok = false;
break;
Scope* scope = scope_->ReceiverScope();
FunctionKind kind = scope->function_kind();
if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
- i::IsConstructor(kind)) {
+ IsClassConstructor(kind)) {
if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
scope->RecordSuperPropertyUsage();
return this->SuperPropertyReference(scope_, factory(), pos);
} else {
if (super_class->IsNull()) {
prototype_parent = isolate->factory()->null_value();
- } else if (super_class->IsJSFunction()) { // TODO(bmeurer): IsConstructor.
- if (Handle<JSFunction>::cast(super_class)->shared()->is_generator()) {
+ } else if (super_class->IsConstructor()) {
+ if (super_class->IsJSFunction() &&
+ Handle<JSFunction>::cast(super_class)->shared()->is_generator()) {
THROW_NEW_ERROR(
isolate,
NewTypeError(MessageTemplate::kExtendsValueGenerator, super_class),
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
- RUNTIME_ASSERT(fun->should_have_prototype());
+ RUNTIME_ASSERT(fun->IsConstructor());
RETURN_FAILURE_ON_EXCEPTION(isolate,
Accessors::FunctionSetPrototype(fun, value));
return args[0]; // return TOS
RUNTIME_FUNCTION(Runtime_IsConstructor) {
- HandleScope handles(isolate);
- RUNTIME_ASSERT(args.length() == 1);
-
- CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
-
- // TODO(caitp): implement this in a better/simpler way, allow inlining via TF
- if (object->IsJSFunction()) {
- Handle<JSFunction> func = Handle<JSFunction>::cast(object);
- bool should_have_prototype = func->should_have_prototype();
- if (func->shared()->bound()) {
- Handle<FixedArray> bound_args =
- Handle<FixedArray>(FixedArray::cast(func->function_bindings()));
- Handle<Object> bound_function(
- JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
- isolate);
- if (bound_function->IsJSFunction()) {
- Handle<JSFunction> bound = Handle<JSFunction>::cast(bound_function);
- DCHECK(!bound->shared()->bound());
- should_have_prototype = bound->should_have_prototype();
- }
- }
- return isolate->heap()->ToBoolean(should_have_prototype);
- }
- return isolate->heap()->false_value();
+ SealHandleScope shs(isolate);
+ DCHECK_EQ(1, args.length());
+ CONVERT_ARG_CHECKED(Object, object, 0);
+ return isolate->heap()->ToBoolean(object->IsConstructor());
}
bound_function_map = Map::TransitionToPrototype(bound_function_map, proto,
REGULAR_PROTOTYPE);
}
+ if (bound_function_map->is_constructor() != bindee->IsConstructor()) {
+ bound_function_map = Map::Copy(bound_function_map, "IsConstructor");
+ bound_function_map->set_is_constructor(bindee->IsConstructor());
+ }
JSObject::MigrateToMap(bound_function, bound_function_map);
Handle<String> length_string = isolate->factory()->length_string();
Handle<JSFunction>::cast(original_constructor);
- // If function should not have prototype, construction is not allowed. In this
- // case generated code bailouts here, since function has no initial_map.
- if (!function->should_have_prototype() && !function->shared()->bound()) {
+ // Check that function is a constructor.
+ if (!function->IsConstructor()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kNotConstructor, constructor));
}
Variable::NORMAL, kCreatedInitialized);
}
- if (IsConciseMethod(function_kind_) || IsConstructor(function_kind_) ||
+ if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
IsAccessorFunction(function_kind_)) {
variables_.Declare(this, ast_value_factory_->this_function_string(),
CONST, Variable::NORMAL, kCreatedInitialized);
// It needs to be investigated whether this causes any practical problems.
if (!is_function_scope()) return nullptr;
if (IsInObjectLiteral(function_kind_)) return nullptr;
- if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) &&
+ if (!IsConciseMethod(function_kind_) && !IsClassConstructor(function_kind_) &&
!IsAccessorFunction(function_kind_)) {
return nullptr;
}
return scope_uses_super_property_ ||
(scope_calls_eval_ && (IsConciseMethod(function_kind()) ||
IsAccessorFunction(function_kind()) ||
- IsConstructor(function_kind())));
+ IsClassConstructor(function_kind())));
}
const Scope* NearestOuterEvalScope() const {
Variable* this_function_var() const {
// This is only used in derived constructors atm.
DCHECK(this_function_ == nullptr ||
- (is_function_scope() && (IsConstructor(function_kind()) ||
+ (is_function_scope() && (IsClassConstructor(function_kind()) ||
IsConciseMethod(function_kind()) ||
IsAccessorFunction(function_kind()))));
return this_function_;
}
+// static
+void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : the number of arguments (not including the receiver)
+ // -- rdx : the original constructor (either the same as the constructor or
+ // the JSFunction on which new was invoked initially)
+ // -- rdi : the constructor to call (checked to be a JSFunctionProxy)
+ // -----------------------------------
+
+ // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+ __ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset));
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+}
+
+
// static
void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -----------------------------------
StackArgumentsAccessor args(rsp, rax);
- Label non_callable, non_function;
- __ JumpIfSmi(rdi, &non_callable);
- __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+ // Check if target has a [[Construct]] internal method.
+ Label non_constructor;
+ __ JumpIfSmi(rdi, &non_constructor, Label::kNear);
+ __ movp(rcx, FieldOperand(rdi, HeapObject::kMapOffset));
+ __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsConstructor));
+ __ j(zero, &non_constructor, Label::kNear);
+
+ // Dispatch based on instance type.
+ __ CmpInstanceType(rcx, JS_FUNCTION_TYPE);
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
- __ j(not_equal, &non_function, Label::kNear);
-
- // 1. Construct of function proxy.
- // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
- __ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset));
- __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+ __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
+ RelocInfo::CODE_TARGET);
- // 2. Construct of something else, which might have a [[Construct]] internal
- // method (if not we raise an exception).
- __ bind(&non_function);
- // Check if target has a [[Call]] internal method.
- // TODO(bmeurer): This shoud use IsConstructor once available.
- __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
- Immediate(1 << Map::kIsCallable));
- __ j(zero, &non_callable, Label::kNear);
- // Overwrite the original receiver with the (original) target.
- __ movp(args.GetReceiverOperand(), rdi);
- // Let the "call_as_constructor_delegate" take care of the rest.
- __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, rdi);
- __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+ // Called Construct on an exotic Object with a [[Construct]] internal method.
+ {
+ // Overwrite the original receiver with the (original) target.
+ __ movp(args.GetReceiverOperand(), rdi);
+ // Let the "call_as_constructor_delegate" take care of the rest.
+ __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, rdi);
+ __ Jump(masm->isolate()->builtins()->CallFunction(),
+ RelocInfo::CODE_TARGET);
+ }
- // 3. Construct of something that is not callable.
- __ bind(&non_callable);
+ // Called Construct on an Object that doesn't have a [[Construct]] internal
+ // method.
+ __ bind(&non_constructor);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(rdi);