From 656ebdce8d2cfa1ba1d37686b20785321f1874b9 Mon Sep 17 00:00:00 2001 From: bmeurer Date: Wed, 23 Sep 2015 22:26:44 -0700 Subject: [PATCH] Revert of [es6] Introduce spec compliant IsConstructor. (patchset #2 id:20001 of https://codereview.chromium.org/1358423002/ ) Reason for revert: Failed on Fuzzer and MIPS bot. Original issue's description: > [es6] Introduce spec compliant IsConstructor. > > There was already a bit on the Map named "function with prototype", > which basically meant that the Map was a map for a JSFunction that could > be used as a constructor. Now this CL generalizes that bit to > IsConstructor, which says that whatever (Heap)Object you are looking at > can be used as a constructor (i.e. the bit is also set for bound > functions that can be used as constructors and proxies that have a > [[Construct]] internal method). > > This way we have a single chokepoint for IsConstructor checking, which > allows us to get rid of the various ways in which we tried to guess > whether something could be used as a constructor or not. > > Drive-by-fix: Renamed IsConstructor on FunctionKind to > IsClassConstructor to resolve the weird name clash, and the > IsClassConstructor name also matches the spec. > > R=jarin@chromium.org, rossberg@chromium.org > BUG=v8:4430 > LOG=n > > Committed: https://crrev.com/8de4d9351df4cf66c8a128d561a6e331d196be54 > Cr-Commit-Position: refs/heads/master@{#30900} TBR=jarin@chromium.org,rossberg@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:4430 Review URL: https://codereview.chromium.org/1360403002 Cr-Commit-Position: refs/heads/master@{#30901} --- src/accessors.cc | 2 +- src/api-natives.cc | 1 - src/arm/builtins-arm.cc | 63 ++++++++++++------------------- src/arm64/builtins-arm64.cc | 61 +++++++++++------------------- src/bootstrapper.cc | 10 ++--- src/builtins.h | 3 -- src/contexts.h | 2 +- src/factory.cc | 3 +- src/globals.h | 2 +- src/hydrogen.cc | 5 +-- src/ia32/builtins-ia32.cc | 61 +++++++++++------------------- src/ic/ic.cc | 2 +- src/mips/builtins-mips.cc | 67 +++++++++++++-------------------- src/mips64/builtins-mips64.cc | 67 +++++++++++++-------------------- src/objects-inl.h | 24 +++++------- src/objects.cc | 2 +- src/objects.h | 18 ++++----- src/parser.cc | 13 ++++--- src/preparser.cc | 11 +++--- src/preparser.h | 4 +- src/runtime/runtime-classes.cc | 5 +-- src/runtime/runtime-function.cc | 34 ++++++++++++----- src/runtime/runtime-object.cc | 5 ++- src/scopes.cc | 4 +- src/scopes.h | 4 +- src/x64/builtins-x64.cc | 63 ++++++++++++------------------- 26 files changed, 225 insertions(+), 311 deletions(-) diff --git a/src/accessors.cc b/src/accessors.cc index c04b26681..441ff4d2f 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -929,7 +929,7 @@ MUST_USE_RESULT static MaybeHandle SetFunctionPrototype( MaybeHandle Accessors::FunctionSetPrototype(Handle function, Handle prototype) { - DCHECK(function->IsConstructor()); + DCHECK(function->should_have_prototype()); Isolate* isolate = function->GetIsolate(); return SetFunctionPrototype(isolate, function, prototype); } diff --git a/src/api-natives.cc b/src/api-natives.cc index 0a3bc1714..a62c231ce 100644 --- a/src/api-natives.cc +++ b/src/api-natives.cc @@ -494,7 +494,6 @@ Handle ApiNatives::CreateApiFunction( // 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, diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index ea2c92e64..5b278a1b1 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -1635,21 +1635,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { } -// 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 ------------- @@ -1659,35 +1644,35 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { // the JSFunction on which new was invoked initially) // ----------------------------------- - // 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); + Label non_callable, non_function; + __ JumpIfSmi(r1, &non_callable); + __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE); __ Jump(masm->isolate()->builtins()->ConstructFunction(), RelocInfo::CODE_TARGET, eq); __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE)); - __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, - eq); + __ b(ne, &non_function); - // 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); - } + // 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); + + // 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 Object that doesn't have a [[Construct]] internal - // method. - __ bind(&non_constructor); + // 3. Construct of something that is not callable. + __ bind(&non_callable); { FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); __ Push(r1); diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc index 433119801..afa3b077f 100644 --- a/src/arm64/builtins-arm64.cc +++ b/src/arm64/builtins-arm64.cc @@ -1692,21 +1692,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { } -// 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 ------------- @@ -1716,34 +1701,34 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { // the JSFunction on which new was invoked initially) // ----------------------------------- - // 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); + Label non_callable, non_function; + __ JumpIfSmi(x1, &non_callable); + __ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE); __ Jump(masm->isolate()->builtins()->ConstructFunction(), RelocInfo::CODE_TARGET, eq); __ Cmp(x5, JS_FUNCTION_PROXY_TYPE); - __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, - eq); + __ B(ne, &non_function); - // 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); - } + // 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); + + // 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 Object that doesn't have a [[Construct]] internal - // method. - __ bind(&non_constructor); + // 3. Construct of something that is not callable. + __ bind(&non_callable); { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(x1); diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index d5f3c336a..b40a96a49 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -487,7 +487,7 @@ void Genesis::SetFunctionInstanceDescriptor(Handle map, Handle Genesis::CreateSloppyFunctionMap(FunctionMode function_mode) { Handle map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); SetFunctionInstanceDescriptor(map, function_mode); - map->set_is_constructor(IsFunctionModeWithPrototype(function_mode)); + map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode)); map->set_is_callable(); return map; } @@ -727,7 +727,7 @@ Handle Genesis::CreateStrictFunctionMap( FunctionMode function_mode, Handle empty_function) { Handle map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); SetStrictFunctionInstanceDescriptor(map, function_mode); - map->set_is_constructor(IsFunctionModeWithPrototype(function_mode)); + map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode)); map->set_is_callable(); Map::SetPrototype(map, empty_function); return map; @@ -738,7 +738,7 @@ Handle Genesis::CreateStrongFunctionMap( Handle empty_function, bool is_constructor) { Handle map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize); SetStrongFunctionInstanceDescriptor(map); - map->set_is_constructor(is_constructor); + map->set_function_with_prototype(is_constructor); Map::SetPrototype(map, empty_function); map->set_is_callable(); map->set_is_extensible(is_constructor); @@ -1373,7 +1373,7 @@ void Genesis::InitializeGlobal(Handle global_object, } // @@iterator method is added later. - map->set_is_constructor(true); + map->set_function_with_prototype(true); map->SetInObjectProperties(2); native_context()->set_sloppy_arguments_map(*map); @@ -1439,7 +1439,7 @@ void Genesis::InitializeGlobal(Handle global_object, } // @@iterator method is added later. - map->set_is_constructor(true); + map->set_function_with_prototype(true); DCHECK_EQ(native_context()->object_function()->prototype(), *isolate->initial_object_prototype()); Map::SetPrototype(map, isolate->initial_object_prototype()); diff --git a/src/builtins.h b/src/builtins.h index d9129608d..56f2db91e 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -78,7 +78,6 @@ enum BuiltinExtraArguments { 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) \ @@ -282,8 +281,6 @@ class Builtins { // 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); diff --git a/src/contexts.h b/src/contexts.h index 5bf401b10..267fdea70 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -513,7 +513,7 @@ class Context: public FixedArray { : SLOPPY_GENERATOR_FUNCTION_MAP_INDEX; } - if (IsClassConstructor(kind)) { + if (IsConstructor(kind)) { // Use strict function map (no own "caller" / "arguments") return is_strong(language_mode) ? STRONG_CONSTRUCTOR_MAP_INDEX : STRICT_FUNCTION_MAP_INDEX; diff --git a/src/factory.cc b/src/factory.cc index c3a3b1570..c1322d7e7 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1930,7 +1930,6 @@ Handle Factory::NewJSFunctionProxy(Handle handler, Handle 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 result = New(map, NEW_SPACE); @@ -1992,7 +1991,7 @@ void Factory::ReinitializeJSProxy(Handle proxy, InstanceType type, // Functions require some minimal initialization. if (type == JS_FUNCTION_TYPE) { - map->set_is_constructor(true); + map->set_function_with_prototype(true); map->set_is_callable(); Handle js_function = Handle::cast(proxy); InitializeFunction(js_function, shared.ToHandleChecked(), context); diff --git a/src/globals.h b/src/globals.h index 03ec3a809..2b6987fda 100644 --- a/src/globals.h +++ b/src/globals.h @@ -997,7 +997,7 @@ inline bool IsSubclassConstructor(FunctionKind kind) { } -inline bool IsClassConstructor(FunctionKind kind) { +inline bool IsConstructor(FunctionKind kind) { DCHECK(IsValidFunctionKind(kind)); return kind & (FunctionKind::kBaseConstructor | FunctionKind::kSubclassConstructor | diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 87f8ce954..5f1af6be3 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -6418,8 +6418,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { if (!CanInlinePropertyAccess(map_)) return false; if (IsJSObjectFieldAccessor()) return IsLoad(); if (IsJSArrayBufferViewFieldAccessor()) return IsLoad(); - if (map_->IsJSFunctionMap() && map_->is_constructor() && - !map_->has_non_instance_prototype() && + if (map_->function_with_prototype() && !map_->has_non_instance_prototype() && name_.is_identical_to(isolate()->factory()->prototype_string())) { return IsLoad(); } @@ -6533,7 +6532,7 @@ HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess( } if (info->name().is_identical_to(isolate()->factory()->prototype_string()) && - info->map()->IsJSFunctionMap() && info->map()->is_constructor()) { + info->map()->function_with_prototype()) { DCHECK(!info->map()->has_non_instance_prototype()); return New(checked_object); } diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index ccdd01c7a..88e9841d5 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -1566,21 +1566,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { } -// 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 ------------- @@ -1590,34 +1575,34 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { // -- edi : the constructor to call (can be any Object) // ----------------------------------- - // 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); + Label non_callable, non_function; + __ JumpIfSmi(edi, &non_callable); + __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); __ j(equal, masm->isolate()->builtins()->ConstructFunction(), RelocInfo::CODE_TARGET); __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); - __ j(equal, masm->isolate()->builtins()->ConstructProxy(), - RelocInfo::CODE_TARGET); + __ j(not_equal, &non_function, Label::kNear); - // 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); - } + // 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); - // Called Construct on an Object that doesn't have a [[Construct]] internal - // method. - __ bind(&non_constructor); + // 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); + + // 3. Construct of something that is not callable. + __ bind(&non_callable); { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(edi); diff --git a/src/ic/ic.cc b/src/ic/ic.cc index a9ad1c9df..23944028a 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -1159,7 +1159,7 @@ Handle LoadIC::CompileHandler(LookupIterator* lookup, // Use specialized code for getting prototype of functions. if (receiver->IsJSFunction() && Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) && - receiver->IsConstructor() && + Handle::cast(receiver)->should_have_prototype() && !Handle::cast(receiver) ->map() ->has_non_instance_prototype()) { diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc index 748a40b37..4a2b611b7 100644 --- a/src/mips/builtins-mips.cc +++ b/src/mips/builtins-mips.cc @@ -1648,21 +1648,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { } -// 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 ------------- @@ -1672,36 +1657,36 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { // the JSFunction on which new was invoked initially) // ----------------------------------- - // Check if target has a [[Construct]] internal method. - Label non_constructor; - __ JumpIfSmi(a1, &non_constructor); - __ lw(t1, FieldMemOperand(t1, 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)); + Label non_callable, non_function; + __ JumpIfSmi(a1, &non_callable); + __ GetObjectType(a1, t1, t2); __ Jump(masm->isolate()->builtins()->ConstructFunction(), RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE)); - __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, - eq, t2, Operand(JS_FUNCTION_PROXY_TYPE)); + __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE)); - // 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); - } + // 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); + + // 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 Object that doesn't have a [[Construct]] internal - // method. - __ bind(&non_constructor); + // 3. Construct of something that is not callable. + __ bind(&non_callable); { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(a1); diff --git a/src/mips64/builtins-mips64.cc b/src/mips64/builtins-mips64.cc index 29e0968f8..105d2e59f 100644 --- a/src/mips64/builtins-mips64.cc +++ b/src/mips64/builtins-mips64.cc @@ -1644,21 +1644,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { } -// 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 ------------- @@ -1668,36 +1653,36 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { // the JSFunction on which new was invoked initially) // ----------------------------------- - // Check if target has a [[Construct]] internal method. - Label non_constructor; - __ JumpIfSmi(a1, &non_constructor); - __ ld(t1, FieldMemOperand(t1, 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)); + Label non_callable, non_function; + __ JumpIfSmi(a1, &non_callable); + __ GetObjectType(a1, t1, t2); __ Jump(masm->isolate()->builtins()->ConstructFunction(), RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE)); - __ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET, - eq, t2, Operand(JS_FUNCTION_PROXY_TYPE)); + __ Branch(&non_function, ne, t2, Operand(JS_FUNCTION_PROXY_TYPE)); - // 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); - } + // 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); + + // 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 Object that doesn't have a [[Construct]] internal - // method. - __ bind(&non_constructor); + // 3. Construct of something that is not callable. + __ bind(&non_callable); { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(a1); diff --git a/src/objects-inl.h b/src/objects-inl.h index 2efd7ef65..4aa0ea18b 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -192,12 +192,6 @@ bool Object::IsCallable() const { } -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; @@ -4538,17 +4532,13 @@ bool Map::has_non_instance_prototype() { } -void Map::set_is_constructor(bool value) { - if (value) { - set_bit_field(bit_field() | (1 << kIsConstructor)); - } else { - set_bit_field(bit_field() & ~(1 << kIsConstructor)); - } +void Map::set_function_with_prototype(bool value) { + set_bit_field(FunctionWithPrototype::update(bit_field(), value)); } -bool Map::is_constructor() const { - return ((1 << kIsConstructor) & bit_field()) != 0; +bool Map::function_with_prototype() { + return FunctionWithPrototype::decode(bit_field()); } @@ -4805,7 +4795,6 @@ bool Map::IsJSObjectMap() { 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(); @@ -6267,6 +6256,11 @@ Object* JSFunction::prototype() { } +bool JSFunction::should_have_prototype() { + return map()->function_with_prototype(); +} + + bool JSFunction::is_compiled() { Builtins* builtins = GetIsolate()->builtins(); return code() != builtins->builtin(Builtins::kCompileLazy) && diff --git a/src/objects.cc b/src/objects.cc index 3e88c961e..d5cbcda37 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -10719,7 +10719,7 @@ void JSFunction::SetInstancePrototype(Handle function, void JSFunction::SetPrototype(Handle function, Handle value) { - DCHECK(function->IsConstructor()); + DCHECK(function->should_have_prototype()); Handle construct_prototype = value; // If the value is not a JSReceiver, store the value in the map's diff --git a/src/objects.h b/src/objects.h index 075cca447..572f26cee 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1033,9 +1033,6 @@ class Object { // 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); @@ -5365,10 +5362,11 @@ class Map: public HeapObject { inline void set_non_instance_prototype(bool value); inline bool has_non_instance_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 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 with this map should be ignored by the // Object.getPrototypeOf() function and the __proto__ accessor. @@ -5396,7 +5394,7 @@ class Map: public HeapObject { inline void set_is_observed(); inline bool is_observed(); - // Tells whether the instance has a [[Call]] internal method. + // Tells whether the instance has a [[Call]] internal field. // This property is implemented according to ES6, section 7.2.3. inline void set_is_callable(); inline bool is_callable() const; @@ -5725,7 +5723,6 @@ class Map: public HeapObject { inline bool IsPrimitiveMap(); inline bool IsJSObjectMap(); inline bool IsJSArrayMap(); - inline bool IsJSFunctionMap(); inline bool IsStringMap(); inline bool IsJSProxyMap(); inline bool IsJSGlobalProxyMap(); @@ -5830,7 +5827,7 @@ class Map: public HeapObject { static const int kIsUndetectable = 4; static const int kIsObserved = 5; static const int kIsAccessCheckNeeded = 6; - static const int kIsConstructor = 7; + class FunctionWithPrototype: public BitField {}; // Bit positions for bit field 2 static const int kIsExtensible = 0; @@ -7145,6 +7142,7 @@ class JSFunction: public JSObject { // 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 diff --git a/src/parser.cc b/src/parser.cc index e3ce0f017..123a7bdc6 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1280,8 +1280,9 @@ void* Parser::ParseStatementList(ZoneList* body, int end_token, Scanner::Location old_super_loc = function_state_->super_location(); Statement* stat = ParseStatementListItem(CHECK_OK); - if (is_strong(language_mode()) && scope_->is_function_scope() && - IsClassConstructor(function_state_->kind())) { + if (is_strong(language_mode()) && + scope_->is_function_scope() && + i::IsConstructor(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 && @@ -1335,7 +1336,7 @@ void* Parser::ParseStatementList(ZoneList* body, int end_token, if (use_strong_found) { scope_->SetLanguageMode( static_cast(scope_->language_mode() | STRONG)); - if (IsClassConstructor(function_state_->kind())) { + if (i::IsConstructor(function_state_->kind())) { // "use strong" cannot occur in a class constructor body, to avoid // unintuitive strong class object semantics. ParserTraits::ReportMessageAt( @@ -2641,7 +2642,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement( // Fall through. case Token::SUPER: if (is_strong(language_mode()) && - IsClassConstructor(function_state_->kind())) { + i::IsConstructor(function_state_->kind())) { bool is_this = peek() == Token::THIS; Expression* expr; ExpressionClassifier classifier; @@ -2848,7 +2849,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { } } else { if (is_strong(language_mode()) && - IsClassConstructor(function_state_->kind())) { + i::IsConstructor(function_state_->kind())) { int pos = peek_position(); ReportMessageAt(Scanner::Location(pos, pos + 1), MessageTemplate::kStrongConstructorReturnValue); @@ -4603,7 +4604,7 @@ ZoneList* Parser::ParseEagerFunctionBody( // For concise constructors, check that they are constructed, // not called. - if (IsClassConstructor(kind)) { + if (i::IsConstructor(kind)) { AddAssertIsConstruct(result, pos); } diff --git a/src/preparser.cc b/src/preparser.cc index 04757b379..44ba38b0b 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -232,8 +232,9 @@ void PreParser::ParseStatementList(int end_token, bool* ok, Statement statement = ParseStatementListItem(ok); if (!*ok) return; - if (is_strong(language_mode()) && scope_->is_function_scope() && - IsClassConstructor(function_state_->kind())) { + if (is_strong(language_mode()) && + scope_->is_function_scope() && + i::IsConstructor(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 && @@ -261,7 +262,7 @@ void PreParser::ParseStatementList(int end_token, bool* ok, } else if (use_strong_found) { scope_->SetLanguageMode(static_cast( scope_->language_mode() | STRONG)); - if (IsClassConstructor(function_state_->kind())) { + if (i::IsConstructor(function_state_->kind())) { // "use strong" cannot occur in a class constructor body, to avoid // unintuitive strong class object semantics. PreParserTraits::ReportMessageAt( @@ -638,7 +639,7 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) { // Fall through. case Token::SUPER: if (is_strong(language_mode()) && - IsClassConstructor(function_state_->kind())) { + i::IsConstructor(function_state_->kind())) { bool is_this = peek() == Token::THIS; Expression expr = Expression::Default(); ExpressionClassifier classifier; @@ -789,7 +790,7 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) { tok != Token::RBRACE && tok != Token::EOS) { if (is_strong(language_mode()) && - IsClassConstructor(function_state_->kind())) { + i::IsConstructor(function_state_->kind())) { int pos = peek_position(); ReportMessageAt(Scanner::Location(pos, pos + 1), MessageTemplate::kStrongConstructorReturnValue); diff --git a/src/preparser.h b/src/preparser.h index e9e0f4bfb..a5aa3709a 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -2228,7 +2228,7 @@ ParserBase::ParsePrimaryExpression(ExpressionClassifier* classifier, 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 (IsClassConstructor(function_state_->kind())) { + if (i::IsConstructor(function_state_->kind())) { ReportMessage(MessageTemplate::kStrongConstructorThis); *ok = false; break; @@ -3612,7 +3612,7 @@ ParserBase::ParseSuperExpression(bool is_new, Scope* scope = scope_->ReceiverScope(); FunctionKind kind = scope->function_kind(); if (IsConciseMethod(kind) || IsAccessorFunction(kind) || - IsClassConstructor(kind)) { + i::IsConstructor(kind)) { if (peek() == Token::PERIOD || peek() == Token::LBRACK) { scope->RecordSuperPropertyUsage(); return this->SuperPropertyReference(scope_, factory(), pos); diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc index 5219a6882..50c2ccae9 100644 --- a/src/runtime/runtime-classes.cc +++ b/src/runtime/runtime-classes.cc @@ -105,9 +105,8 @@ static MaybeHandle DefineClass(Isolate* isolate, Handle name, } else { if (super_class->IsNull()) { prototype_parent = isolate->factory()->null_value(); - } else if (super_class->IsConstructor()) { - if (super_class->IsJSFunction() && - Handle::cast(super_class)->shared()->is_generator()) { + } else if (super_class->IsJSFunction()) { // TODO(bmeurer): IsConstructor. + if (Handle::cast(super_class)->shared()->is_generator()) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kExtendsValueGenerator, super_class), diff --git a/src/runtime/runtime-function.cc b/src/runtime/runtime-function.cc index be92d59a6..560016659 100644 --- a/src/runtime/runtime-function.cc +++ b/src/runtime/runtime-function.cc @@ -159,7 +159,7 @@ RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) { CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); - RUNTIME_ASSERT(fun->IsConstructor()); + RUNTIME_ASSERT(fun->should_have_prototype()); RETURN_FAILURE_ON_EXCEPTION(isolate, Accessors::FunctionSetPrototype(fun, value)); return args[0]; // return TOS @@ -270,10 +270,30 @@ RUNTIME_FUNCTION(Runtime_SetNativeFlag) { RUNTIME_FUNCTION(Runtime_IsConstructor) { - SealHandleScope shs(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_CHECKED(Object, object, 0); - return isolate->heap()->ToBoolean(object->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 func = Handle::cast(object); + bool should_have_prototype = func->should_have_prototype(); + if (func->shared()->bound()) { + Handle bound_args = + Handle(FixedArray::cast(func->function_bindings())); + Handle bound_function( + JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)), + isolate); + if (bound_function->IsJSFunction()) { + Handle bound = Handle::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(); } @@ -417,10 +437,6 @@ RUNTIME_FUNCTION(Runtime_FunctionBindArguments) { 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 length_string = isolate->factory()->length_string(); diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index b128190fb..d00ce5276 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -1056,8 +1056,9 @@ static Object* Runtime_NewObjectHelper(Isolate* isolate, Handle::cast(original_constructor); - // Check that function is a constructor. - if (!function->IsConstructor()) { + // 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()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kNotConstructor, constructor)); } diff --git a/src/scopes.cc b/src/scopes.cc index 19466e40a..e9c04c977 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -357,7 +357,7 @@ void Scope::Initialize() { Variable::NORMAL, kCreatedInitialized); } - if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) || + if (IsConciseMethod(function_kind_) || IsConstructor(function_kind_) || IsAccessorFunction(function_kind_)) { variables_.Declare(this, ast_value_factory_->this_function_string(), CONST, Variable::NORMAL, kCreatedInitialized); @@ -1285,7 +1285,7 @@ ClassVariable* Scope::ClassVariableForMethod() const { // 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_) && !IsClassConstructor(function_kind_) && + if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) && !IsAccessorFunction(function_kind_)) { return nullptr; } diff --git a/src/scopes.h b/src/scopes.h index 61bf6338f..d9aac2f7e 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -347,7 +347,7 @@ class Scope: public ZoneObject { return scope_uses_super_property_ || (scope_calls_eval_ && (IsConciseMethod(function_kind()) || IsAccessorFunction(function_kind()) || - IsClassConstructor(function_kind()))); + IsConstructor(function_kind()))); } const Scope* NearestOuterEvalScope() const { @@ -445,7 +445,7 @@ class Scope: public ZoneObject { Variable* this_function_var() const { // This is only used in derived constructors atm. DCHECK(this_function_ == nullptr || - (is_function_scope() && (IsClassConstructor(function_kind()) || + (is_function_scope() && (IsConstructor(function_kind()) || IsConciseMethod(function_kind()) || IsAccessorFunction(function_kind())))); return this_function_; diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index 38d7e5abe..a056e4c2f 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -1770,21 +1770,6 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { } -// 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 ------------- @@ -1795,35 +1780,35 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { // ----------------------------------- StackArgumentsAccessor args(rsp, rax); - // 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); + Label non_callable, non_function; + __ JumpIfSmi(rdi, &non_callable); + __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); __ j(equal, masm->isolate()->builtins()->ConstructFunction(), RelocInfo::CODE_TARGET); __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); - __ j(equal, masm->isolate()->builtins()->ConstructProxy(), - RelocInfo::CODE_TARGET); + __ j(not_equal, &non_function, Label::kNear); - // 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); - } + // 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); + + // 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 Object that doesn't have a [[Construct]] internal - // method. - __ bind(&non_constructor); + // 3. Construct of something that is not callable. + __ bind(&non_callable); { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(rdi); -- 2.34.1