mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
!9078 Add asm shared barrier
Merge pull request !9078 from zhouguangyuan0718/master-asm-share-barrier
This commit is contained in:
commit
02edc6ddb0
@ -1019,6 +1019,11 @@ void AssemblerAarch64::Tbnz(const Register &rt, int32_t bitPos, int32_t imm)
|
||||
EmitU32(code);
|
||||
}
|
||||
|
||||
void AssemblerAarch64::Tst(const Register& rn, const Operand& operand)
|
||||
{
|
||||
Ands(Register(Zero, rn.GetType()), rn, operand);
|
||||
}
|
||||
|
||||
void AssemblerAarch64::Tst(const Register &rn, const LogicalImmediate &imm)
|
||||
{
|
||||
Ands(Register(Zero, rn.GetType()), rn, imm);
|
||||
|
@ -866,6 +866,14 @@ void AssemblerX64::Movl(const Operand &src, Register dst)
|
||||
EmitOperand(dst, src);
|
||||
}
|
||||
|
||||
void AssemblerX64::Movl(Register src, const Operand& dst)
|
||||
{
|
||||
EmitRexPrefixl(src, dst);
|
||||
// 0x89: Move r32 to r/m64
|
||||
EmitU8(0x89);
|
||||
EmitOperand(src, dst);
|
||||
}
|
||||
|
||||
void AssemblerX64::Testq(Immediate src, Register dst)
|
||||
{
|
||||
if (InRange8(src.Value())) {
|
||||
@ -1011,6 +1019,16 @@ void AssemblerX64::Shrq(Immediate src, Register dst)
|
||||
EmitI8(static_cast<int8_t>(src.Value()));
|
||||
}
|
||||
|
||||
void AssemblerX64::Shrl(Immediate src, Register dst)
|
||||
{
|
||||
EmitRexPrefix(dst);
|
||||
// C1 : Shr r/m32, imm8;
|
||||
EmitU8(0xc1);
|
||||
// 5: C1 /5 id
|
||||
EmitModrm(5, dst);
|
||||
EmitI8(static_cast<int8_t>(src.Value()));
|
||||
}
|
||||
|
||||
void AssemblerX64::Shr(Immediate src, Register dst)
|
||||
{
|
||||
Shrq(src, dst);
|
||||
@ -1278,6 +1296,16 @@ void AssemblerX64::Movzbl(const Operand &src, Register dst)
|
||||
EmitOperand(dst, src);
|
||||
}
|
||||
|
||||
void AssemblerX64::Movzbl(Register src, Register dst)
|
||||
{
|
||||
EmitRexPrefixl(dst, src);
|
||||
// 0F B6 : Movzx r64, r/m16
|
||||
EmitU8(0x0F);
|
||||
EmitU8(0xB6);
|
||||
// 0F B6 /r: Movzx r64, r/m16
|
||||
EmitModrm(dst, src);
|
||||
}
|
||||
|
||||
void AssemblerX64::Btq(Immediate src, Register dst)
|
||||
{
|
||||
EmitRexPrefixW(dst);
|
||||
@ -1327,6 +1355,16 @@ void AssemblerX64::Shlq(Immediate src, Register dst)
|
||||
EmitI8(static_cast<int8_t>(src.Value()));
|
||||
}
|
||||
|
||||
void AssemblerX64::Btsl(Register src, Register dst)
|
||||
{
|
||||
EmitRexPrefixl(src, dst);
|
||||
// 0F AB: bts r32, r32;
|
||||
EmitU8(0x0F);
|
||||
EmitU8(0xAB);
|
||||
|
||||
EmitModrm(src, dst);
|
||||
}
|
||||
|
||||
void AssemblerX64::Int3()
|
||||
{
|
||||
// CC :: INT3
|
||||
|
@ -143,13 +143,17 @@ public:
|
||||
void Leal(const Operand &src, Register dst);
|
||||
void Movl(Register src, Register dst);
|
||||
void Movl(const Operand &src, Register dst);
|
||||
void Movl(Register dst, const Operand& src);
|
||||
void Movzbq(const Operand &src, Register dst);
|
||||
void Movzbl(const Operand &src, Register dst);
|
||||
void Movzbl(Register src, Register dst);
|
||||
void Movabs(uint64_t src, Register dst);
|
||||
void Shrq(Immediate src, Register dst);
|
||||
void Shrl(Immediate src, Register dst);
|
||||
void Shr(Immediate src, Register dst);
|
||||
void Shll(Immediate src, Register dst);
|
||||
void Shlq(Immediate src, Register dst);
|
||||
void Btsl(Register src, Register dst);
|
||||
void Testq(Immediate src, Register dst);
|
||||
void Testb(Immediate src, Register dst);
|
||||
void Int3();
|
||||
|
@ -840,6 +840,11 @@ DEF_CALL_SIGNATURE(ASMWriteBarrierWithEden)
|
||||
callSign->SetTargetKind(CallSignature::TargetKind::ASM_CALL_BARRIER_STUB);
|
||||
}
|
||||
|
||||
DEF_CALL_SIGNATURE(VerifyBarrier)
|
||||
{
|
||||
SETVALUEBARRIER_CALL_ARGS_SIGNATURE_COMMON(VerifyBarrier);
|
||||
}
|
||||
|
||||
#undef SETVALUEBARRIER_CALL_ARGS_SIGNATURE_COMMON
|
||||
|
||||
DEF_CALL_SIGNATURE(NewThisObjectChecked)
|
||||
|
@ -629,7 +629,8 @@ private:
|
||||
V(ConvertCharToInt32) \
|
||||
V(ConvertCharToDouble) \
|
||||
V(ASMFastWriteBarrier) \
|
||||
V(ASMWriteBarrierWithEden)
|
||||
V(ASMWriteBarrierWithEden) \
|
||||
V(VerifyBarrier)
|
||||
|
||||
#define DECL_CALL_SIGNATURE(name) \
|
||||
class name##CallSignature final { \
|
||||
|
@ -117,7 +117,8 @@ namespace panda::ecmascript::kungfu {
|
||||
V(ConvertCharToDouble) \
|
||||
V(DeleteObjectProperty) \
|
||||
V(SameValue) \
|
||||
V(StringIteratorNext)
|
||||
V(StringIteratorNext) \
|
||||
V(VerifyBarrier)
|
||||
|
||||
#define COMMON_STUB_ID_LIST(V) \
|
||||
COMMON_STUB_LIST(V)
|
||||
|
@ -889,6 +889,16 @@ void SetSValueWithBarrierStubBuilder::GenerateCircuit()
|
||||
Return();
|
||||
}
|
||||
|
||||
void VerifyBarrierStubBuilder::GenerateCircuit()
|
||||
{
|
||||
GateRef glue = PtrArgument(0);
|
||||
GateRef obj = TaggedArgument(1);
|
||||
GateRef offset = PtrArgument(2); // 2 : 3rd para
|
||||
GateRef value = TaggedArgument(3); // 3 : 4th para
|
||||
VerifyBarrier(glue, obj, offset, value);
|
||||
Return();
|
||||
}
|
||||
|
||||
void NewThisObjectCheckedStubBuilder::GenerateCircuit()
|
||||
{
|
||||
GateRef glue = PtrArgument(0);
|
||||
|
@ -750,8 +750,7 @@ public:
|
||||
bool enableLog = data->GetLog()->EnableMethodCIRLog();
|
||||
Scheduler::Run(data->GetCircuit(), data->GetCfg(), data->GetMethodName(), enableLog);
|
||||
Chunk chunk(data->GetNativeAreaAllocator());
|
||||
// disable fast barrier for stub, need fix for local2share barrier.
|
||||
PostSchedule(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk, false).Run(data->GetCfg());
|
||||
PostSchedule(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk, true).Run(data->GetCfg());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -539,6 +539,14 @@ void PostSchedule::LoweringStoreUnknownBarrierAndPrepareScheduleGate(GateRef gat
|
||||
GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, index, GateType::NJSValue());
|
||||
GateRef reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
|
||||
GateRef reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
|
||||
#ifndef NDEBUG
|
||||
GateRef verifyTarget = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, CommonStubCSigns::VerifyBarrier,
|
||||
GateType::NJSValue());
|
||||
const CallSignature* verifyBarrierCs = CommonStubCSigns::Get(CommonStubCSigns::VerifyBarrier);
|
||||
GateRef verifyBarrier = builder_.Call(verifyBarrierCs, glue, verifyTarget, builder_.GetDepend(),
|
||||
{glue, base, offset, value, reseverdFrameArgs, reseverdPc},
|
||||
Circuit::NullGate(), "verify barrier");
|
||||
#endif
|
||||
GateRef storeBarrier = builder_.Call(cs, glue, target, builder_.GetDepend(),
|
||||
{ glue, base, offset, value, reseverdFrameArgs, reseverdPc },
|
||||
Circuit::NullGate(), comment.data());
|
||||
@ -547,6 +555,9 @@ void PostSchedule::LoweringStoreUnknownBarrierAndPrepareScheduleGate(GateRef gat
|
||||
GateRef ordinaryBlock = isHeapObject.GetControl();
|
||||
PrepareToScheduleNewGate(ordinaryBlock, barrierBBGates);
|
||||
PrepareToScheduleNewGate(storeBarrier, barrierBBGates);
|
||||
#ifndef NDEBUG
|
||||
PrepareToScheduleNewGate(verifyBarrier, barrierBBGates);
|
||||
#endif
|
||||
PrepareToScheduleNewGate(reseverdFrameArgs, barrierBBGates);
|
||||
PrepareToScheduleNewGate(reseverdPc, barrierBBGates);
|
||||
PrepareToScheduleNewGate(ifTrue, barrierBBGates);
|
||||
|
@ -1786,6 +1786,28 @@ void StubBuilder::SetValueWithRep(
|
||||
return;
|
||||
}
|
||||
|
||||
void StubBuilder::VerifyBarrier(GateRef glue, GateRef obj, [[maybe_unused]] GateRef offset, GateRef value)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label entry(env);
|
||||
env->SubCfgEntry(&entry);
|
||||
Label exit(env);
|
||||
// ObjectAddressToRange function may cause obj is not an object. GC may not mark this obj.
|
||||
GateRef objectRegion = ObjectAddressToRange(obj);
|
||||
GateRef valueRegion = ObjectAddressToRange(value);
|
||||
Label fatal(env);
|
||||
Label noFatal(env);
|
||||
int msgId = GET_MESSAGE_STRING_ID(SharedObjectRefersLocalObject);
|
||||
BRANCH(BoolAnd(InSharedHeap(objectRegion), BoolNot(InSharedHeap(valueRegion))), &fatal, &exit);
|
||||
Bind(&fatal);
|
||||
{
|
||||
FatalPrint(glue, {Int32(msgId)});
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(&exit);
|
||||
env->SubCfgExit();
|
||||
}
|
||||
|
||||
void StubBuilder::SetValueWithBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value, bool withEden,
|
||||
MemoryAttribute::ShareFlag share)
|
||||
{
|
||||
|
@ -731,6 +731,7 @@ ShortcutBoolOr([&]{ return first; }, [&]{ return second; })
|
||||
GateRef IntPtrEuqal(GateRef x, GateRef y);
|
||||
void SetValueWithAttr(GateRef glue, GateRef obj, GateRef offset, GateRef key, GateRef value, GateRef attr);
|
||||
void SetValueWithRep(GateRef glue, GateRef obj, GateRef offset, GateRef value, GateRef rep, Label *repChange);
|
||||
void VerifyBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value);
|
||||
void SetValueWithBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value, bool withEden = false,
|
||||
MemoryAttribute::ShareFlag share = MemoryAttribute::UNKNOWN);
|
||||
GateRef GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index,
|
||||
|
@ -1195,7 +1195,7 @@ void AsmInterpreterCall::PreserveMostCall(ExtendedAssembler* assembler)
|
||||
// Skip x0 slot and frametype slot
|
||||
__ Add(SP, SP, Immediate(DOUBLE_SLOT_SIZE * PreserveRegPairIndex +
|
||||
FRAME_SLOT_SIZE + FRAME_SLOT_SIZE));
|
||||
__ Ldp(X29, X30, MemoryOperand(SP, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
|
||||
__ Ldp(FP, X30, MemoryOperand(SP, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
|
||||
__ Ret();
|
||||
}
|
||||
}
|
||||
@ -1214,7 +1214,7 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
// region flag: 0x08, 0x09, [0x0A, 0x11], [0x12, 0x15], 0x16
|
||||
// value is share: [0x12, 0x16] => valueMaybeSweepableShare
|
||||
// readonly share: 0x16 => return
|
||||
// sweepable share: [0x12, 0x15] => needCallShare
|
||||
// sweepable share: [0x12, 0x15] => needShareBarrier
|
||||
// value is not share: 0x08, 0x09, [0x0A, 0x11], => valueNotShare
|
||||
// value is young : 0x09 => needCallNotShare
|
||||
// value is not young : 0x08, [0x0A, 0x11], => checkMark
|
||||
@ -1225,7 +1225,7 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
Label needCall;
|
||||
Label checkMark;
|
||||
Label needCallNotShare;
|
||||
Label needCallShare;
|
||||
Label needShareBarrier;
|
||||
Label valueNotShare;
|
||||
Label valueMaybeSweepableShare;
|
||||
{
|
||||
@ -1289,21 +1289,14 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
{
|
||||
// valueMaybeSweepableShare:
|
||||
// if (valueFlag != IN_SHARED_READ_ONLY_SPACE){
|
||||
// goto needCallShare
|
||||
// goto needShareBarrier
|
||||
// }
|
||||
// return
|
||||
__ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE));
|
||||
__ B(NE, &needCallShare);
|
||||
__ B(NE, &needShareBarrier);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
__ Bind(&needCallShare);
|
||||
{
|
||||
int32_t SValueBarrierOffset = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
|
||||
kungfu::CommonStubCSigns::SetSValueWithBarrier * FRAME_SLOT_SIZE;
|
||||
__ Mov(X15, SValueBarrierOffset);
|
||||
__ B(&needCall);
|
||||
}
|
||||
__ Bind(&needCallNotShare);
|
||||
{
|
||||
int32_t NonSValueBarrier = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
|
||||
@ -1315,6 +1308,10 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
__ Ldr(X15, MemoryOperand(X0, Register(X15), UXTX));
|
||||
PreserveMostCall(assembler);
|
||||
}
|
||||
__ Bind(&needShareBarrier);
|
||||
{
|
||||
ASMFastSharedWriteBarrier(assembler, needCall);
|
||||
}
|
||||
}
|
||||
|
||||
// ASMWriteBarrierWithEden(GateRef glue, GateRef obj, GateRef offset, GateRef value)
|
||||
@ -1334,6 +1331,128 @@ void AsmInterpreterCall::ASMWriteBarrierWithEden(ExtendedAssembler* assembler)
|
||||
PreserveMostCall(assembler);
|
||||
}
|
||||
|
||||
// %x0 - glue
|
||||
// %x1 - obj
|
||||
// %x2 - offset
|
||||
// %x3 - value
|
||||
void AsmInterpreterCall::ASMFastSharedWriteBarrier(ExtendedAssembler* assembler, Label& needCall)
|
||||
{
|
||||
Label checkBarrierForSharedValue;
|
||||
Label restoreScratchRegister;
|
||||
Label callSharedBarrier;
|
||||
{
|
||||
// int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
|
||||
// int8_t objFlag = *objRegion
|
||||
// if (objFlag >= SHARED_SPACE_BEGIN){
|
||||
// // share to share, just check the barrier
|
||||
// goto checkBarrierForSharedValue
|
||||
// }
|
||||
__ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
|
||||
__ Ldrb(Register(X15, W), MemoryOperand(X15, 0));
|
||||
// X15 is the flag load from region of obj.
|
||||
__ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::SHARED_SPACE_BEGIN));
|
||||
__ B(GE, &checkBarrierForSharedValue); // if objflag >= SHARED_SPACE_BEGIN => checkBarrierForSharedValue
|
||||
}
|
||||
{
|
||||
// int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
|
||||
// int8_t *localToShareSet = *(objRegion + LocalToShareSetOffset)
|
||||
// if (localToShareSet == 0){
|
||||
// goto callSharedBarrier
|
||||
// }
|
||||
__ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
|
||||
__ Ldr(X15, MemoryOperand(X15, Region::PackedData::GetLocalToShareSetOffset(false)));
|
||||
// X15 is localToShareSet for obj region.
|
||||
__ Cbz({X15, X}, &callSharedBarrier); // if localToShareSet == 0 => callSharedBarrier
|
||||
}
|
||||
{
|
||||
// X16, X17 will be used as scratch register, spill them.
|
||||
// the caller will call this function with inline asm, it will not save any registers except x15.
|
||||
// So we need spill and restore x16, x17 when we need them as scratch register.
|
||||
{
|
||||
__ Stp(X16, X17, MemoryOperand(SP, -DOUBLE_SLOT_SIZE, PREINDEX));
|
||||
}
|
||||
// int64_t objOffset = obj & DEFAULT_REGION_MASK
|
||||
// int64_t slotOffset = objOffset + offset
|
||||
__ And(X16, X1, LogicalImmediate::Create(DEFAULT_REGION_MASK, RegXSize));
|
||||
__ Add(X16, X16, Operand(Register(X2)));
|
||||
|
||||
// the logic to get mask in stub_builder.cpp
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// bitOffset: bbbbbbbbbbbbbbbbbbbbbbbb bbbcc ccc
|
||||
// bitPerWordMask: 11 111
|
||||
// indexInWord = And bitoffset bitPerWordMask
|
||||
// indexInWord: cc ccc
|
||||
// mask = 1 << indexInWord
|
||||
|
||||
// the logic to test bit set value here:
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// slotOffset: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb ccccc ddd
|
||||
// Ubfm X16 slotOffset 3 7
|
||||
// indexInWord: cc ccc
|
||||
__ Ubfm(X17, X16, TAGGED_TYPE_SIZE_LOG, TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2 - 1);
|
||||
|
||||
// the logic to get byteIndex in stub_builder.cpp
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// slotOffset: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb ccccc ddd
|
||||
// 1. bitOffsetPtr = LSR TAGGED_TYPE_SIZE_LOG(3) slotOffset
|
||||
// bitOffsetPtr: aaaaaaaaaaaaaaaaaaaaaaaaaa aaabbbbbbbbbbbbbbbbbbbbbbbb bbbcc ccc
|
||||
// 2. bitOffset = TruncPtrToInt32 bitOffsetPtr
|
||||
// bitOffset: bbbbbbbbbbbbbbbbbbbbbbbb bbbcc ccc
|
||||
// 3. index = LSR BIT_PER_WORD_LOG2(5) bitOffset
|
||||
// index: bbbbbbbbbbbbbbbbbbb bbbbb bbb
|
||||
// 4. byteIndex = Mul index BYTE_PER_WORD(4)
|
||||
// byteIndex: bbbbbbbbbbbbbbbbbbbbb bbbbb b00
|
||||
|
||||
// the logic to get byteIndex here:
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// slotOffset: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb ccccc ddd
|
||||
// Ubfm X16 slotOffset 8 34
|
||||
// index: bbbbbbbbbbbbbbbbbbb bbbbb bbb
|
||||
__ Ubfm(X16, X16, TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2,
|
||||
sizeof(uint32_t) * GCBitset::BIT_PER_BYTE + TAGGED_TYPE_SIZE_LOG - 1);
|
||||
__ Add(X15, X15, Operand(Register(X16), LSL, GCBitset::BYTE_PER_WORD_LOG2));
|
||||
__ Add(X15, X15, Immediate(RememberedSet::GCBITSET_DATA_OFFSET));
|
||||
// X15 is the address of bitset value. X15 = X15 + X16 << BYTE_PER_WORD_LOG2 + GCBITSET_DATA_OFFSET
|
||||
|
||||
// mask = 1 << indexInWord
|
||||
__ Mov(Register(X16, W), 1);
|
||||
__ Lsl(Register(X17, W), Register(X16, W), Register(X17, W)); // X17 is the mask
|
||||
|
||||
__ Ldr(Register(X16, W), MemoryOperand(X15, 0)); // x16: oldsetValue
|
||||
__ Tst(Register(X16, W), Register(X17, W));
|
||||
__ B(NE, &restoreScratchRegister);
|
||||
__ Orr(Register(X16, W), Register(X16, W), Register(X17, W));
|
||||
__ Str(Register(X16, W), MemoryOperand(X15, 0));
|
||||
}
|
||||
__ Bind(&restoreScratchRegister);
|
||||
{
|
||||
__ Ldp(X16, X17, MemoryOperand(SP, DOUBLE_SLOT_SIZE, POSTINDEX));
|
||||
}
|
||||
__ Bind(&checkBarrierForSharedValue);
|
||||
{
|
||||
// checkBarrierForSharedValue:
|
||||
// int8_t GCStateBitField = *(glue+SharedGCStateBitFieldOffset)
|
||||
// if (GCStateBitField & JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK != 0) {
|
||||
// goto callSharedBarrier
|
||||
// }
|
||||
// return
|
||||
__ Mov(X15, JSThread::GlueData::GetSharedGCStateBitFieldOffset(false));
|
||||
__ Ldrb(Register(X15, W), MemoryOperand(X0, Register(X15), UXTX));
|
||||
static_assert(JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK == 1 && "Tbnz can't handle other bit mask");
|
||||
__ Tbnz(Register(X15, W), 0, &callSharedBarrier);
|
||||
// if GCState is not READY_TO_MARK, go to needCallNotShare.
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
__ Bind(&callSharedBarrier);
|
||||
{
|
||||
int32_t SValueBarrierOffset = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
|
||||
kungfu::CommonStubCSigns::SetSValueWithBarrier * FRAME_SLOT_SIZE;
|
||||
__ Mov(X15, SValueBarrierOffset);
|
||||
__ B(&needCall);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate code for generator re-entering asm interpreter
|
||||
// c++ calling convention
|
||||
// Input: %X0 - glue
|
||||
|
@ -217,6 +217,8 @@ public:
|
||||
static void ASMFastWriteBarrier(ExtendedAssembler *assembler);
|
||||
|
||||
static void ASMWriteBarrierWithEden(ExtendedAssembler *assembler);
|
||||
|
||||
static void ASMFastSharedWriteBarrier(ExtendedAssembler *assembler, Label& needCall);
|
||||
private:
|
||||
static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode,
|
||||
Label *stackOverflow, FrameTransitionType type);
|
||||
|
@ -1495,7 +1495,7 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
// region flag: 0x08, 0x09, [0x0A, 0x11], [0x12, 0x14], 0x15
|
||||
// value is share: [0x12, 0x15] => valueMaybeSweepableShare
|
||||
// readonly share: 0x15 => return
|
||||
// sweepable share: [0x12, 0x14] => needCallShare
|
||||
// sweepable share: [0x12, 0x14] => needShareBarrier
|
||||
// value is not share: 0x08, 0x09, [0x0A, 0x11], => valueNotShare
|
||||
// value is young : 0x09 => needCallNotShare
|
||||
// value is not young : 0x08, [0x0A, 0x11], => checkMark
|
||||
@ -1506,7 +1506,7 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
Label needCall;
|
||||
Label checkMark;
|
||||
Label needCallNotShare;
|
||||
Label needCallShare;
|
||||
Label needShareBarrier;
|
||||
Label valueNotShare;
|
||||
Label valueMaybeSweepableShare;
|
||||
{
|
||||
@ -1567,21 +1567,14 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
{
|
||||
// valueMaybeSweepableShare:
|
||||
// if (valueFlag != IN_SHARED_READ_ONLY_SPACE){
|
||||
// goto needCallShare
|
||||
// goto needShareBarrier
|
||||
// }
|
||||
// return
|
||||
__ Cmpl(Immediate(RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE), r11);
|
||||
__ Jne(&needCallShare);
|
||||
__ Jne(&needShareBarrier);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
__ Bind(&needCallShare);
|
||||
{
|
||||
int32_t SValueBarrierOffset = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
|
||||
kungfu::CommonStubCSigns::SetSValueWithBarrier * FRAME_SLOT_SIZE;
|
||||
__ Movq(Operand(rdi, SValueBarrierOffset), r11);
|
||||
__ Jmp(&needCall);
|
||||
}
|
||||
__ Bind(&needCallNotShare);
|
||||
{
|
||||
int32_t NonSValueBarrier = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
|
||||
@ -1592,14 +1585,18 @@ void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
|
||||
{
|
||||
PreserveMostCall(assembler);
|
||||
}
|
||||
__ Bind(&needShareBarrier);
|
||||
{
|
||||
ASMFastSharedWriteBarrier(assembler, needCall);
|
||||
}
|
||||
}
|
||||
|
||||
// ASMWriteBarrierWithEden(GateRef glue, GateRef obj, GateRef offset, GateRef value)
|
||||
// c calling convention, but preserve all general registers except %x15
|
||||
// %x0 - glue
|
||||
// %x1 - obj
|
||||
// %x2 - offset
|
||||
// %x3 - value
|
||||
// %rd1 - glue
|
||||
// %rsi - obj
|
||||
// %rdx - offset
|
||||
// %rcx - value
|
||||
void AsmInterpreterCall::ASMWriteBarrierWithEden(ExtendedAssembler* assembler)
|
||||
{
|
||||
__ BindAssemblerStub(RTSTUB_ID(ASMWriteBarrierWithEden));
|
||||
@ -1610,6 +1607,136 @@ void AsmInterpreterCall::ASMWriteBarrierWithEden(ExtendedAssembler* assembler)
|
||||
PreserveMostCall(assembler);
|
||||
}
|
||||
|
||||
// %rd1 - glue
|
||||
// %rsi - obj
|
||||
// %rdx - offset
|
||||
// %rcx - value
|
||||
void AsmInterpreterCall::ASMFastSharedWriteBarrier(ExtendedAssembler* assembler, Label& needcall)
|
||||
{
|
||||
Label checkBarrierForSharedValue;
|
||||
Label restoreScratchRegister;
|
||||
Label callSharedBarrier;
|
||||
{
|
||||
// int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
|
||||
// int8_t objFlag = *objRegion
|
||||
// if (objFlag >= SHARED_SPACE_BEGIN){
|
||||
// // share to share, just check the barrier
|
||||
// goto checkBarrierForSharedValue
|
||||
// }
|
||||
__ Movabs(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), r11); // r11 is the mask to get the region.
|
||||
__ And(rsi, r11); // r11: region address of obj.
|
||||
__ Movzbl(Operand(r11, 0), r11); // r11: the flag load from region of obj.
|
||||
__ Cmpl(Immediate(RegionSpaceFlag::SHARED_SPACE_BEGIN), r11);
|
||||
__ Jae(&checkBarrierForSharedValue); // if objflag >= SHARED_SPACE_BEGIN => checkBarrierForSharedValue
|
||||
}
|
||||
{
|
||||
// int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
|
||||
// int8_t *localToShareSet = *(objRegion + LocalToShareSetOffset)
|
||||
// if (localToShareSet == 0){
|
||||
// goto callSharedBarrier
|
||||
// }
|
||||
__ Movabs(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), r11); // r11 is the mask to get the region.
|
||||
__ And(rsi, r11); // r11: region address of obj.
|
||||
__ Movq(Operand(r11, Region::PackedData::GetLocalToShareSetOffset(false)), r11);
|
||||
// r11 is localToShareSet for obj region.
|
||||
__ Cmpq(Immediate(0), r11);
|
||||
__ Je(&callSharedBarrier); // if localToShareSet == 0 => callSharedBarrier
|
||||
}
|
||||
{
|
||||
// r12, r13 will be used as scratch register, spill them.
|
||||
{
|
||||
__ Pushq(r12);
|
||||
__ Pushq(r13);
|
||||
}
|
||||
// int64_t objOffset = obj & DEFAULT_REGION_MASK
|
||||
// int64_t slotOffset = objOffset + offset
|
||||
// int8_t lowSlotOffset = slotOffset & 0xff
|
||||
|
||||
__ Movabs(DEFAULT_REGION_MASK, r12);
|
||||
__ And(rsi, r12); // obj & DEFAULT_REGION_MASK => r12 is obj's offset to region
|
||||
__ Addq(rdx, r12); // r12 is slotAddr's offset to region
|
||||
__ Movzbl(r12, r13); // r13 is low 8 bit of slotAddr's offset to region
|
||||
|
||||
// the logic to get byteIndex in stub_builder.cpp
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// slotOffset: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb ccccc ddd
|
||||
// 1. bitOffsetPtr = LSR TAGGED_TYPE_SIZE_LOG(3) slotOffset
|
||||
// bitOffsetPtr: aaaaaaaaaaaaaaaaaaaaaaaaaa aaabbbbbbbbbbbbbbbbbbbbbbbb bbbcc ccc
|
||||
// 2. bitOffset = TruncPtrToInt32 bitOffsetPtr
|
||||
// bitOffset: bbbbbbbbbbbbbbbbbbbbbbbb bbbcc ccc
|
||||
// 3. index = LSR BIT_PER_WORD_LOG2(5) bitOffset
|
||||
// index: bbbbbbbbbbbbbbbbbbb bbbbb bbb
|
||||
// 4. byteIndex = Mul index BYTE_PER_WORD(4)
|
||||
// byteIndex: bbbbbbbbbbbbbbbbbbbbb bbbbb b00
|
||||
|
||||
// the logic to get byteIndex here:
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// slotOffset: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb ccccc ddd
|
||||
// 1. LSR (TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2 - GCBitset::BYTE_PER_WORD_LOG2)(6) slotOffset
|
||||
// r12: aaaaaaaaaaaaaaaaaaaaaaa aaaaaabbbbbbbbbbbbbbbbbbbbb bbbbb bcc
|
||||
// indexMask: 00000000000000000000000000000 000000111111111111111111111 11111 100
|
||||
// 2. And r12 indexMask
|
||||
// byteIndex: bbbbbbbbbbbbbbbbbbbbb bbbbb b00
|
||||
constexpr uint32_t byteIndexMask = static_cast<uint32_t>(0xffffffffffffffff >> TAGGED_TYPE_SIZE_LOG) >>
|
||||
GCBitset::BIT_PER_WORD_LOG2 << GCBitset::BYTE_PER_WORD_LOG2;
|
||||
static_assert(byteIndexMask == 0x1ffffffc && "LocalToShareSet is changed?");
|
||||
__ Shrq(TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2 - GCBitset::BYTE_PER_WORD_LOG2, r12);
|
||||
__ Andq(byteIndexMask, r12); // r12 is byteIndex
|
||||
|
||||
__ Addq(RememberedSet::GCBITSET_DATA_OFFSET, r11); // r11 is bitsetData addr
|
||||
__ Addq(r12, r11); // r11 is the addr of bitset value
|
||||
__ Movl(Operand(r11, 0), r12); // r12: oldsetValue
|
||||
|
||||
// the logic to get mask in stub_builder.cpp
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// bitOffset: bbbbbbbbbbbbbbbbbbbbbbbb bbbcc ccc
|
||||
// bitPerWordMask: 11 111
|
||||
// indexInWord = And bitoffset bitPerWordMask
|
||||
// indexInWord: cc ccc
|
||||
// mask = 1 << indexInWord
|
||||
|
||||
// the logic to test bit set value here:
|
||||
// [63-------------------------35][34------------------------8][7---3][2-0]
|
||||
// slotOffset: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb ccccc ddd
|
||||
// lowSlotOffset: ccccc ddd
|
||||
// indexInWord = Shrl TAGGED_TYPE_SIZE_LOG lowSlotOffset
|
||||
// indexInWord: cc ccc
|
||||
__ Shrl(TAGGED_TYPE_SIZE_LOG, r13);
|
||||
|
||||
// if "r13" position in r12 is 1, goto restoreScratchRegister;
|
||||
// if "r13" position in r12 is 0, set it to 1 and store r12 to r11(addr of bitset value)
|
||||
__ Btsl(r13, r12);
|
||||
__ Jb(&restoreScratchRegister);
|
||||
__ Movl(r12, Operand(r11, 0));
|
||||
}
|
||||
__ Bind(&restoreScratchRegister);
|
||||
{
|
||||
__ Popq(r13);
|
||||
__ Popq(r12);
|
||||
}
|
||||
__ Bind(&checkBarrierForSharedValue);
|
||||
{
|
||||
// checkBarrierForSharedValue:
|
||||
// int8_t GCStateBitField = *(glue+SharedGCStateBitFieldOffset)
|
||||
// if (GCStateBitField & JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK != 0) {
|
||||
// goto callSharedBarrier
|
||||
// }
|
||||
// return
|
||||
__ Movl(Operand(rdi, JSThread::GlueData::GetSharedGCStateBitFieldOffset(false)), r11);
|
||||
__ Testb(Immediate(JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK), r11);
|
||||
__ Jne(&callSharedBarrier);
|
||||
// if GCState is not READY_TO_MARK, go to needCallNotShare.
|
||||
__ Ret();
|
||||
}
|
||||
__ Bind(&callSharedBarrier);
|
||||
{
|
||||
int32_t NonSValueBarrier = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
|
||||
kungfu::CommonStubCSigns::SetSValueWithBarrier * FRAME_SLOT_SIZE;
|
||||
__ Movq(Operand(rdi, NonSValueBarrier), r11);
|
||||
__ Jmp(&needcall);
|
||||
}
|
||||
}
|
||||
|
||||
void AsmInterpreterCall::PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
|
||||
Register op1, Register op2, Label *stackOverflow)
|
||||
{
|
||||
|
@ -220,6 +220,7 @@ private:
|
||||
static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
|
||||
Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow);
|
||||
static void PreserveMostCall(ExtendedAssembler* assembler);
|
||||
static void ASMFastSharedWriteBarrier(ExtendedAssembler *assembler, Label &needcall);
|
||||
friend class OptimizedCall;
|
||||
friend class BaselineCall;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user