Commit 78be1562 authored by chunyang.dai's avatar chunyang.dai Committed by Commit bot

X87: [builtin] Refactor Invoke to deal with any kind of callable.

port 634d1d86 (r30874).

original commit message:

    Now both Execution::Call and Execution::New can deal with any
    kind of target and will raise a proper exception if the target is not
    callable (which is not yet spec compliant for New, as we would
    have to check IsConstructor instead, which we don't have yet).

    Now we no longer need to do any of these weird call/construct
    delegate gymnastics in C++, and we finally have a single true
    bottleneck for Call/Construct abstract operations in the code
    base, with only a few special handlings left in the compilers to
    optimize the JSFunction case.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#30904}
parent 28de5bf8
......@@ -1516,13 +1516,13 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// -- edi : the target to call (can be any Object).
// -----------------------------------
Label non_smi, non_function;
__ JumpIfSmi(edi, &non_function);
Label non_callable, non_function, non_smi;
__ JumpIfSmi(edi, &non_callable);
__ bind(&non_smi);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, edx);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(equal, masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &non_function);
// 1. Call to function proxy.
......@@ -1534,28 +1534,22 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
__ bind(&non_function);
// TODO(bmeurer): I wonder why we prefer to have slow API calls? This could
// be awesome instead; i.e. a trivial improvement would be to call into the
// runtime and just deal with the API function there instead of returning a
// delegate from a runtime call that just jumps back to the runtime once
// called. Or, bonus points, call directly into the C API function here, as
// we do in some Crankshaft fast cases.
// Check if target has a [[Call]] internal method.
__ 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_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(eax);
__ Push(eax);
__ Push(edi);
__ CallRuntime(Runtime::kGetFunctionDelegate, 1);
__ mov(edi, eax);
__ Pop(eax);
__ SmiUntag(eax);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(edi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......@@ -1591,33 +1585,39 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -- edi : the constructor to call (can be any Object)
// -----------------------------------
Label slow;
__ JumpIfSmi(edi, &slow, Label::kNear);
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(not_equal, &slow, Label::kNear);
__ 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);
__ bind(&slow);
// 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);
{
// Determine the delegate for the target (if any).
FrameScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(eax);
__ Push(eax);
__ Push(edi);
__ CallRuntime(Runtime::kGetConstructorDelegate, 1);
__ mov(edi, eax);
__ Pop(eax);
__ SmiUntag(eax);
__ CallRuntime(Runtime::kThrowCalledNonCallable, 1);
}
// The delegate is always a regular function.
__ AssertFunction(edi);
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
}
......
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