Commit b9a6301e authored by Patrick Thier's avatar Patrick Thier Committed by V8 LUCI CQ

[masm] Improve Instance Type Checks in Builtins::Call/Construct

Load instance type into a register instead of using memory operands for
several checks on ia32 and x64.

Drive-by: Name used registers in Generate_Call/Generate_Construct

Change-Id: I289c5e420fa03ca639c9b78266560cafb166f6f7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3190099Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77156}
parent c5c60391
...@@ -2466,38 +2466,48 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2466,38 +2466,48 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- r0 : the number of arguments // -- r0 : the number of arguments
// -- r1 : the target to call (can be any Object). // -- r1 : the target to call (can be any Object).
// ----------------------------------- // -----------------------------------
Register argc = r0;
Register target = r1;
Register map = r4;
Register instance_type = r5;
DCHECK(!AreAliased(argc, target, map, instance_type));
Label non_callable, class_constructor; Label non_callable, class_constructor;
__ JumpIfSmi(r1, &non_callable); __ JumpIfSmi(target, &non_callable);
__ LoadMap(r4, r1); __ LoadMap(map, target);
__ CompareInstanceTypeRange(r4, r5, FIRST_CALLABLE_JS_FUNCTION_TYPE, __ CompareInstanceTypeRange(map, instance_type,
FIRST_CALLABLE_JS_FUNCTION_TYPE,
LAST_CALLABLE_JS_FUNCTION_TYPE); LAST_CALLABLE_JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(mode), __ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, ls); RelocInfo::CODE_TARGET, ls);
__ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE)); __ cmp(instance_type, Operand(JS_BOUND_FUNCTION_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction),
RelocInfo::CODE_TARGET, eq); RelocInfo::CODE_TARGET, eq);
// Check if target has a [[Call]] internal method. // Check if target has a [[Call]] internal method.
__ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset)); {
__ tst(r4, Operand(Map::Bits1::IsCallableBit::kMask)); Register flags = r4;
__ b(eq, &non_callable); __ ldrb(flags, FieldMemOperand(map, Map::kBitFieldOffset));
map = no_reg;
__ tst(flags, Operand(Map::Bits1::IsCallableBit::kMask));
__ b(eq, &non_callable);
}
// Check if target is a proxy and call CallProxy external builtin // Check if target is a proxy and call CallProxy external builtin
__ cmp(r5, Operand(JS_PROXY_TYPE)); __ cmp(instance_type, Operand(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq); __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq);
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
// Check that the function is not a "classConstructor". // Check that the function is not a "classConstructor".
__ cmp(r5, Operand(JS_CLASS_CONSTRUCTOR_TYPE)); __ cmp(instance_type, Operand(JS_CLASS_CONSTRUCTOR_TYPE));
__ b(eq, &class_constructor); __ b(eq, &class_constructor);
// 2. Call to something else, which might have a [[Call]] internal method (if // 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception). // not we raise an exception).
// Overwrite the original receiver the (original) target. // Overwrite the original receiver the (original) target.
__ str(r1, __ ReceiverOperand(r0)); __ str(target, __ ReceiverOperand(argc));
// Let the "call_as_function_delegate" take care of the rest. // Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(r1, Context::CALL_AS_FUNCTION_DELEGATE_INDEX); __ LoadNativeContextSlot(target, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction( __ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined), ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -2506,7 +2516,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2506,7 +2516,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&non_callable); __ bind(&non_callable);
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r1); __ Push(target);
__ CallRuntime(Runtime::kThrowCalledNonCallable); __ CallRuntime(Runtime::kThrowCalledNonCallable);
__ Trap(); // Unreachable. __ Trap(); // Unreachable.
} }
...@@ -2515,7 +2525,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2515,7 +2525,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&class_constructor); __ bind(&class_constructor);
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r1); __ Push(target);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError); __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
__ Trap(); // Unreachable. __ Trap(); // Unreachable.
} }
...@@ -2582,31 +2592,40 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -2582,31 +2592,40 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -- r3 : the new target (either the same as the constructor or // -- r3 : the new target (either the same as the constructor or
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// ----------------------------------- // -----------------------------------
Register argc = r0;
Register target = r1;
Register map = r4;
Register instance_type = r5;
DCHECK(!AreAliased(argc, target, map, instance_type));
// Check if target is a Smi. // Check if target is a Smi.
Label non_constructor, non_proxy; Label non_constructor, non_proxy;
__ JumpIfSmi(r1, &non_constructor); __ JumpIfSmi(target, &non_constructor);
// Check if target has a [[Construct]] internal method. // Check if target has a [[Construct]] internal method.
__ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset)); __ ldr(map, FieldMemOperand(target, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r4, Map::kBitFieldOffset)); {
__ tst(r2, Operand(Map::Bits1::IsConstructorBit::kMask)); Register flags = r2;
__ b(eq, &non_constructor); DCHECK(!AreAliased(argc, target, map, instance_type, flags));
__ ldrb(flags, FieldMemOperand(map, Map::kBitFieldOffset));
__ tst(flags, Operand(Map::Bits1::IsConstructorBit::kMask));
__ b(eq, &non_constructor);
}
// Dispatch based on instance type. // Dispatch based on instance type.
__ CompareInstanceTypeRange(r4, r5, FIRST_JS_FUNCTION_TYPE, __ CompareInstanceTypeRange(map, instance_type, FIRST_JS_FUNCTION_TYPE,
LAST_JS_FUNCTION_TYPE); LAST_JS_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, ls); RelocInfo::CODE_TARGET, ls);
// Only dispatch to bound functions after checking whether they are // Only dispatch to bound functions after checking whether they are
// constructors. // constructors.
__ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE)); __ cmp(instance_type, Operand(JS_BOUND_FUNCTION_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),
RelocInfo::CODE_TARGET, eq); RelocInfo::CODE_TARGET, eq);
// Only dispatch to proxies after checking whether they are constructors. // Only dispatch to proxies after checking whether they are constructors.
__ cmp(r5, Operand(JS_PROXY_TYPE)); __ cmp(instance_type, Operand(JS_PROXY_TYPE));
__ b(ne, &non_proxy); __ b(ne, &non_proxy);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -2615,9 +2634,10 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -2615,9 +2634,10 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ bind(&non_proxy); __ bind(&non_proxy);
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.
__ str(r1, __ ReceiverOperand(r0)); __ str(target, __ ReceiverOperand(argc));
// Let the "call_as_constructor_delegate" take care of the rest. // Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(r1, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX); __ LoadNativeContextSlot(target,
Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(), __ Jump(masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} }
......
...@@ -2891,39 +2891,49 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2891,39 +2891,49 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- x0 : the number of arguments // -- x0 : the number of arguments
// -- x1 : the target to call (can be any Object). // -- x1 : the target to call (can be any Object).
// ----------------------------------- // -----------------------------------
Register argc = x0;
Register target = x1;
Register map = x4;
Register instance_type = x5;
DCHECK(!AreAliased(argc, target, map, instance_type));
Label non_callable, class_constructor; Label non_callable, class_constructor;
__ JumpIfSmi(x1, &non_callable); __ JumpIfSmi(target, &non_callable);
__ LoadMap(x4, x1); __ LoadMap(map, target);
__ CompareInstanceTypeRange(x4, x5, FIRST_CALLABLE_JS_FUNCTION_TYPE, __ CompareInstanceTypeRange(map, instance_type,
FIRST_CALLABLE_JS_FUNCTION_TYPE,
LAST_CALLABLE_JS_FUNCTION_TYPE); LAST_CALLABLE_JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(mode), __ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, ls); RelocInfo::CODE_TARGET, ls);
__ Cmp(x5, JS_BOUND_FUNCTION_TYPE); __ Cmp(instance_type, JS_BOUND_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction),
RelocInfo::CODE_TARGET, eq); RelocInfo::CODE_TARGET, eq);
// Check if target has a [[Call]] internal method. // Check if target has a [[Call]] internal method.
__ Ldrb(x4, FieldMemOperand(x4, Map::kBitFieldOffset)); {
__ TestAndBranchIfAllClear(x4, Map::Bits1::IsCallableBit::kMask, Register flags = x4;
&non_callable); __ Ldrb(flags, FieldMemOperand(map, Map::kBitFieldOffset));
map = no_reg;
__ TestAndBranchIfAllClear(flags, Map::Bits1::IsCallableBit::kMask,
&non_callable);
}
// Check if target is a proxy and call CallProxy external builtin // Check if target is a proxy and call CallProxy external builtin
__ Cmp(x5, JS_PROXY_TYPE); __ Cmp(instance_type, JS_PROXY_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq); __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq);
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
// Check that the function is not a "classConstructor". // Check that the function is not a "classConstructor".
__ Cmp(x5, JS_CLASS_CONSTRUCTOR_TYPE); __ Cmp(instance_type, JS_CLASS_CONSTRUCTOR_TYPE);
__ B(eq, &class_constructor); __ B(eq, &class_constructor);
// 2. Call to something else, which might have a [[Call]] internal method (if // 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception). // not we raise an exception).
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.
__ Poke(x1, __ ReceiverOperand(x0)); __ Poke(target, __ ReceiverOperand(argc));
// Let the "call_as_function_delegate" take care of the rest. // Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(x1, Context::CALL_AS_FUNCTION_DELEGATE_INDEX); __ LoadNativeContextSlot(target, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction( __ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined), ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -2932,7 +2942,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2932,7 +2942,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&non_callable); __ bind(&non_callable);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ PushArgument(x1); __ PushArgument(target);
__ CallRuntime(Runtime::kThrowCalledNonCallable); __ CallRuntime(Runtime::kThrowCalledNonCallable);
__ Unreachable(); __ Unreachable();
} }
...@@ -2941,7 +2951,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2941,7 +2951,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&class_constructor); __ bind(&class_constructor);
{ {
FrameScope frame(masm, StackFrame::INTERNAL); FrameScope frame(masm, StackFrame::INTERNAL);
__ PushArgument(x1); __ PushArgument(target);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError); __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
__ Unreachable(); __ Unreachable();
} }
...@@ -3015,31 +3025,41 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -3015,31 +3025,41 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// -- x3 : the new target (either the same as the constructor or // -- x3 : the new target (either the same as the constructor or
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// ----------------------------------- // -----------------------------------
Register argc = x0;
Register target = x1;
Register map = x4;
Register instance_type = x5;
DCHECK(!AreAliased(argc, target, map, instance_type));
// Check if target is a Smi. // Check if target is a Smi.
Label non_constructor, non_proxy; Label non_constructor, non_proxy;
__ JumpIfSmi(x1, &non_constructor); __ JumpIfSmi(target, &non_constructor);
// Check if target has a [[Construct]] internal method. // Check if target has a [[Construct]] internal method.
__ LoadTaggedPointerField(x4, FieldMemOperand(x1, HeapObject::kMapOffset)); __ LoadTaggedPointerField(map,
__ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset)); FieldMemOperand(target, HeapObject::kMapOffset));
__ TestAndBranchIfAllClear(x2, Map::Bits1::IsConstructorBit::kMask, {
&non_constructor); Register flags = x2;
DCHECK(!AreAliased(argc, target, map, instance_type, flags));
__ Ldrb(flags, FieldMemOperand(map, Map::kBitFieldOffset));
__ TestAndBranchIfAllClear(flags, Map::Bits1::IsConstructorBit::kMask,
&non_constructor);
}
// Dispatch based on instance type. // Dispatch based on instance type.
__ CompareInstanceTypeRange(x4, x5, FIRST_JS_FUNCTION_TYPE, __ CompareInstanceTypeRange(map, instance_type, FIRST_JS_FUNCTION_TYPE,
LAST_JS_FUNCTION_TYPE); LAST_JS_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, ls); RelocInfo::CODE_TARGET, ls);
// Only dispatch to bound functions after checking whether they are // Only dispatch to bound functions after checking whether they are
// constructors. // constructors.
__ Cmp(x5, JS_BOUND_FUNCTION_TYPE); __ Cmp(instance_type, JS_BOUND_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),
RelocInfo::CODE_TARGET, eq); RelocInfo::CODE_TARGET, eq);
// Only dispatch to proxies after checking whether they are constructors. // Only dispatch to proxies after checking whether they are constructors.
__ Cmp(x5, JS_PROXY_TYPE); __ Cmp(instance_type, JS_PROXY_TYPE);
__ B(ne, &non_proxy); __ B(ne, &non_proxy);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -3048,10 +3068,11 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -3048,10 +3068,11 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ bind(&non_proxy); __ bind(&non_proxy);
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.
__ Poke(x1, __ ReceiverOperand(x0)); __ Poke(target, __ ReceiverOperand(argc));
// Let the "call_as_constructor_delegate" take care of the rest. // Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(x1, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX); __ LoadNativeContextSlot(target,
Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(), __ Jump(masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} }
......
...@@ -2642,49 +2642,56 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2642,49 +2642,56 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- eax : the number of arguments // -- eax : the number of arguments
// -- edi : the target to call (can be any Object). // -- edi : the target to call (can be any Object).
// ----------------------------------- // -----------------------------------
StackArgumentsAccessor args(eax); Register argc = eax;
Register target = edi;
Register map = ecx;
Register instance_type = edx;
DCHECK(!AreAliased(argc, target, map, instance_type));
StackArgumentsAccessor args(argc);
Label non_callable, non_smi, non_callable_jsfunction, non_jsboundfunction, Label non_callable, non_smi, non_callable_jsfunction, non_jsboundfunction,
non_proxy, class_constructor; non_proxy, class_constructor;
__ JumpIfSmi(edi, &non_callable); __ JumpIfSmi(target, &non_callable);
__ bind(&non_smi); __ bind(&non_smi);
__ LoadMap(ecx, edi); __ LoadMap(map, target);
__ CmpInstanceTypeRange(ecx, ecx, FIRST_CALLABLE_JS_FUNCTION_TYPE, __ CmpInstanceTypeRange(map, instance_type, map,
FIRST_CALLABLE_JS_FUNCTION_TYPE,
LAST_CALLABLE_JS_FUNCTION_TYPE); LAST_CALLABLE_JS_FUNCTION_TYPE);
__ j(above, &non_callable_jsfunction); __ j(above, &non_callable_jsfunction);
__ Jump(masm->isolate()->builtins()->CallFunction(mode), __ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
__ bind(&non_callable_jsfunction); __ bind(&non_callable_jsfunction);
__ LoadMap(ecx, edi); __ cmpw(instance_type, Immediate(JS_BOUND_FUNCTION_TYPE));
__ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
__ j(not_equal, &non_jsboundfunction); __ j(not_equal, &non_jsboundfunction);
__ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
// Check if target is a proxy and call CallProxy external builtin // Check if target is a proxy and call CallProxy external builtin
__ bind(&non_jsboundfunction); __ bind(&non_jsboundfunction);
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), __ LoadMap(map, target);
__ test_b(FieldOperand(map, Map::kBitFieldOffset),
Immediate(Map::Bits1::IsCallableBit::kMask)); Immediate(Map::Bits1::IsCallableBit::kMask));
__ j(zero, &non_callable); __ j(zero, &non_callable);
// Call CallProxy external builtin // Call CallProxy external builtin
__ CmpInstanceType(ecx, JS_PROXY_TYPE); __ cmpw(instance_type, Immediate(JS_PROXY_TYPE));
__ j(not_equal, &non_proxy); __ j(not_equal, &non_proxy);
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET); __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET);
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
// Check that the function is not a "classConstructor". // Check that the function is not a "classConstructor".
__ bind(&non_proxy); __ bind(&non_proxy);
__ CmpInstanceType(ecx, JS_CLASS_CONSTRUCTOR_TYPE); __ cmpw(instance_type, Immediate(JS_CLASS_CONSTRUCTOR_TYPE));
__ j(equal, &class_constructor); __ j(equal, &class_constructor);
// 2. Call to something else, which might have a [[Call]] internal method (if // 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception). // not we raise an exception).
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.
__ mov(args.GetReceiverOperand(), edi); __ mov(args.GetReceiverOperand(), target);
// Let the "call_as_function_delegate" take care of the rest. // Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(edi, Context::CALL_AS_FUNCTION_DELEGATE_INDEX); __ LoadNativeContextSlot(target, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction( __ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined), ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -2693,7 +2700,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2693,7 +2700,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&non_callable); __ bind(&non_callable);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(edi); __ Push(target);
__ CallRuntime(Runtime::kThrowCalledNonCallable); __ CallRuntime(Runtime::kThrowCalledNonCallable);
__ Trap(); // Unreachable. __ Trap(); // Unreachable.
} }
...@@ -2702,7 +2709,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2702,7 +2709,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&class_constructor); __ bind(&class_constructor);
{ {
FrameScope frame(masm, StackFrame::INTERNAL); FrameScope frame(masm, StackFrame::INTERNAL);
__ Push(edi); __ Push(target);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError); __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
__ Trap(); // Unreachable. __ Trap(); // Unreachable.
} }
...@@ -2775,20 +2782,25 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -2775,20 +2782,25 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// -- edi : the constructor to call (can be any Object) // -- edi : the constructor to call (can be any Object)
// ----------------------------------- // -----------------------------------
StackArgumentsAccessor args(eax); Register argc = eax;
Register target = edi;
Register map = ecx;
DCHECK(!AreAliased(argc, target, map));
StackArgumentsAccessor args(argc);
// Check if target is a Smi. // Check if target is a Smi.
Label non_constructor, non_proxy, non_jsfunction, non_jsboundfunction; Label non_constructor, non_proxy, non_jsfunction, non_jsboundfunction;
__ JumpIfSmi(edi, &non_constructor); __ JumpIfSmi(target, &non_constructor);
// Check if target has a [[Construct]] internal method. // Check if target has a [[Construct]] internal method.
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); __ mov(map, FieldOperand(target, HeapObject::kMapOffset));
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), __ test_b(FieldOperand(map, Map::kBitFieldOffset),
Immediate(Map::Bits1::IsConstructorBit::kMask)); Immediate(Map::Bits1::IsConstructorBit::kMask));
__ j(zero, &non_constructor); __ j(zero, &non_constructor);
// Dispatch based on instance type. // Dispatch based on instance type.
__ CmpInstanceTypeRange(ecx, ecx, FIRST_JS_FUNCTION_TYPE, __ CmpInstanceTypeRange(map, map, map, FIRST_JS_FUNCTION_TYPE,
LAST_JS_FUNCTION_TYPE); LAST_JS_FUNCTION_TYPE);
__ j(above, &non_jsfunction); __ j(above, &non_jsfunction);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
...@@ -2797,15 +2809,15 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -2797,15 +2809,15 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// Only dispatch to bound functions after checking whether they are // Only dispatch to bound functions after checking whether they are
// constructors. // constructors.
__ bind(&non_jsfunction); __ bind(&non_jsfunction);
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); __ mov(map, FieldOperand(target, HeapObject::kMapOffset));
__ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); __ CmpInstanceType(map, JS_BOUND_FUNCTION_TYPE);
__ j(not_equal, &non_jsboundfunction); __ j(not_equal, &non_jsboundfunction);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
// Only dispatch to proxies after checking whether they are constructors. // Only dispatch to proxies after checking whether they are constructors.
__ bind(&non_jsboundfunction); __ bind(&non_jsboundfunction);
__ CmpInstanceType(ecx, JS_PROXY_TYPE); __ CmpInstanceType(map, JS_PROXY_TYPE);
__ j(not_equal, &non_proxy); __ j(not_equal, &non_proxy);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -2814,9 +2826,10 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -2814,9 +2826,10 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ bind(&non_proxy); __ bind(&non_proxy);
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.
__ mov(args.GetReceiverOperand(), edi); __ mov(args.GetReceiverOperand(), target);
// Let the "call_as_constructor_delegate" take care of the rest. // Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(edi, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX); __ LoadNativeContextSlot(target,
Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(), __ Jump(masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} }
......
...@@ -2574,42 +2574,48 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2574,42 +2574,48 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- rax : the number of arguments // -- rax : the number of arguments
// -- rdi : the target to call (can be any Object) // -- rdi : the target to call (can be any Object)
// ----------------------------------- // -----------------------------------
StackArgumentsAccessor args(rax); Register argc = rax;
Register target = rdi;
Register map = rcx;
Register instance_type = rdx;
DCHECK(!AreAliased(argc, target, map, instance_type));
StackArgumentsAccessor args(argc);
Label non_callable, class_constructor; Label non_callable, class_constructor;
__ JumpIfSmi(rdi, &non_callable); __ JumpIfSmi(target, &non_callable);
__ LoadMap(rcx, rdi); __ LoadMap(map, target);
__ CmpInstanceTypeRange(rcx, FIRST_CALLABLE_JS_FUNCTION_TYPE, __ CmpInstanceTypeRange(map, instance_type, FIRST_CALLABLE_JS_FUNCTION_TYPE,
LAST_CALLABLE_JS_FUNCTION_TYPE); LAST_CALLABLE_JS_FUNCTION_TYPE);
__ Jump(masm->isolate()->builtins()->CallFunction(mode), __ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, below_equal); RelocInfo::CODE_TARGET, below_equal);
__ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE); __ cmpw(instance_type, Immediate(JS_BOUND_FUNCTION_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction),
RelocInfo::CODE_TARGET, equal); RelocInfo::CODE_TARGET, equal);
// Check if target has a [[Call]] internal method. // Check if target has a [[Call]] internal method.
__ testb(FieldOperand(rcx, Map::kBitFieldOffset), __ testb(FieldOperand(map, Map::kBitFieldOffset),
Immediate(Map::Bits1::IsCallableBit::kMask)); Immediate(Map::Bits1::IsCallableBit::kMask));
__ j(zero, &non_callable, Label::kNear); __ j(zero, &non_callable, Label::kNear);
// Check if target is a proxy and call CallProxy external builtin // Check if target is a proxy and call CallProxy external builtin
__ CmpInstanceType(rcx, JS_PROXY_TYPE); __ cmpw(instance_type, Immediate(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET,
equal); equal);
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
// Check that the function is not a "classConstructor". // Check that the function is not a "classConstructor".
__ CmpInstanceType(rcx, JS_CLASS_CONSTRUCTOR_TYPE); __ cmpw(instance_type, Immediate(JS_CLASS_CONSTRUCTOR_TYPE));
__ j(equal, &class_constructor); __ j(equal, &class_constructor);
// 2. Call to something else, which might have a [[Call]] internal method (if // 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception). // not we raise an exception).
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.
__ movq(args.GetReceiverOperand(), rdi); __ movq(args.GetReceiverOperand(), target);
// Let the "call_as_function_delegate" take care of the rest. // Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(rdi, Context::CALL_AS_FUNCTION_DELEGATE_INDEX); __ LoadNativeContextSlot(target, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction( __ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined), ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -2618,7 +2624,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2618,7 +2624,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&non_callable); __ bind(&non_callable);
{ {
FrameScope scope(masm, StackFrame::INTERNAL); FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(rdi); __ Push(target);
__ CallRuntime(Runtime::kThrowCalledNonCallable); __ CallRuntime(Runtime::kThrowCalledNonCallable);
__ Trap(); // Unreachable. __ Trap(); // Unreachable.
} }
...@@ -2627,7 +2633,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { ...@@ -2627,7 +2633,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&class_constructor); __ bind(&class_constructor);
{ {
FrameScope frame(masm, StackFrame::INTERNAL); FrameScope frame(masm, StackFrame::INTERNAL);
__ Push(rdi); __ Push(target);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError); __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
__ Trap(); // Unreachable. __ Trap(); // Unreachable.
} }
...@@ -2696,40 +2702,48 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { ...@@ -2696,40 +2702,48 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// -- rdi : the constructor to call (can be any Object) // -- rdi : the constructor to call (can be any Object)
// ----------------------------------- // -----------------------------------
StackArgumentsAccessor args(rax); Register argc = rax;
Register target = rdi;
Register map = rcx;
Register instance_type = r8;
DCHECK(!AreAliased(argc, target, map, instance_type));
StackArgumentsAccessor args(argc);
// Check if target is a Smi. // Check if target is a Smi.
Label non_constructor; Label non_constructor;
__ JumpIfSmi(rdi, &non_constructor); __ JumpIfSmi(target, &non_constructor);
// Check if target has a [[Construct]] internal method. // Check if target has a [[Construct]] internal method.
__ LoadMap(rcx, rdi); __ LoadMap(map, target);
__ testb(FieldOperand(rcx, Map::kBitFieldOffset), __ testb(FieldOperand(map, Map::kBitFieldOffset),
Immediate(Map::Bits1::IsConstructorBit::kMask)); Immediate(Map::Bits1::IsConstructorBit::kMask));
__ j(zero, &non_constructor); __ j(zero, &non_constructor);
// Dispatch based on instance type. // Dispatch based on instance type.
__ CmpInstanceTypeRange(rcx, FIRST_JS_FUNCTION_TYPE, LAST_JS_FUNCTION_TYPE); __ CmpInstanceTypeRange(map, instance_type, FIRST_JS_FUNCTION_TYPE,
LAST_JS_FUNCTION_TYPE);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, below_equal); RelocInfo::CODE_TARGET, below_equal);
// Only dispatch to bound functions after checking whether they are // Only dispatch to bound functions after checking whether they are
// constructors. // constructors.
__ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE); __ cmpw(instance_type, Immediate(JS_BOUND_FUNCTION_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction), __ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),
RelocInfo::CODE_TARGET, equal); RelocInfo::CODE_TARGET, equal);
// Only dispatch to proxies after checking whether they are constructors. // Only dispatch to proxies after checking whether they are constructors.
__ CmpInstanceType(rcx, JS_PROXY_TYPE); __ cmpw(instance_type, Immediate(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy), RelocInfo::CODE_TARGET, __ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy), RelocInfo::CODE_TARGET,
equal); equal);
// Called Construct on an exotic Object with a [[Construct]] internal method. // Called Construct on an exotic Object with a [[Construct]] internal method.
{ {
// Overwrite the original receiver with the (original) target. // Overwrite the original receiver with the (original) target.
__ movq(args.GetReceiverOperand(), rdi); __ movq(args.GetReceiverOperand(), target);
// Let the "call_as_constructor_delegate" take care of the rest. // Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(rdi, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX); __ LoadNativeContextSlot(target,
Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(), __ Jump(masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} }
......
...@@ -1877,16 +1877,26 @@ void MacroAssembler::CompareInstanceType(Register map, Register type_reg, ...@@ -1877,16 +1877,26 @@ void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
cmp(type_reg, Operand(type)); cmp(type_reg, Operand(type));
} }
void MacroAssembler::CompareRange(Register value, unsigned lower_limit,
unsigned higher_limit) {
ASM_CODE_COMMENT(this);
DCHECK_LT(lower_limit, higher_limit);
if (lower_limit != 0) {
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
sub(scratch, value, Operand(lower_limit));
cmp(scratch, Operand(higher_limit - lower_limit));
} else {
cmp(value, Operand(higher_limit));
}
}
void MacroAssembler::CompareInstanceTypeRange(Register map, Register type_reg, void MacroAssembler::CompareInstanceTypeRange(Register map, Register type_reg,
InstanceType lower_limit, InstanceType lower_limit,
InstanceType higher_limit) { InstanceType higher_limit) {
ASM_CODE_COMMENT(this); ASM_CODE_COMMENT(this);
DCHECK_LT(lower_limit, higher_limit); DCHECK_LT(lower_limit, higher_limit);
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
ldrh(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); ldrh(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
sub(scratch, type_reg, Operand(lower_limit)); CompareRange(type_reg, lower_limit, higher_limit);
cmp(scratch, Operand(higher_limit - lower_limit));
} }
void MacroAssembler::CompareRoot(Register obj, RootIndex index) { void MacroAssembler::CompareRoot(Register obj, RootIndex index) {
...@@ -1901,14 +1911,7 @@ void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit, ...@@ -1901,14 +1911,7 @@ void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, unsigned higher_limit,
Label* on_in_range) { Label* on_in_range) {
ASM_CODE_COMMENT(this); ASM_CODE_COMMENT(this);
if (lower_limit != 0) { CompareRange(value, lower_limit, higher_limit);
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
sub(scratch, value, Operand(lower_limit));
cmp(scratch, Operand(higher_limit - lower_limit));
} else {
cmp(value, Operand(higher_limit));
}
b(ls, on_in_range); b(ls, on_in_range);
} }
......
...@@ -757,7 +757,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -757,7 +757,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
} }
// Checks if value is in range [lower_limit, higher_limit] using a single // Checks if value is in range [lower_limit, higher_limit] using a single
// comparison. // comparison. Flags C=0 or Z=1 indicate the value is in the range (condition
// ls).
void CompareRange(Register value, unsigned lower_limit,
unsigned higher_limit);
void JumpIfIsInRange(Register value, unsigned lower_limit, void JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range); unsigned higher_limit, Label* on_in_range);
......
...@@ -158,16 +158,23 @@ void MacroAssembler::PushRoot(RootIndex index) { ...@@ -158,16 +158,23 @@ void MacroAssembler::PushRoot(RootIndex index) {
} }
} }
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit, void MacroAssembler::CompareRange(Register value, unsigned lower_limit,
unsigned higher_limit, Register scratch, unsigned higher_limit, Register scratch) {
Label* on_in_range, ASM_CODE_COMMENT(this);
Label::Distance near_jump) { DCHECK_LT(lower_limit, higher_limit);
if (lower_limit != 0) { if (lower_limit != 0) {
lea(scratch, Operand(value, 0u - lower_limit)); lea(scratch, Operand(value, 0u - lower_limit));
cmp(scratch, Immediate(higher_limit - lower_limit)); cmp(scratch, Immediate(higher_limit - lower_limit));
} else { } else {
cmp(value, Immediate(higher_limit)); cmp(value, Immediate(higher_limit));
} }
}
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Register scratch,
Label* on_in_range,
Label::Distance near_jump) {
CompareRange(value, lower_limit, higher_limit, scratch);
j(below_equal, on_in_range, near_jump); j(below_equal, on_in_range, near_jump);
} }
...@@ -723,14 +730,15 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { ...@@ -723,14 +730,15 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
cmpw(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type)); cmpw(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type));
} }
void MacroAssembler::CmpInstanceTypeRange(Register map, Register scratch, void MacroAssembler::CmpInstanceTypeRange(Register map,
Register instance_type_out,
Register scratch,
InstanceType lower_limit, InstanceType lower_limit,
InstanceType higher_limit) { InstanceType higher_limit) {
ASM_CODE_COMMENT(this); ASM_CODE_COMMENT(this);
DCHECK_LT(lower_limit, higher_limit); DCHECK_LT(lower_limit, higher_limit);
movzx_w(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); movzx_w(instance_type_out, FieldOperand(map, Map::kInstanceTypeOffset));
lea(scratch, Operand(scratch, 0u - lower_limit)); CompareRange(instance_type_out, lower_limit, higher_limit, scratch);
cmp(scratch, Immediate(higher_limit - lower_limit));
} }
void MacroAssembler::AssertSmi(Register object) { void MacroAssembler::AssertSmi(Register object) {
...@@ -762,7 +770,7 @@ void MacroAssembler::AssertFunction(Register object, Register scratch) { ...@@ -762,7 +770,7 @@ void MacroAssembler::AssertFunction(Register object, Register scratch) {
Check(not_equal, AbortReason::kOperandIsASmiAndNotAFunction); Check(not_equal, AbortReason::kOperandIsASmiAndNotAFunction);
Push(object); Push(object);
LoadMap(object, object); LoadMap(object, object);
CmpInstanceTypeRange(object, scratch, FIRST_JS_FUNCTION_TYPE, CmpInstanceTypeRange(object, scratch, scratch, FIRST_JS_FUNCTION_TYPE,
LAST_JS_FUNCTION_TYPE); LAST_JS_FUNCTION_TYPE);
Pop(object); Pop(object);
Check(below_equal, AbortReason::kOperandIsNotAFunction); Check(below_equal, AbortReason::kOperandIsNotAFunction);
......
...@@ -435,7 +435,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -435,7 +435,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
} }
// Checks if value is in range [lower_limit, higher_limit] using a single // Checks if value is in range [lower_limit, higher_limit] using a single
// comparison. // comparison. Flags CF=1 or ZF=1 indicate the value is in the range
// (condition below_equal). It is valid, that |value| == |scratch| as far as
// this function is concerned.
void CompareRange(Register value, unsigned lower_limit, unsigned higher_limit,
Register scratch);
void JumpIfIsInRange(Register value, unsigned lower_limit, void JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Register scratch, unsigned higher_limit, Register scratch,
Label* on_in_range, Label* on_in_range,
...@@ -519,8 +523,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -519,8 +523,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
// //
// Always use unsigned comparisons: below_equal for a positive // Always use unsigned comparisons: below_equal for a positive
// result. // result.
void CmpInstanceTypeRange(Register map, Register scratch, void CmpInstanceTypeRange(Register map, Register instance_type_out,
InstanceType lower_limit, Register scratch, InstanceType lower_limit,
InstanceType higher_limit); InstanceType higher_limit);
// Smi tagging support. // Smi tagging support.
......
...@@ -1676,15 +1676,22 @@ void MacroAssembler::Cmp(Operand dst, Handle<Object> source) { ...@@ -1676,15 +1676,22 @@ void MacroAssembler::Cmp(Operand dst, Handle<Object> source) {
} }
} }
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit, void MacroAssembler::CompareRange(Register value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range, unsigned higher_limit) {
Label::Distance near_jump) { ASM_CODE_COMMENT(this);
DCHECK_LT(lower_limit, higher_limit);
if (lower_limit != 0) { if (lower_limit != 0) {
leal(kScratchRegister, Operand(value, 0u - lower_limit)); leal(kScratchRegister, Operand(value, 0u - lower_limit));
cmpl(kScratchRegister, Immediate(higher_limit - lower_limit)); cmpl(kScratchRegister, Immediate(higher_limit - lower_limit));
} else { } else {
cmpl(value, Immediate(higher_limit)); cmpl(value, Immediate(higher_limit));
} }
}
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range,
Label::Distance near_jump) {
CompareRange(value, lower_limit, higher_limit);
j(below_equal, on_in_range, near_jump); j(below_equal, on_in_range, near_jump);
} }
...@@ -2331,12 +2338,12 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { ...@@ -2331,12 +2338,12 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
} }
void MacroAssembler::CmpInstanceTypeRange(Register map, void MacroAssembler::CmpInstanceTypeRange(Register map,
Register instance_type_out,
InstanceType lower_limit, InstanceType lower_limit,
InstanceType higher_limit) { InstanceType higher_limit) {
DCHECK_LT(lower_limit, higher_limit); DCHECK_LT(lower_limit, higher_limit);
movzxwl(kScratchRegister, FieldOperand(map, Map::kInstanceTypeOffset)); movzxwl(instance_type_out, FieldOperand(map, Map::kInstanceTypeOffset));
leal(kScratchRegister, Operand(kScratchRegister, 0u - lower_limit)); CompareRange(instance_type_out, lower_limit, higher_limit);
cmpl(kScratchRegister, Immediate(higher_limit - lower_limit));
} }
void TurboAssembler::AssertNotSmi(Register object) { void TurboAssembler::AssertNotSmi(Register object) {
...@@ -2401,7 +2408,8 @@ void MacroAssembler::AssertFunction(Register object) { ...@@ -2401,7 +2408,8 @@ void MacroAssembler::AssertFunction(Register object) {
Check(not_equal, AbortReason::kOperandIsASmiAndNotAFunction); Check(not_equal, AbortReason::kOperandIsASmiAndNotAFunction);
Push(object); Push(object);
LoadMap(object, object); LoadMap(object, object);
CmpInstanceTypeRange(object, FIRST_JS_FUNCTION_TYPE, LAST_JS_FUNCTION_TYPE); CmpInstanceTypeRange(object, object, FIRST_JS_FUNCTION_TYPE,
LAST_JS_FUNCTION_TYPE);
Pop(object); Pop(object);
Check(below_equal, AbortReason::kOperandIsNotAFunction); Check(below_equal, AbortReason::kOperandIsNotAFunction);
} }
......
...@@ -750,7 +750,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -750,7 +750,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
void Cmp(Operand dst, Handle<Object> source); void Cmp(Operand dst, Handle<Object> source);
// Checks if value is in range [lower_limit, higher_limit] using a single // Checks if value is in range [lower_limit, higher_limit] using a single
// comparison. // comparison. Flags CF=1 or ZF=1 indicate the value is in the range
// (condition below_equal).
void CompareRange(Register value, unsigned lower_limit,
unsigned higher_limit);
void JumpIfIsInRange(Register value, unsigned lower_limit, void JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit, Label* on_in_range, unsigned higher_limit, Label* on_in_range,
Label::Distance near_jump = Label::kFar); Label::Distance near_jump = Label::kFar);
...@@ -784,7 +787,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -784,7 +787,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
// Compare instance type ranges for a map (low and high inclusive) // Compare instance type ranges for a map (low and high inclusive)
// Always use unsigned comparisons: below_equal for a positive result. // Always use unsigned comparisons: below_equal for a positive result.
void CmpInstanceTypeRange(Register map, InstanceType low, InstanceType high); void CmpInstanceTypeRange(Register map, Register instance_type_out,
InstanceType low, InstanceType high);
template <typename Field> template <typename Field>
void DecodeField(Register reg) { void DecodeField(Register reg) {
......
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