Commit c249bf6f authored by Liu Yu's avatar Liu Yu Committed by V8 LUCI CQ

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

Port commit b9a6301e

Change-Id: Ibc45a348fc5cca937a0663f8950877ee54cf5eb3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3239380
Auto-Submit: Liu yu <liuyu@loongson.cn>
Reviewed-by: 's avatarZhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Commit-Queue: Zhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Cr-Commit-Position: refs/heads/main@{#77612}
parent 37cda58d
......@@ -2456,35 +2456,49 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- a1 : the target to call (can be any Object).
// -----------------------------------
Register argc = a0;
Register target = a1;
Register map = t1;
Register instance_type = t2;
Register scratch = t8;
DCHECK(!AreAliased(argc, target, map, instance_type, scratch));
Label non_callable, class_constructor;
__ JumpIfSmi(a1, &non_callable);
__ LoadMap(t1, a1);
__ GetInstanceTypeRange(t1, t2, FIRST_CALLABLE_JS_FUNCTION_TYPE, t8);
__ JumpIfSmi(target, &non_callable);
__ LoadMap(map, target);
__ GetInstanceTypeRange(map, instance_type, FIRST_CALLABLE_JS_FUNCTION_TYPE,
scratch);
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, ls, t8,
RelocInfo::CODE_TARGET, ls, scratch,
Operand(LAST_CALLABLE_JS_FUNCTION_TYPE -
FIRST_CALLABLE_JS_FUNCTION_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
RelocInfo::CODE_TARGET, eq, instance_type,
Operand(JS_BOUND_FUNCTION_TYPE));
// Check if target has a [[Call]] internal method.
__ Ld_bu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t1, t1, Operand(Map::Bits1::IsCallableBit::kMask));
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
{
Register flags = t1;
__ Ld_bu(flags, FieldMemOperand(map, Map::kBitFieldOffset));
map = no_reg;
__ And(flags, flags, Operand(Map::Bits1::IsCallableBit::kMask));
__ Branch(&non_callable, eq, flags, Operand(zero_reg));
}
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq,
t2, Operand(JS_PROXY_TYPE));
instance_type, Operand(JS_PROXY_TYPE));
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
// Check that the function is not a "classConstructor".
__ Branch(&class_constructor, eq, t2, Operand(JS_CLASS_CONSTRUCTOR_TYPE));
__ Branch(&class_constructor, eq, instance_type,
Operand(JS_CLASS_CONSTRUCTOR_TYPE));
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
// Overwrite the original receiver with the (original) target.
__ StoreReceiver(a1, a0, kScratchReg);
__ StoreReceiver(target, argc, kScratchReg);
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(a1, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ LoadNativeContextSlot(target, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
......@@ -2493,7 +2507,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&non_callable);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
__ Push(target);
__ CallRuntime(Runtime::kThrowCalledNonCallable);
}
......@@ -2501,7 +2515,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&class_constructor);
{
FrameScope frame(masm, StackFrame::INTERNAL);
__ Push(a1);
__ Push(target);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError);
}
}
......@@ -2620,29 +2634,40 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -----------------------------------
Register argc = a0;
Register target = a1;
Register map = t1;
Register instance_type = t2;
Register scratch = t8;
DCHECK(!AreAliased(argc, target, map, instance_type, scratch));
// Check if target is a Smi.
Label non_constructor, non_proxy;
__ JumpIfSmi(a1, &non_constructor);
__ JumpIfSmi(target, &non_constructor);
// Check if target has a [[Construct]] internal method.
__ Ld_d(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ Ld_bu(t3, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t3, t3, Operand(Map::Bits1::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, t3, Operand(zero_reg));
__ Ld_d(map, FieldMemOperand(target, HeapObject::kMapOffset));
{
Register flags = t3;
__ Ld_bu(flags, FieldMemOperand(map, Map::kBitFieldOffset));
__ And(flags, flags, Operand(Map::Bits1::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, flags, Operand(zero_reg));
}
// Dispatch based on instance type.
__ GetInstanceTypeRange(t1, t2, FIRST_JS_FUNCTION_TYPE, t8);
__ GetInstanceTypeRange(map, instance_type, FIRST_JS_FUNCTION_TYPE, scratch);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, ls, t8,
RelocInfo::CODE_TARGET, ls, scratch,
Operand(LAST_JS_FUNCTION_TYPE - FIRST_JS_FUNCTION_TYPE));
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
RelocInfo::CODE_TARGET, eq, instance_type,
Operand(JS_BOUND_FUNCTION_TYPE));
// Only dispatch to proxies after checking whether they are constructors.
__ Branch(&non_proxy, ne, t2, Operand(JS_PROXY_TYPE));
__ Branch(&non_proxy, ne, instance_type, Operand(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy),
RelocInfo::CODE_TARGET);
......@@ -2650,9 +2675,10 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ bind(&non_proxy);
{
// Overwrite the original receiver with the (original) target.
__ StoreReceiver(a1, a0, kScratchReg);
__ StoreReceiver(target, argc, kScratchReg);
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(a1, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ LoadNativeContextSlot(target,
Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET);
}
......
......@@ -2399,36 +2399,50 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- a1 : the target to call (can be any Object).
// -----------------------------------
Register argc = a0;
Register target = a1;
Register map = t1;
Register instance_type = t2;
Register scratch = t8;
DCHECK(!AreAliased(argc, target, map, instance_type, scratch));
Label non_callable, class_constructor;
__ JumpIfSmi(a1, &non_callable);
__ LoadMap(t1, a1);
__ GetInstanceTypeRange(t1, t2, FIRST_CALLABLE_JS_FUNCTION_TYPE, t8);
__ JumpIfSmi(target, &non_callable);
__ LoadMap(map, target);
__ GetInstanceTypeRange(map, instance_type, FIRST_CALLABLE_JS_FUNCTION_TYPE,
scratch);
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, ls, t8,
RelocInfo::CODE_TARGET, ls, scratch,
Operand(LAST_CALLABLE_JS_FUNCTION_TYPE -
FIRST_CALLABLE_JS_FUNCTION_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
RelocInfo::CODE_TARGET, eq, instance_type,
Operand(JS_BOUND_FUNCTION_TYPE));
// Check if target has a [[Call]] internal method.
__ lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t1, t1, Operand(Map::Bits1::IsCallableBit::kMask));
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
{
Register flags = t1;
__ lbu(flags, FieldMemOperand(map, Map::kBitFieldOffset));
map = no_reg;
__ And(flags, flags, Operand(Map::Bits1::IsCallableBit::kMask));
__ Branch(&non_callable, eq, flags, Operand(zero_reg));
}
// Check if target is a proxy and call CallProxy external builtin
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq,
instance_type, Operand(JS_PROXY_TYPE));
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
// Check that the function is not a "classConstructor".
__ Branch(&class_constructor, eq, t2, Operand(JS_CLASS_CONSTRUCTOR_TYPE));
__ Branch(&class_constructor, eq, instance_type,
Operand(JS_CLASS_CONSTRUCTOR_TYPE));
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
// Overwrite the original receiver with the (original) target.
__ StoreReceiver(a1, a0, kScratchReg);
__ StoreReceiver(target, argc, kScratchReg);
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(a1, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ LoadNativeContextSlot(target, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
......@@ -2437,7 +2451,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&non_callable);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
__ Push(target);
__ CallRuntime(Runtime::kThrowCalledNonCallable);
}
......@@ -2445,7 +2459,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&class_constructor);
{
FrameScope frame(masm, StackFrame::INTERNAL);
__ Push(a1);
__ Push(target);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError);
}
}
......@@ -2564,29 +2578,40 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -----------------------------------
Register argc = a0;
Register target = a1;
Register map = t1;
Register instance_type = t2;
Register scratch = t8;
DCHECK(!AreAliased(argc, target, map, instance_type, scratch));
// Check if target is a Smi.
Label non_constructor, non_proxy;
__ JumpIfSmi(a1, &non_constructor);
__ JumpIfSmi(target, &non_constructor);
// Check if target has a [[Construct]] internal method.
__ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lbu(t3, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t3, t3, Operand(Map::Bits1::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, t3, Operand(zero_reg));
__ lw(map, FieldMemOperand(target, HeapObject::kMapOffset));
{
Register flags = t3;
__ lbu(flags, FieldMemOperand(map, Map::kBitFieldOffset));
__ And(flags, flags, Operand(Map::Bits1::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, flags, Operand(zero_reg));
}
// Dispatch based on instance type.
__ GetInstanceTypeRange(t1, t2, FIRST_JS_FUNCTION_TYPE, t8);
__ GetInstanceTypeRange(map, instance_type, FIRST_JS_FUNCTION_TYPE, scratch);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, ls, t8,
RelocInfo::CODE_TARGET, ls, scratch,
Operand(LAST_JS_FUNCTION_TYPE - FIRST_JS_FUNCTION_TYPE));
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
RelocInfo::CODE_TARGET, eq, instance_type,
Operand(JS_BOUND_FUNCTION_TYPE));
// Only dispatch to proxies after checking whether they are constructors.
__ Branch(&non_proxy, ne, t2, Operand(JS_PROXY_TYPE));
__ Branch(&non_proxy, ne, instance_type, Operand(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy),
RelocInfo::CODE_TARGET);
......@@ -2594,9 +2619,10 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ bind(&non_proxy);
{
// Overwrite the original receiver with the (original) target.
__ StoreReceiver(a1, a0, kScratchReg);
__ StoreReceiver(target, argc, kScratchReg);
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(a1, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ LoadNativeContextSlot(target,
Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(),
RelocInfo::CODE_TARGET);
}
......
......@@ -2451,36 +2451,49 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- a0 : the number of arguments
// -- a1 : the target to call (can be any Object).
// -----------------------------------
Register argc = a0;
Register target = a1;
Register map = t1;
Register instance_type = t2;
Register scratch = t8;
DCHECK(!AreAliased(argc, target, map, instance_type, scratch));
Label non_callable, class_constructor;
__ JumpIfSmi(a1, &non_callable);
__ LoadMap(t1, a1);
__ GetInstanceTypeRange(t1, t2, FIRST_CALLABLE_JS_FUNCTION_TYPE, t8);
__ JumpIfSmi(target, &non_callable);
__ LoadMap(map, target);
__ GetInstanceTypeRange(map, instance_type, FIRST_CALLABLE_JS_FUNCTION_TYPE,
scratch);
__ Jump(masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET, ls, t8,
RelocInfo::CODE_TARGET, ls, scratch,
Operand(LAST_CALLABLE_JS_FUNCTION_TYPE -
FIRST_CALLABLE_JS_FUNCTION_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallBoundFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
RelocInfo::CODE_TARGET, eq, instance_type,
Operand(JS_BOUND_FUNCTION_TYPE));
// Check if target has a [[Call]] internal method.
__ Lbu(t1, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t1, t1, Operand(Map::Bits1::IsCallableBit::kMask));
__ Branch(&non_callable, eq, t1, Operand(zero_reg));
{
Register flags = t1;
__ Lbu(flags, FieldMemOperand(map, Map::kBitFieldOffset));
map = no_reg;
__ And(flags, flags, Operand(Map::Bits1::IsCallableBit::kMask));
__ Branch(&non_callable, eq, flags, Operand(zero_reg));
}
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET, eq,
instance_type, Operand(JS_PROXY_TYPE));
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
// Check that the function is not a "classConstructor".
__ Branch(&class_constructor, eq, t2, Operand(JS_CLASS_CONSTRUCTOR_TYPE));
__ Branch(&class_constructor, eq, instance_type,
Operand(JS_CLASS_CONSTRUCTOR_TYPE));
// 2. Call to something else, which might have a [[Call]] internal method (if
// not we raise an exception).
// Overwrite the original receiver with the (original) target.
__ StoreReceiver(a1, a0, kScratchReg);
__ StoreReceiver(target, argc, kScratchReg);
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(a1, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ LoadNativeContextSlot(target, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(
ConvertReceiverMode::kNotNullOrUndefined),
RelocInfo::CODE_TARGET);
......@@ -2489,7 +2502,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&non_callable);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1);
__ Push(target);
__ CallRuntime(Runtime::kThrowCalledNonCallable);
}
......@@ -2497,7 +2510,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
__ bind(&class_constructor);
{
FrameScope frame(masm, StackFrame::INTERNAL);
__ Push(a1);
__ Push(target);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError);
}
}
......@@ -2615,29 +2628,40 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -----------------------------------
Register argc = a0;
Register target = a1;
Register map = t1;
Register instance_type = t2;
Register scratch = t8;
DCHECK(!AreAliased(argc, target, map, instance_type, scratch));
// Check if target is a Smi.
Label non_constructor, non_proxy;
__ JumpIfSmi(a1, &non_constructor);
__ JumpIfSmi(target, &non_constructor);
// Check if target has a [[Construct]] internal method.
__ ld(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
__ Lbu(t3, FieldMemOperand(t1, Map::kBitFieldOffset));
__ And(t3, t3, Operand(Map::Bits1::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, t3, Operand(zero_reg));
__ ld(map, FieldMemOperand(target, HeapObject::kMapOffset));
{
Register flags = t3;
__ Lbu(flags, FieldMemOperand(map, Map::kBitFieldOffset));
__ And(flags, flags, Operand(Map::Bits1::IsConstructorBit::kMask));
__ Branch(&non_constructor, eq, flags, Operand(zero_reg));
}
// Dispatch based on instance type.
__ GetInstanceTypeRange(t1, t2, FIRST_JS_FUNCTION_TYPE, t8);
__ GetInstanceTypeRange(map, instance_type, FIRST_JS_FUNCTION_TYPE, scratch);
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructFunction),
RelocInfo::CODE_TARGET, ls, t8,
RelocInfo::CODE_TARGET, ls, scratch,
Operand(LAST_JS_FUNCTION_TYPE - FIRST_JS_FUNCTION_TYPE));
// Only dispatch to bound functions after checking whether they are
// constructors.
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructBoundFunction),
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_BOUND_FUNCTION_TYPE));
RelocInfo::CODE_TARGET, eq, instance_type,
Operand(JS_BOUND_FUNCTION_TYPE));
// Only dispatch to proxies after checking whether they are constructors.
__ Branch(&non_proxy, ne, t2, Operand(JS_PROXY_TYPE));
__ Branch(&non_proxy, ne, instance_type, Operand(JS_PROXY_TYPE));
__ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy),
RelocInfo::CODE_TARGET);
......@@ -2645,9 +2669,10 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ bind(&non_proxy);
{
// Overwrite the original receiver with the (original) target.
__ StoreReceiver(a1, a0, kScratchReg);
__ StoreReceiver(target, argc, kScratchReg);
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(a1, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ LoadNativeContextSlot(target,
Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ 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