Commit 20c9749b authored by chunyang.dai's avatar chunyang.dai Committed by Commit bot

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

port ccbb4ff0 (r30629)

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%.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#30668}
parent 0cfa52d0
......@@ -1458,12 +1458,12 @@ void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode) {
}
void Assembler::j(Condition cc, Handle<Code> code) {
void Assembler::j(Condition cc, Handle<Code> code, RelocInfo::Mode rmode) {
EnsureSpace ensure_space(this);
// 0000 1111 1000 tttn #32-bit disp
EMIT(0x0F);
EMIT(0x80 | cc);
emit(code, RelocInfo::CODE_TARGET);
emit(code, rmode);
}
......
......@@ -842,7 +842,8 @@ class Assembler : public AssemblerBase {
Label* L,
Label::Distance distance = Label::kFar);
void j(Condition cc, byte* entry, RelocInfo::Mode rmode);
void j(Condition cc, Handle<Code> code);
void j(Condition cc, Handle<Code> code,
RelocInfo::Mode rmode = RelocInfo::CODE_TARGET);
// Floating-point operations
void fld(int i);
......
This diff is collapsed.
......@@ -1746,33 +1746,9 @@ static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
}
static void EmitSlowCase(Isolate* isolate,
MacroAssembler* masm,
int argc,
Label* non_function) {
// Check for function proxy.
__ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, non_function);
__ pop(ecx);
__ push(edi); // put proxy as additional argument under return address
__ push(ecx);
__ Move(eax, Immediate(argc + 1));
__ Move(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX);
{
Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
__ jmp(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);
__ mov(Operand(esp, (argc + 1) * kPointerSize), edi);
__ Move(eax, Immediate(argc));
__ Move(ebx, Immediate(0));
__ GetBuiltinEntry(edx, Context::CALL_NON_FUNCTION_BUILTIN_INDEX);
Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
__ jmp(adaptor, RelocInfo::CODE_TARGET);
static void EmitSlowCase(Isolate* isolate, MacroAssembler* masm, int argc) {
__ Set(eax, argc);
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
}
......@@ -1793,11 +1769,11 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
int argc, bool needs_checks,
bool call_as_method) {
// edi : the function to call
Label slow, non_function, wrap, cont;
Label slow, wrap, cont;
if (needs_checks) {
// Check that the function really is a JavaScript function.
__ JumpIfSmi(edi, &non_function);
__ JumpIfSmi(edi, &slow);
// Goto slow case if we do not have a function.
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
......@@ -1832,8 +1808,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
if (needs_checks) {
// Slow-case: Non-function called.
__ bind(&slow);
// (non_function is bound in EmitSlowCase)
EmitSlowCase(masm->isolate(), masm, argc, &non_function);
EmitSlowCase(masm->isolate(), masm, argc);
}
if (call_as_method) {
......@@ -1977,13 +1952,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.
__ int3();
__ Set(eax, arg_count());
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
}
......@@ -1997,7 +1967,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);
......@@ -2050,7 +2020,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
__ bind(&slow);
EmitSlowCase(isolate, masm, argc, &non_function);
EmitSlowCase(isolate, masm, argc);
if (CallAsMethod()) {
__ bind(&wrap);
......@@ -2131,7 +2101,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&slow_start);
// Check that the function really is a JavaScript function.
__ JumpIfSmi(edi, &non_function);
__ JumpIfSmi(edi, &slow);
// Goto slow case if we do not have a function.
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
......
......@@ -116,6 +116,12 @@ void MacroAssembler::CompareRoot(const Operand& with,
}
void MacroAssembler::PushRoot(Heap::RootListIndex index) {
DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
Push(isolate()->heap()->root_handle(index));
}
void MacroAssembler::InNewSpace(
Register object,
Register scratch,
......@@ -776,6 +782,18 @@ void MacroAssembler::AssertName(Register object) {
}
void MacroAssembler::AssertFunction(Register object) {
if (emit_debug_code()) {
test(object, Immediate(kSmiTagMask));
Check(not_equal, kOperandIsASmiAndNotAFunction);
Push(object);
CmpObjectType(object, JS_FUNCTION_TYPE, object);
Pop(object);
Check(equal, kOperandIsNotAFunction);
}
}
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
if (emit_debug_code()) {
Label done_checking;
......@@ -2062,6 +2080,12 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
}
void MacroAssembler::LoadGlobalProxy(Register dst) {
mov(dst, GlobalObjectOperand());
mov(dst, FieldOperand(dst, GlobalObject::kGlobalProxyOffset));
}
void MacroAssembler::LoadTransitionedArrayMapConditional(
ElementsKind expected_kind,
ElementsKind transitioned_kind,
......
......@@ -71,6 +71,16 @@ class MacroAssembler: public Assembler {
void Load(Register dst, const Operand& src, Representation r);
void Store(Register src, const Operand& dst, Representation r);
// Load a register with a long value as efficiently as possible.
void Set(Register dst, int32_t x) {
if (x == 0) {
xor_(dst, dst);
} else {
mov(dst, Immediate(x));
}
}
void Set(const Operand& dst, int32_t x) { mov(dst, Immediate(x)); }
// Operations on roots in the root-array.
void LoadRoot(Register destination, Heap::RootListIndex index);
void StoreRoot(Register source, Register scratch, Heap::RootListIndex index);
......@@ -79,6 +89,22 @@ class MacroAssembler: public Assembler {
// and not in new space).
void CompareRoot(Register with, Heap::RootListIndex index);
void CompareRoot(const Operand& with, Heap::RootListIndex index);
void PushRoot(Heap::RootListIndex index);
// 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,
Label::Distance if_equal_distance = Label::kNear) {
CompareRoot(with, index);
j(equal, if_equal, if_equal_distance);
}
// 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,
Label::Distance if_not_equal_distance = Label::kNear) {
CompareRoot(with, index);
j(not_equal, if_not_equal, if_not_equal_distance);
}
// ---------------------------------------------------------------------------
// GC Support
......@@ -240,6 +266,9 @@ class MacroAssembler: public Assembler {
// Find the function context up the context chain.
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
......@@ -530,6 +559,9 @@ class MacroAssembler: public Assembler {
// Abort execution if argument is not a name, enabled via --debug-code.
void AssertName(Register object);
// Abort execution if argument is not a JSFunction, enabled via --debug-code.
void AssertFunction(Register object);
// Abort execution if argument is not undefined or an AllocationSite, enabled
// via --debug-code.
void AssertUndefinedOrAllocationSite(Register object);
......@@ -766,8 +798,14 @@ class MacroAssembler: public Assembler {
void Drop(int element_count);
void Call(Label* target) { call(target); }
void Call(Handle<Code> target, RelocInfo::Mode rmode) { call(target, rmode); }
void Jump(Handle<Code> target, RelocInfo::Mode rmode) { jmp(target, rmode); }
void Push(Register src) { push(src); }
void Push(const Operand& src) { push(src); }
void Push(Immediate value) { push(value); }
void Pop(Register dst) { pop(dst); }
void PushReturnAddressFrom(Register src) { push(src); }
void PopReturnAddressTo(Register dst) { pop(dst); }
void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); }
void Lzcnt(Register dst, const Operand& src);
......
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