[ia32,root] Port all CallFunction variants
As part of this, we also update all InvokeFunctionCode callers to pass ecx as the expected-argc register. Drive-by: Inline InvokeFunction overload into its single use. Bug: v8:6666 Change-Id: I67590ecc3f4981d014642c9e18d3ed6db9831e54 Reviewed-on: https://chromium-review.googlesource.com/1233653 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#56040}
This commit is contained in:
parent
15b7c38969
commit
23cf68ac2c
@ -17,15 +17,24 @@ namespace internal {
|
||||
|
||||
void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined(
|
||||
MacroAssembler* masm) {
|
||||
#ifdef V8_TARGET_ARCH_IA32
|
||||
Assembler::SupportsRootRegisterScope supports_root_register(masm);
|
||||
#endif
|
||||
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined);
|
||||
}
|
||||
|
||||
void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined(
|
||||
MacroAssembler* masm) {
|
||||
#ifdef V8_TARGET_ARCH_IA32
|
||||
Assembler::SupportsRootRegisterScope supports_root_register(masm);
|
||||
#endif
|
||||
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined);
|
||||
}
|
||||
|
||||
void Builtins::Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
|
||||
#ifdef V8_TARGET_ARCH_IA32
|
||||
Assembler::SupportsRootRegisterScope supports_root_register(masm);
|
||||
#endif
|
||||
Generate_CallFunction(masm, ConvertReceiverMode::kAny);
|
||||
}
|
||||
|
||||
|
@ -1866,6 +1866,8 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
|
||||
// static
|
||||
void Builtins::Generate_CallFunction(MacroAssembler* masm,
|
||||
ConvertReceiverMode mode) {
|
||||
Assembler::SupportsRootRegisterScope supports_root_register(masm);
|
||||
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : the number of arguments (not including the receiver)
|
||||
// -- edi : the function to call (checked to be a JSFunction)
|
||||
@ -1906,8 +1908,10 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
|
||||
__ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
|
||||
__ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
|
||||
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
|
||||
__ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
|
||||
__ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ecx); // Clobbers ecx.
|
||||
__ j(above_equal, &done_convert);
|
||||
// Reload the receiver (it was clobbered by CmpObjectType).
|
||||
__ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
|
||||
if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
|
||||
Label convert_global_proxy;
|
||||
__ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
|
||||
@ -1955,9 +1959,9 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
|
||||
// -----------------------------------
|
||||
|
||||
__ movzx_w(
|
||||
ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
ecx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
ParameterCount actual(eax);
|
||||
ParameterCount expected(ebx);
|
||||
ParameterCount expected(ecx);
|
||||
__ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION);
|
||||
// The function is a "classConstructor", need to raise an exception.
|
||||
__ bind(&class_constructor);
|
||||
|
@ -40,11 +40,13 @@ void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) {
|
||||
__ movzx_w(
|
||||
eax, FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
|
||||
ParameterCount dummy(eax);
|
||||
__ InvokeFunction(edi, dummy, dummy, JUMP_FUNCTION);
|
||||
// The expected and actual argument counts don't matter as long as they match
|
||||
// and we don't enter the ArgumentsAdaptorTrampoline.
|
||||
ParameterCount dummy(0);
|
||||
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
|
||||
__ InvokeFunctionCode(edi, no_reg, dummy, dummy, JUMP_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
const bool LiveEdit::kFrameDropperSupported = true;
|
||||
|
||||
#undef __
|
||||
|
@ -1037,6 +1037,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
|
||||
bool* definitely_mismatches,
|
||||
InvokeFlag flag,
|
||||
Label::Distance done_near) {
|
||||
DCHECK_IMPLIES(expected.is_reg(), expected.reg() == ecx);
|
||||
DCHECK_IMPLIES(actual.is_reg(), actual.reg() == eax);
|
||||
|
||||
bool definitely_matches = false;
|
||||
*definitely_mismatches = false;
|
||||
Label invoke;
|
||||
@ -1055,7 +1058,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
|
||||
definitely_matches = true;
|
||||
} else {
|
||||
*definitely_mismatches = true;
|
||||
mov(ebx, expected.immediate());
|
||||
mov(ecx, expected.immediate());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1066,14 +1069,14 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
|
||||
mov(eax, actual.immediate());
|
||||
cmp(expected.reg(), actual.immediate());
|
||||
j(equal, &invoke);
|
||||
DCHECK(expected.reg() == ebx);
|
||||
DCHECK(expected.reg() == ecx);
|
||||
} else if (expected.reg() != actual.reg()) {
|
||||
// Both expected and actual are in (different) registers. This
|
||||
// is the case when we invoke functions using call and apply.
|
||||
cmp(expected.reg(), actual.reg());
|
||||
j(equal, &invoke);
|
||||
DCHECK(actual.reg() == eax);
|
||||
DCHECK(expected.reg() == ebx);
|
||||
DCHECK(expected.reg() == ecx);
|
||||
} else {
|
||||
definitely_matches = true;
|
||||
Move(eax, actual.reg());
|
||||
@ -1081,9 +1084,6 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
|
||||
}
|
||||
|
||||
if (!definitely_matches) {
|
||||
// TODO(v8:6666): All call-sites should be updated to pass in ecx as the
|
||||
// expected register to avoid this useless move.
|
||||
MoveForRootRegisterRefactoring(ecx, ebx);
|
||||
Handle<Code> adaptor = BUILTIN_CODE(isolate(), ArgumentsAdaptorTrampoline);
|
||||
if (flag == CALL_FUNCTION) {
|
||||
Call(adaptor, RelocInfo::CODE_TARGET);
|
||||
@ -1155,6 +1155,8 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
|
||||
DCHECK(flag == JUMP_FUNCTION || has_frame());
|
||||
DCHECK(function == edi);
|
||||
DCHECK_IMPLIES(new_target.is_valid(), new_target == edx);
|
||||
DCHECK_IMPLIES(expected.is_reg(), expected.reg() == ecx);
|
||||
DCHECK_IMPLIES(actual.is_reg(), actual.reg() == eax);
|
||||
|
||||
// On function call, call into the debugger if necessary.
|
||||
CheckDebugHook(function, new_target, expected, actual);
|
||||
@ -1192,28 +1194,15 @@ void MacroAssembler::InvokeFunction(Register fun, Register new_target,
|
||||
DCHECK(flag == JUMP_FUNCTION || has_frame());
|
||||
|
||||
DCHECK(fun == edi);
|
||||
mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||
mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
|
||||
movzx_w(ebx,
|
||||
FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
movzx_w(ecx,
|
||||
FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||
|
||||
ParameterCount expected(ebx);
|
||||
ParameterCount expected(ecx);
|
||||
InvokeFunctionCode(edi, new_target, expected, actual, flag);
|
||||
}
|
||||
|
||||
void MacroAssembler::InvokeFunction(Register fun,
|
||||
const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
InvokeFlag flag) {
|
||||
// You can't call a function without a valid frame.
|
||||
DCHECK(flag == JUMP_FUNCTION || has_frame());
|
||||
|
||||
DCHECK(fun == edi);
|
||||
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
|
||||
|
||||
InvokeFunctionCode(edi, no_reg, expected, actual, flag);
|
||||
}
|
||||
|
||||
void MacroAssembler::LoadGlobalProxy(Register dst) {
|
||||
mov(dst, NativeContextOperand());
|
||||
mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX));
|
||||
|
@ -608,9 +608,6 @@ class MacroAssembler : public TurboAssembler {
|
||||
void InvokeFunction(Register function, Register new_target,
|
||||
const ParameterCount& actual, InvokeFlag flag);
|
||||
|
||||
void InvokeFunction(Register function, const ParameterCount& expected,
|
||||
const ParameterCount& actual, InvokeFlag flag);
|
||||
|
||||
// Compare object type for heap object.
|
||||
// Incoming register is heap_object and outgoing register is map.
|
||||
void CmpObjectType(Register heap_object, InstanceType type, Register map);
|
||||
|
Loading…
Reference in New Issue
Block a user