Commit 11fd60f5 authored by chunyang.dai's avatar chunyang.dai Committed by Commit bot

X87: [es6] Introduce spec compliant IsConstructor.

port 8fe3ac07 (30902).

original commit message:

    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.

BUG=

Review URL: https://codereview.chromium.org/1362313002

Cr-Commit-Position: refs/heads/master@{#30908}
parent 46d61217
...@@ -1566,6 +1566,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { ...@@ -1566,6 +1566,21 @@ 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 // static
void Builtins::Generate_Construct(MacroAssembler* masm) { void Builtins::Generate_Construct(MacroAssembler* masm) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
...@@ -1575,34 +1590,34 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -1575,34 +1590,34 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -- edi : the constructor to call (can be any Object) // -- edi : the constructor to call (can be any Object)
// ----------------------------------- // -----------------------------------
Label non_callable, non_function; // Check if target has a [[Construct]] internal method.
__ JumpIfSmi(edi, &non_callable); Label non_constructor;
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); __ 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(), __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &non_function, Label::kNear); __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
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);
// 2. Construct of something else, which might have a [[Construct]] internal // Called Construct on an exotic Object with a [[Construct]] internal method.
// method (if not we raise an exception). {
__ bind(&non_function); // Overwrite the original receiver with the (original) target.
// Check if target has a [[Call]] internal method. __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
// TODO(bmeurer): This shoud use IsConstructor once available. // Let the "call_as_constructor_delegate" take care of the rest.
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable); __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
__ j(zero, &non_callable, Label::kNear); __ Jump(masm->isolate()->builtins()->CallFunction(),
// Overwrite the original receiver with the (original) target. RelocInfo::CODE_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. // Called Construct on an Object that doesn't have a [[Construct]] internal
__ bind(&non_callable); // method.
__ bind(&non_constructor);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(edi); __ Push(edi);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment