Commit 31a9396e authored by mbrandy's avatar mbrandy Committed by Commit bot

PPC: [builtins] Unify the various versions of [[Call]] with a Call builtin.

Port ccbb4ff0

Original commit message:
    The new Call and CallFunction builtins supersede the current
    CallFunctionStub (and CallIC magic) and will be the single bottleneck
    for all calling, including the currently special Function.prototype.call
    and Function.prototype.apply builtins, which had handwritten (and
    not fully compliant) versions of CallFunctionStub, and also the
    CallIC(s), which where also slightly different.

    This also reduces the overhead for API function calls, which is still
    unnecessary high, but let's do that step-by-step.

    This also fixes a bunch of cases where the implicit ToObject for
    sloppy receivers was done in the wrong context (in the caller
    context instead of the callee context), which basically meant
    that we allowed cross context access to %ObjectPrototype%.

    MIPS and MIPS64 ports contributed by akos.palfi@imgtec.com.

R=bmeurer@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com, dstence@us.ibm.com
BUG=v8:4413
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#30656}
parent 50c6b031
This diff is collapsed.
......@@ -2567,30 +2567,9 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
}
static void EmitSlowCase(MacroAssembler* masm, int argc, Label* non_function) {
// Check for function proxy.
STATIC_ASSERT(JS_FUNCTION_PROXY_TYPE < 0xffffu);
__ cmpi(r7, Operand(JS_FUNCTION_PROXY_TYPE));
__ bne(non_function);
__ push(r4); // put proxy as additional argument
__ li(r3, Operand(argc + 1));
__ li(r5, Operand::Zero());
__ GetBuiltinFunction(r4, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
{
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
__ Jump(adaptor, RelocInfo::CODE_TARGET);
}
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
__ bind(non_function);
__ StoreP(r4, MemOperand(sp, argc * kPointerSize), r0);
__ li(r3, Operand(argc)); // Set up the number of arguments.
__ li(r5, Operand::Zero());
__ GetBuiltinFunction(r4, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
static void EmitSlowCase(MacroAssembler* masm, int argc) {
__ mov(r3, Operand(argc));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
}
......@@ -2612,12 +2591,12 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
static void CallFunctionNoFeedback(MacroAssembler* masm, int argc,
bool needs_checks, bool call_as_method) {
// r4 : the function to call
Label slow, non_function, wrap, cont;
Label slow, wrap, cont;
if (needs_checks) {
// Check that the function is really a JavaScript function.
// r4: pushed function (to be verified)
__ JumpIfSmi(r4, &non_function);
__ JumpIfSmi(r4, &slow);
// Goto slow case if we do not have a function.
__ CompareObjectType(r4, r7, r7, JS_FUNCTION_TYPE);
......@@ -2652,7 +2631,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm, int argc,
if (needs_checks) {
// Slow-case: Non-function called.
__ bind(&slow);
EmitSlowCase(masm, argc, &non_function);
EmitSlowCase(masm, argc);
}
if (call_as_method) {
......@@ -2794,10 +2773,8 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
GenerateMiss(masm);
// The slow case, we need this no matter what to complete a call after a miss.
CallFunctionNoFeedback(masm, arg_count(), true, CallAsMethod());
// Unreachable.
__ stop("Unexpected code address");
__ mov(r3, Operand(arg_count()));
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
}
......@@ -2810,7 +2787,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, slow_start;
Label slow, non_function, wrap, cont;
Label slow, wrap, cont;
Label have_js_function;
int argc = arg_count();
ParameterCount actual(argc);
......@@ -2864,7 +2841,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ InvokeFunction(r4, actual, JUMP_FUNCTION, NullCallWrapper());
__ bind(&slow);
EmitSlowCase(masm, argc, &non_function);
EmitSlowCase(masm, argc);
if (CallAsMethod()) {
__ bind(&wrap);
......@@ -2949,7 +2926,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&slow_start);
// Check that the function is really a JavaScript function.
// r4: pushed function (to be verified)
__ JumpIfSmi(r4, &non_function);
__ JumpIfSmi(r4, &slow);
// Goto slow case if we do not have a function.
__ CompareObjectType(r4, r7, r7, JS_FUNCTION_TYPE);
......
......@@ -2399,6 +2399,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
}
void MacroAssembler::LoadGlobalProxy(Register dst) {
LoadP(dst, GlobalObjectOperand());
LoadP(dst, FieldMemOperand(dst, GlobalObject::kGlobalProxyOffset));
}
void MacroAssembler::LoadTransitionedArrayMapConditional(
ElementsKind expected_kind, ElementsKind transitioned_kind,
Register map_in_out, Register scratch, Label* no_map_match) {
......@@ -2575,6 +2581,17 @@ void MacroAssembler::AssertName(Register object) {
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
STATIC_ASSERT(kSmiTag == 0);
TestIfSmi(object, r0);
Check(ne, kOperandIsASmiAndNotAFunction, cr0);
CompareObjectType(object, r0, r0, JS_FUNCTION_TYPE);
Check(eq, kOperandIsNotAFunction);
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
Register scratch) {
if (emit_debug_code()) {
......
......@@ -415,6 +415,9 @@ class MacroAssembler : public Assembler {
void LoadContext(Register dst, int context_chain_length);
// Load the global proxy from the current context.
void LoadGlobalProxy(Register dst);
// Conditionally load the cached Array transitioned map of type
// transitioned_kind from the native context if the map in register
// map_in_out is the cached Array map in the native context of
......@@ -781,7 +784,23 @@ class MacroAssembler : public Assembler {
// Compare the object in a register to a value from the root list.
// Uses the ip register as scratch.
void CompareRoot(Register obj, Heap::RootListIndex index);
void PushRoot(Heap::RootListIndex index) {
LoadRoot(r0, index);
Push(r0);
}
// Compare the object in a register to a value and jump if they are equal.
void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) {
CompareRoot(with, index);
beq(if_equal);
}
// Compare the object in a register to a value and jump if they are not equal.
void JumpIfNotRoot(Register with, Heap::RootListIndex index,
Label* if_not_equal) {
CompareRoot(with, index);
bne(if_not_equal);
}
// Load and check the instance type of an object for being a string.
// Loads the type into the second argument register.
......@@ -1288,6 +1307,8 @@ class MacroAssembler : public Assembler {
// Abort execution if argument is not a name, enabled via --debug-code.
void AssertName(Register object);
void AssertFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object, Register scratch);
......
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