mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-26 19:50:55 +00:00
!9510 add asmbirdge for AsmInterpreterEntry to call IR
Merge pull request !9510 from wpy111/master
This commit is contained in:
commit
afe027a27d
@ -1826,21 +1826,26 @@ void AsmInterpreterCall::CallBCStub(ExtendedAssembler *assembler, Register &newS
|
||||
|
||||
void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
|
||||
{
|
||||
Label callFastBuiltin;
|
||||
Label callNativeBuiltin;
|
||||
Register glue(X0);
|
||||
Register argv(X5);
|
||||
Register method(X2);
|
||||
Register function(X1);
|
||||
Register nativeCode(X7);
|
||||
Register temp(X9);
|
||||
Register callFieldRegister(X3);
|
||||
// get native pointer
|
||||
__ Ldr(nativeCode, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
|
||||
__ Tbnz(callFieldRegister, MethodLiteral::IsFastBuiltinBit::START_BIT, &callFastBuiltin);
|
||||
|
||||
__ Bind(&callNativeBuiltin);
|
||||
Register sp(SP);
|
||||
// 2: function & align
|
||||
__ Stp(function, Register(Zero), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
|
||||
// 2: skip argc & thread
|
||||
__ Sub(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
|
||||
PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_ENTRY_FRAME, temp, argv);
|
||||
// get native pointer
|
||||
__ Ldr(nativeCode, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
|
||||
__ Mov(temp, argv);
|
||||
__ Sub(Register(X0), temp, Immediate(2 * FRAME_SLOT_SIZE)); // 2: skip argc & thread
|
||||
CallNativeInternal(assembler, nativeCode);
|
||||
@ -1848,6 +1853,91 @@ void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
|
||||
// 4: skip function
|
||||
__ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&callFastBuiltin);
|
||||
CallFastBuiltin(assembler, &callNativeBuiltin);
|
||||
}
|
||||
|
||||
void AsmInterpreterCall::CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin)
|
||||
{
|
||||
Label lCall1;
|
||||
Label lCall2;
|
||||
Label lCall3;
|
||||
Label callEntry;
|
||||
Register sp(SP);
|
||||
Register glue(X0);
|
||||
Register function(X1);
|
||||
Register method(X2);
|
||||
Register argc(X4);
|
||||
Register argv(X5);
|
||||
Register nativeCode(X7);
|
||||
|
||||
Register builtinId = __ AvailableRegister1();
|
||||
Register temp = __ AvailableRegister2();
|
||||
// get builtinid
|
||||
__ Ldr(builtinId, MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET)); // get extra literal
|
||||
__ And(builtinId.W(), builtinId.W(), LogicalImmediate::Create(0xff, RegWSize));
|
||||
__ Cmp(builtinId.W(), Immediate(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST));
|
||||
__ B(Condition::GE, callNativeBuiltin);
|
||||
|
||||
__ Cmp(argc, Immediate(3)); // 3: number of args
|
||||
__ B(Condition::HI, callNativeBuiltin);
|
||||
|
||||
// get builtin func addr
|
||||
__ Add(builtinId, glue, Operand(builtinId.W(), UXTW, FRAME_SLOT_SIZE_LOG2));
|
||||
__ Ldr(builtinId, MemoryOperand(builtinId, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
|
||||
// create frame
|
||||
PushAsmBridgeFrame(assembler);
|
||||
__ Mov(temp, function);
|
||||
__ Mov(X1, nativeCode);
|
||||
__ Mov(X2, temp);
|
||||
__ Mov(temp, argv);
|
||||
__ Mov(X5, argc);
|
||||
__ Ldr(X3, MemoryOperand(temp, FRAME_SLOT_SIZE));
|
||||
__ Ldr(X4, MemoryOperand(temp, DOUBLE_SLOT_SIZE));
|
||||
|
||||
__ Cmp(Register(X5), Immediate(0));
|
||||
__ B(Condition::NE, &lCall1);
|
||||
__ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
|
||||
__ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
|
||||
__ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
|
||||
__ B(&callEntry);
|
||||
|
||||
__ Bind(&lCall1);
|
||||
{
|
||||
__ Cmp(Register(X5), Immediate(1));
|
||||
__ B(Condition::NE, &lCall2);
|
||||
__ Ldr(Register(X6), MemoryOperand(temp, TRIPLE_SLOT_SIZE));
|
||||
__ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); // reset x7
|
||||
__ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
|
||||
__ B(&callEntry);
|
||||
}
|
||||
|
||||
__ Bind(&lCall2);
|
||||
{
|
||||
__ Cmp(Register(X5), Immediate(2)); // 2: number of args
|
||||
__ B(Condition::NE, &lCall3);
|
||||
__ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
|
||||
__ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
|
||||
__ Ldp(Register(X6), Register(X7), MemoryOperand(temp, TRIPLE_SLOT_SIZE));
|
||||
__ B(&callEntry);
|
||||
}
|
||||
|
||||
__ Bind(&lCall3);
|
||||
{
|
||||
__ Ldr(Register(X7), MemoryOperand(temp, QUINTUPLE_SLOT_SIZE));
|
||||
__ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
|
||||
__ Ldp(Register(X6), Register(X7), MemoryOperand(temp, TRIPLE_SLOT_SIZE)); // get arg0 arg1
|
||||
__ B(&callEntry);
|
||||
}
|
||||
|
||||
__ Bind(&callEntry);
|
||||
{
|
||||
__ Blr(builtinId);
|
||||
__ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
|
||||
}
|
||||
PopAsmBridgeFrame(assembler);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue,
|
||||
|
@ -187,5 +187,28 @@ void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue,
|
||||
__ Cbz(op, stackOverflow);
|
||||
__ Bind(&skipThrow);
|
||||
}
|
||||
|
||||
void CommonCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
Register sp(SP);
|
||||
TempRegister2Scope temp2Scope(assembler);
|
||||
Register frameType = __ TempRegister2();
|
||||
__ PushFpAndLr();
|
||||
// construct frame
|
||||
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
|
||||
// 2 : 2 means pairs. X19 means calleesave and 16bytes align
|
||||
__ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
|
||||
__ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
|
||||
}
|
||||
|
||||
void CommonCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
TempRegister2Scope temp2Scope(assembler);
|
||||
Register sp(SP);
|
||||
Register frameType = __ TempRegister2();
|
||||
// 2 : 2 means pop call site sp and type
|
||||
__ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
|
||||
__ RestoreFpAndLr();
|
||||
}
|
||||
#undef __
|
||||
} // panda::ecmascript::aarch64
|
@ -73,6 +73,8 @@ public:
|
||||
Register op, Label *stackOverflow);
|
||||
static void PushLeaveFrame(ExtendedAssembler *assembler, Register glue);
|
||||
static void PopLeaveFrame(ExtendedAssembler *assembler);
|
||||
static void PushAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
static void PopAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
};
|
||||
|
||||
class OptimizedCall : public CommonCall {
|
||||
@ -127,8 +129,6 @@ private:
|
||||
int64_t numExtraArgs = 0);
|
||||
static void PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler);
|
||||
static void PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler);
|
||||
static void PushAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
static void PopAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
static void JSCallInternal(ExtendedAssembler *assembler, Register jsfunc, bool isNew = false);
|
||||
static void CallBuiltinTrampoline(ExtendedAssembler *assembler);
|
||||
static void CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv,
|
||||
@ -268,6 +268,8 @@ private:
|
||||
|
||||
static void CallNativeEntry(ExtendedAssembler *assembler);
|
||||
|
||||
static void CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin);
|
||||
|
||||
static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false);
|
||||
static void PreserveMostCall(ExtendedAssembler* assembler);
|
||||
friend class OptimizedCall;
|
||||
|
@ -1174,29 +1174,6 @@ void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
|
||||
__ RestoreFpAndLr();
|
||||
}
|
||||
|
||||
void OptimizedCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
Register sp(SP);
|
||||
TempRegister2Scope temp2Scope(assembler);
|
||||
Register frameType = __ TempRegister2();
|
||||
__ PushFpAndLr();
|
||||
// construct frame
|
||||
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
|
||||
// 2 : 2 means pairs. X19 means calleesave and 16bytes align
|
||||
__ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
|
||||
__ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
|
||||
}
|
||||
|
||||
void OptimizedCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
TempRegister2Scope temp2Scope(assembler);
|
||||
Register sp(SP);
|
||||
Register frameType = __ TempRegister2();
|
||||
// 2 : 2 means pop call site sp and type
|
||||
__ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
|
||||
__ RestoreFpAndLr();
|
||||
}
|
||||
|
||||
// * uint64_t PushOptimizedUnfoldArgVFrame(uintptr_t glue, uint32_t argc, JSTaggedType calltarget,
|
||||
// JSTaggedType new, JSTaggedType this, JSTaggedType argV[])
|
||||
// * cc calling convention call js function()
|
||||
|
@ -929,18 +929,24 @@ void AsmInterpreterCall::CallNativeWithArgv(ExtendedAssembler *assembler, bool c
|
||||
|
||||
void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
|
||||
{
|
||||
Label callFastBuiltin;
|
||||
Label callNativeBuiltin;
|
||||
Register glue = rdi;
|
||||
Register argv = r9;
|
||||
Register method = rdx;
|
||||
Register function = rsi;
|
||||
Register nativeCode = r10;
|
||||
Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
|
||||
__ Movq(Operand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), nativeCode); // get native pointer
|
||||
__ Btq(MethodLiteral::IsFastBuiltinBit::START_BIT, callFieldRegister);
|
||||
__ Jb(&callFastBuiltin);
|
||||
|
||||
__ Bind(&callNativeBuiltin);
|
||||
__ PushAlignBytes();
|
||||
__ Push(function);
|
||||
// 3: 24 means skip thread & argc & returnAddr
|
||||
__ Subq(3 * FRAME_SLOT_SIZE, rsp);
|
||||
PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_ENTRY_FRAME);
|
||||
__ Movq(Operand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET), nativeCode); // get native pointer
|
||||
__ Movq(argv, r11);
|
||||
// 2: 16 means skip numArgs & thread
|
||||
__ Subq(2 * FRAME_SLOT_SIZE, r11);
|
||||
@ -952,6 +958,93 @@ void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler)
|
||||
// 5: 40 means skip function
|
||||
__ Addq(5 * FRAME_SLOT_SIZE, rsp);
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&callFastBuiltin);
|
||||
CallFastBuiltin(assembler, &callNativeBuiltin);
|
||||
}
|
||||
|
||||
void AsmInterpreterCall::CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin)
|
||||
{
|
||||
Label arg1;
|
||||
Label arg2;
|
||||
Label arg3;
|
||||
Label callEntry;
|
||||
Register glue = rdi;
|
||||
Register argc = r8;
|
||||
Register argv = r9;
|
||||
Register method = rdx;
|
||||
Register function = rsi;
|
||||
Register nativeCode = r10;
|
||||
Register temp = rax;
|
||||
Register temp1 = r11;
|
||||
// get builtins id
|
||||
__ Movq(Operand(method, Method::EXTRA_LITERAL_INFO_OFFSET), temp1);
|
||||
__ Shr(MethodLiteral::BuiltinIdBits::START_BIT, temp1);
|
||||
__ Andl((1LU << MethodLiteral::BuiltinIdBits::SIZE) - 1, temp1);
|
||||
|
||||
__ Cmpl(static_cast<int32_t>(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST), temp1);
|
||||
__ Jge(callNativeBuiltin);
|
||||
|
||||
__ Cmpq(Immediate(3), argc); // 3: number of args
|
||||
__ Jg(callNativeBuiltin);
|
||||
|
||||
// create frame
|
||||
PushAsmBridgeFrame(assembler);
|
||||
|
||||
// register args
|
||||
__ Movq(function, temp);
|
||||
__ Movq(nativeCode, rsi); // nativeCode is rsi
|
||||
__ Movq(temp, rdx); // fun is rdx
|
||||
__ Movq(argv, temp); // temp is argv
|
||||
__ Movq(argc, r9); // argc is r9
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE), rcx); // get new target
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE * 2), r8); // 2: skip func & new target to get this target
|
||||
|
||||
__ Cmp(Immediate(0), r9);
|
||||
__ Jne(&arg1);
|
||||
__ Pushq(JSTaggedValue::VALUE_UNDEFINED);
|
||||
__ Pushq(JSTaggedValue::VALUE_UNDEFINED);
|
||||
__ Pushq(JSTaggedValue::VALUE_UNDEFINED);
|
||||
__ Jmp(&callEntry);
|
||||
__ Bind(&arg1);
|
||||
{
|
||||
__ Cmp(Immediate(1), r9);
|
||||
__ Jne(&arg2);
|
||||
__ Pushq(JSTaggedValue::VALUE_UNDEFINED);
|
||||
__ Pushq(JSTaggedValue::VALUE_UNDEFINED);
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE * 3), r10); // 3: get arg0
|
||||
__ Pushq(r10);
|
||||
__ Jmp(&callEntry);
|
||||
}
|
||||
__ Bind(&arg2);
|
||||
{
|
||||
__ Cmp(Immediate(2), r9); // 2: number of args
|
||||
__ Jne(&arg3);
|
||||
__ Pushq(JSTaggedValue::VALUE_UNDEFINED);
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE * 4), r10); // 4: get arg1
|
||||
__ Pushq(r10);
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE * 3), r10); // 3: get arg0
|
||||
__ Pushq(r10);
|
||||
__ Jmp(&callEntry);
|
||||
}
|
||||
__ Bind(&arg3);
|
||||
{
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE * 5), r10); // 5: get arg2
|
||||
__ Pushq(r10);
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE * 4), r10); // 4: get arg1
|
||||
__ Pushq(r10);
|
||||
__ Movq(Operand(temp, FRAME_SLOT_SIZE * 3), r10); // 3: get arg0
|
||||
__ Pushq(r10);
|
||||
__ Jmp(&callEntry);
|
||||
}
|
||||
__ Bind(&callEntry);
|
||||
{
|
||||
__ Movq(Operand(glue, temp1, Times8, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)), temp1);
|
||||
__ Callq(temp1);
|
||||
__ Addq(QUADRUPLE_SLOT_SIZE, rsp);
|
||||
__ Pop(rbp);
|
||||
__ Ret();
|
||||
}
|
||||
}
|
||||
|
||||
// uint64_t PushCallArgsAndDispatchNative(uintptr_t codeAddress, uintptr_t glue, uint32_t argc, ...)
|
||||
|
@ -122,5 +122,18 @@ void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue,
|
||||
}
|
||||
__ Jle(stackOverflow);
|
||||
}
|
||||
|
||||
void CommonCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
__ Pushq(rbp);
|
||||
__ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
|
||||
__ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
|
||||
}
|
||||
|
||||
void CommonCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
__ Addq(FRAME_SLOT_SIZE, rsp); // skip type
|
||||
__ Popq(rbp);
|
||||
}
|
||||
#undef __
|
||||
} // namespace panda::ecmascript::x64
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
Register op1, Register op2, Label *stackOverflow);
|
||||
static void StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1,
|
||||
Register op2, Label *stackOverflow);
|
||||
static void PushAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
static void PopAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
};
|
||||
|
||||
class OptimizedCall : public CommonCall {
|
||||
@ -97,9 +99,7 @@ private:
|
||||
static void PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue);
|
||||
static void PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp);
|
||||
static void PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler);
|
||||
static void PushAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
static void CallBuiltinTrampoline(ExtendedAssembler *assembler, Register temp);
|
||||
static void PopAsmBridgeFrame(ExtendedAssembler *assembler);
|
||||
static void CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv,
|
||||
Register glue, Register temp);
|
||||
static void RemoveArgv(ExtendedAssembler *assembler, Register temp);
|
||||
@ -212,7 +212,8 @@ private:
|
||||
static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow, FrameTransitionType type);
|
||||
static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister,
|
||||
Register callTargetRegister, Register methodRegister, Register accRegister = rInvalid);
|
||||
static void CallNativeEntry(ExtendedAssembler *assemblSer);
|
||||
static void CallNativeEntry(ExtendedAssembler *assembler);
|
||||
static void CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin);
|
||||
static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false);
|
||||
static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode);
|
||||
static bool PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type);
|
||||
|
@ -822,19 +822,6 @@ void OptimizedCall::FastCallToAsmInterBridge(ExtendedAssembler *assembler)
|
||||
assembler, JSCallMode::CALL_FROM_AOT, FrameTransitionType::OTHER_TO_OTHER);
|
||||
}
|
||||
|
||||
void OptimizedCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
__ Pushq(rbp);
|
||||
__ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
|
||||
__ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
|
||||
}
|
||||
|
||||
void OptimizedCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
|
||||
{
|
||||
__ Addq(FRAME_SLOT_SIZE, rsp); // skip type
|
||||
__ Popq(rbp);
|
||||
}
|
||||
|
||||
void OptimizedCall::JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg,
|
||||
Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall)
|
||||
{
|
||||
|
@ -132,3 +132,12 @@ prototypeCallTest.call(0, 1);
|
||||
prototypeCallTest.call(0, 1, 2);
|
||||
prototypeCallTest.call(0, 1, 2, 3);
|
||||
prototypeCallTest.call(0, 1, 2, 3, 4);
|
||||
|
||||
var x = [];
|
||||
x[new Number(0)] = 0;
|
||||
print(x[0]);
|
||||
|
||||
const reg = /bar/;
|
||||
|
||||
reg[Symbol.match] = false;
|
||||
print('/bar/'.startsWith(reg));
|
||||
|
@ -35,3 +35,5 @@ undefined
|
||||
1,2,3
|
||||
0
|
||||
1,2,3,4
|
||||
0
|
||||
true
|
||||
|
Loading…
Reference in New Issue
Block a user