• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/barrier_stub_builder.h"
17 #include "ecmascript/compiler/rt_call_signature.h"
18 #include "ecmascript/compiler/stub_builder-inl.h"
19 #include "ecmascript/js_thread.h"
20 
21 /*  LOCAL_TO_SHARE_SWAPPED 和 OLD_TO_NEW_SWAPPED_MASK标记读取并发场景分析:
22 *   设置标记:CollectGarbage->RunPhases->Sweep->PrepareSweeping这条路径会设置这两个标记, CollectGarbage只会在当前线程local gc时使用。
23 *   清除标记:(1)由CreateXXXXRememberedSet清除标记,这个调用点有两种情况:
24 *                a. js主线程在需要读rset时会调用的方法,一定在js线程。
25 *                b. gc时移动对象时从gc线程调用,此时主线程是被suspendAll停下来的等待gc线程的状态。
26 *           (2)CollectGarbage -> RunPhases -> Evacuate -> UpdateReference ->
27 *               并行UpdateReferenceTask -> UpdateRSet -> Merge:
28 *               其中有并行任务,会主线程会等待并行任务结束,有同步的保证,可以保证清除能够被主线程观察到。
29 *
30 *   LOCAL_TO_SHARE_COLLECTED_MASK标记读取并发场景分析:
31 *   设置标记:SharedGCMarkBase::MarkRoots-> CollectLocalVMRSet(访问多个线程的heap) -> EnumerateRegions -> ExtractLocalToShareRSet,
32 *           这里会有跨线程,但是已经在SuspendAll的保证之下了。
33 *   清除标记:(1)入口在MergeBackAndResetRSetWorkListHandler,这个函数调用点有5个,可能不在当前线程,但是调用点处都有SuspendAll的保证。
34 *           (2)js线程在local gc结束时,会把自己线程被Collect的rset拿回来,这里只处理当前线程的,没有并发问题。
35 */
36 
37 namespace panda::ecmascript::kungfu {
DoBatchBarrier()38 void BarrierStubBuilder::DoBatchBarrier()
39 {
40     auto env = GetEnvironment();
41     Label entry(env);
42     env->SubCfgEntry(&entry);
43     Label exit(env);
44     Label checkNext(env);
45     BRANCH_UNLIKELY(
46         LoadPrimitive(VariableType::BOOL(), glue_, IntPtr(JSThread::GlueData::GetIsEnableCMCGCOffset(env->Is32Bit()))),
47         &exit, &checkNext);
48     Bind(&checkNext);
49     Label handleMark(env);
50     Label handleBitSet(env);
51     BRANCH_NO_WEIGHT(InSharedHeap(objectRegion_), &handleMark, &handleBitSet);
52     Bind(&handleBitSet);
53     {
54         DoBatchBarrierInternal();
55         Jump(&handleMark);
56     }
57 
58     Bind(&handleMark);
59     HandleMark();
60     Jump(&exit);
61     Bind(&exit);
62     env->SubCfgExit();
63 }
64 
DoBatchBarrierInternal()65 void BarrierStubBuilder::DoBatchBarrierInternal()
66 {
67     auto env = GetEnvironment();
68     Label entry(env);
69     env->SubCfgEntry(&entry);
70     Label exit(env);
71     Label inYoung(env);
72     Label notInYoung(env);
73     BRANCH_NO_WEIGHT(InYoungGeneration(objectRegion_), &inYoung, &notInYoung);
74     Bind(&notInYoung);
75     {
76         BarrierBatchBitSet(LocalToShared | OldToNew);
77         Jump(&exit);
78     }
79     Bind(&inYoung);
80     {
81         BarrierBatchBitSet(LocalToShared);
82         Jump(&exit);
83     }
84     Bind(&exit);
85     env->SubCfgExit();
86 }
87 
GetBitSetDataAddr(GateRef objectRegion,GateRef loadOffset,int32_t createFunID)88 GateRef BarrierStubBuilder::GetBitSetDataAddr(GateRef objectRegion, GateRef loadOffset, int32_t createFunID)
89 {
90     auto env = GetEnvironment();
91     Label entry(env);
92     env->SubCfgEntry(&entry);
93     Label exit(env);
94 
95     DEFVARIABLE(oldBitSet, VariableType::NATIVE_POINTER(),
96                 LoadPrimitive(VariableType::NATIVE_POINTER(), objectRegion, loadOffset));
97 
98     Label createRset(env);
99     BRANCH_UNLIKELY(IntPtrEqual(*oldBitSet, IntPtr(0)), &createRset, &exit);
100     Bind(&createRset);
101     {
102         oldBitSet = CallNGCRuntime(glue_, createFunID, {objectRegion});
103         Jump(&exit);
104     }
105 
106     Bind(&exit);
107     GateRef bitSetDataAddr = PtrAdd(*oldBitSet, IntPtr(RememberedSet::GCBITSET_DATA_OFFSET));
108     env->SubCfgExit();
109     return bitSetDataAddr;
110 }
111 
HandleMark()112 void BarrierStubBuilder::HandleMark()
113 {
114     auto env = GetEnvironment();
115     Label entry(env);
116     env->SubCfgEntry(&entry);
117     Label exit(env);
118 
119     bool isArch32 = GetEnvironment()->Is32Bit();
120     GateRef gcStateBitField = LoadPrimitive(VariableType::INT64(), glue_,
121         Int64(JSThread::GlueData::GetGCStateBitFieldOffset(isArch32)));
122     GateRef gcState = Int64And(gcStateBitField, Int64(JSThread::CONCURRENT_MARKING_BITFIELD_MASK));
123     GateRef sharedGCStateBitField = LoadPrimitive(VariableType::INT64(), glue_,
124         Int64(JSThread::GlueData::GetSharedGCStateBitFieldOffset(isArch32)));
125     GateRef sharedGCState = Int64And(sharedGCStateBitField, Int64(JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK));
126     Label needMarking(env);
127     GateRef marking = Int64NotEqual(gcState, Int64(static_cast<int64_t>(MarkStatus::READY_TO_MARK)));
128     GateRef sharedMarking = Int64NotEqual(sharedGCState,
129                                           Int64(static_cast<int64_t>(SharedMarkStatus::READY_TO_CONCURRENT_MARK)));
130     BRANCH_LIKELY(BitAnd(BoolNot(marking), BoolNot(sharedMarking)), &exit, &needMarking);
131     Bind(&needMarking);
132     Label begin(env);
133     Label body(env);
134     Label endLoop(env);
135     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
136     Jump(&begin);
137     LoopBegin(&begin);
138     {
139         BRANCH_LIKELY(Int32UnsignedLessThan(*index, slotCount_), &body, &exit);
140         Bind(&body);
141         {
142             GateRef offset = PtrMul(ZExtInt32ToPtr(*index), IntPtr(JSTaggedValue::TaggedTypeSize()));
143             GateRef value = Load(VariableType::JS_ANY(), glue_, dstAddr_, offset);
144             Label doMarking(env);
145             BRANCH_NO_WEIGHT(TaggedIsHeapObject(value), &doMarking, &endLoop);
146             Bind(&doMarking);
147 
148             GateRef valueRegion = ObjectAddressToRange(value);
149             Label callMarking(env);
150             Label doSharedMarking(env);
151             BRANCH_NO_WEIGHT(LogicAndBuilder(env).And(marking).And(BoolNot(InSharedHeap(valueRegion))).Done(),
152                              &callMarking, &doSharedMarking);
153             Bind(&callMarking);
154             {
155                 CallNGCRuntime(glue_, RTSTUB_ID(MarkingBarrier), {glue_, dstAddr_, offset, value});
156                 Jump(&endLoop);
157             }
158             Bind(&doSharedMarking);
159             {
160                 Label callSharedMarking(env);
161                 BRANCH_NO_WEIGHT(
162                     LogicAndBuilder(env).And(sharedMarking).And(InSharedSweepableSpace(valueRegion)).Done(),
163                     &callSharedMarking, &endLoop);
164                 Bind(&callSharedMarking);
165                 {
166                     CallNGCRuntime(glue_, RTSTUB_ID(SharedGCMarkingBarrier), {glue_, dstAddr_, offset, value});
167                     Jump(&endLoop);
168                 }
169             }
170         }
171     }
172     Bind(&endLoop);
173     index = Int32Add(*index, Int32(1));
174     LoopEnd(&begin);
175     Bind(&exit);
176     env->SubCfgExit();
177 }
178 
BarrierBatchBitSet(uint8_t bitSetSelect)179 void BarrierStubBuilder::BarrierBatchBitSet(uint8_t bitSetSelect)
180 {
181     auto env = GetEnvironment();
182     Label entry(env);
183     env->SubCfgEntry(&entry);
184 
185     Label beforeExit(env);
186     Label exit(env);
187     Label begin(env);
188     Label loopBody(env);
189     Label endLoop(env);
190     GateRef initByteIdx = TruncPtrToInt32(IntPtrLSR(PtrSub(TaggedCastToIntPtr(dstAddr_), objectRegion_),
191                                                     IntPtr(TAGGED_TYPE_SIZE_LOG)));
192     GateRef initQuadIdx = Int32LSR(initByteIdx, Int32(BIT_PER_QUAD_LOG2));
193     DEFVARIABLE(quadIdx, VariableType::INT32(), initQuadIdx);
194     DEFVARIABLE(localToShareBitSet, VariableType::INT64(), Int64(0));
195     DEFVARIABLE(oldToNewBitSet, VariableType::INT64(), Int64(0));
196     DEFVARIABLE(index, VariableType::INT32(), initByteIdx);
197 
198     Jump(&begin);
199     LoopBegin(&begin);
200     {
201         BRANCH_NO_WEIGHT(Int32UnsignedLessThan(*index, Int32Add(initByteIdx, slotCount_)), &loopBody, &beforeExit);
202         Bind(&loopBody);
203         {
204             Label checkLocalRegion(env);
205             Label updateLocalToShared(env);
206             Label updateOldToNew(env);
207             GateRef offset = PtrMul(ZExtInt32ToPtr(*index), IntPtr(JSTaggedValue::TaggedTypeSize()));
208             GateRef value = Load(VariableType::JS_ANY(), glue_, objectRegion_, offset);
209             Label doUpdate(env);
210             BRANCH_NO_WEIGHT(TaggedIsHeapObject(value), &doUpdate, &endLoop);
211             Bind(&doUpdate);
212             {
213                 GateRef valueRegion = ObjectAddressToRange(value);
214                 Label flushLast(env);
215                 Label curCheck(env);
216                 GateRef curQuadIdx = Int32LSR(*index, Int32(BIT_PER_QUAD_LOG2));
217                 GateRef bitOffset = Int32And(*index, Int32(BIT_PER_QUAD_MASK));
218                 GateRef mask = Int64LSL(Int64(1), ZExtInt32ToInt64(bitOffset));
219                 BRANCH_LIKELY(Int32Equal(curQuadIdx, *quadIdx), &curCheck, &flushLast);
220                 Bind(&flushLast);
221                 {
222                     Label updateIdx(env);
223                     FlushBatchBitSet(bitSetSelect, *quadIdx,  localToShareBitSet, oldToNewBitSet, &updateIdx);
224                     Bind(&updateIdx);
225                     quadIdx = curQuadIdx;
226                     Jump(&curCheck);
227                 }
228                 Bind(&curCheck);
229                 if ((bitSetSelect & LocalToShared) != 0) {
230                     BRANCH_NO_WEIGHT(InSharedSweepableSpace(valueRegion), &updateLocalToShared, &checkLocalRegion);
231                     Bind(&updateLocalToShared);
232                     {
233                         localToShareBitSet = Int64Or(*localToShareBitSet, mask);
234                         Jump(&endLoop);
235                     }
236                     Bind(&checkLocalRegion);
237                 }
238                 if ((bitSetSelect & OldToNew) != 0) {
239                     BRANCH_NO_WEIGHT(InYoungGeneration(valueRegion), &updateOldToNew, &endLoop);
240                     Bind(&updateOldToNew);
241                     {
242                         oldToNewBitSet = Int64Or(*oldToNewBitSet, mask);
243                     }
244                 }
245                 Jump(&endLoop);
246             }
247         }
248         Bind(&endLoop);
249         index = Int32Add(*index, Int32(1));
250         LoopEnd(&begin);
251     }
252     Bind(&beforeExit);
253     FlushBatchBitSet(bitSetSelect, *quadIdx, localToShareBitSet, oldToNewBitSet, &exit);
254     Bind(&exit);
255     env->SubCfgExit();
256 }
257 
FlushBatchBitSet(uint8_t bitSetSelect,GateRef quadIdx,Variable & localToShareBitSetVar,Variable & oldToNewBitSetVar,Label * next)258 void BarrierStubBuilder::FlushBatchBitSet(uint8_t bitSetSelect, GateRef quadIdx,
259                                           Variable &localToShareBitSetVar, Variable &oldToNewBitSetVar, Label* next)
260 {
261     auto env = GetEnvironment();
262     Label batchUpdateLocalToShare(env);
263     Label checkNext(env);
264     Label batchUpdateOldToNew(env);
265     if ((bitSetSelect & LocalToShared) != 0) {
266         BRANCH_LIKELY(Int64NotEqual(*localToShareBitSetVar, Int64(0)), &batchUpdateLocalToShare, &checkNext);
267         Bind(&batchUpdateLocalToShare);
268         {
269             GateRef loadOffset = IntPtr(Region::PackedData::GetLocalToShareSetOffset(env->Is32Bit()));
270             GateRef bitSetAddr = GetBitSetDataAddr(objectRegion_, loadOffset, RTSTUB_ID(CreateLocalToShare));
271 
272             GateRef byteIndex = Int32LSL(quadIdx, Int32(BYTE_PER_QUAD_LOG2));
273             GateRef oldValue = LoadPrimitive(VariableType::INT64(), bitSetAddr, ZExtInt32ToInt64(byteIndex));
274             Store(VariableType::INT64(), glue_, bitSetAddr, ZExtInt32ToInt64(byteIndex),
275                   Int64Or(oldValue, *localToShareBitSetVar), MemoryAttribute::NoBarrier());
276             localToShareBitSetVar = Int64(0);
277             Jump(&checkNext);
278         }
279         Bind(&checkNext);
280     }
281     if ((bitSetSelect & OldToNew) != 0) {
282         BRANCH_LIKELY(Int64NotEqual(*oldToNewBitSetVar, Int64(0)), &batchUpdateOldToNew, next);
283         Bind(&batchUpdateOldToNew);
284         {
285             GateRef loadOffset = IntPtr(Region::PackedData::GetOldToNewSetOffset(env->Is32Bit()));
286             GateRef bitSetAddr = GetBitSetDataAddr(objectRegion_, loadOffset, RTSTUB_ID(CreateOldToNew));
287             GateRef byteIndex = Int32LSL(quadIdx, Int32(BYTE_PER_QUAD_LOG2));
288             GateRef oldValue = LoadPrimitive(VariableType::INT64(), bitSetAddr, ZExtInt32ToInt64(byteIndex));
289             Store(VariableType::INT64(), glue_, bitSetAddr, ZExtInt32ToInt64(byteIndex),
290                   Int64Or(oldValue, *oldToNewBitSetVar), MemoryAttribute::NoBarrier());
291             oldToNewBitSetVar = Int64(0);
292         }
293     }
294     Jump(next);
295 }
296 
DoMoveBarrierCrossRegion(GateRef srcAddr,GateRef srcObj)297 void BarrierStubBuilder::DoMoveBarrierCrossRegion(GateRef srcAddr, GateRef srcObj)
298 {
299     auto env = GetEnvironment();
300     Label entry(env);
301     env->SubCfgEntry(&entry);
302     Label exit(env);
303     Label checkNext(env);
304     BRANCH_UNLIKELY(
305         LoadPrimitive(VariableType::BOOL(), glue_, IntPtr(JSThread::GlueData::GetIsEnableCMCGCOffset(env->Is32Bit()))),
306         &exit, &checkNext);
307     Bind(&checkNext);
308     Label handleMark(env);
309     Label handleBitSet(env);
310     Label doMove(env);
311     BRANCH_NO_WEIGHT(Int32Equal(slotCount_, Int32(0)), &exit, &doMove);
312     Bind(&doMove);
313     BRANCH_NO_WEIGHT(InSharedHeap(objectRegion_), &handleMark, &handleBitSet);
314     Bind(&handleBitSet);
315     {
316         GateRef srcRegion = ObjectAddressToRange(srcObj);
317         Label batchBarrier(env);
318         Label srcNotInSharedHeap(env);
319         // copy shared array to local heap, there is no bitset can be copied, do batch barrier for dst object.
320         BRANCH_UNLIKELY(InSharedHeap(srcRegion), &batchBarrier, &srcNotInSharedHeap);
321         Bind(&srcNotInSharedHeap);
322         {
323             GateRef sameKind = LogicOrBuilder(env)
324                                .Or(BitAnd(InYoungGeneration(objectRegion_), InYoungGeneration(srcRegion)))
325                                .Or(BitAnd(InGeneralOldGeneration(objectRegion_), InGeneralOldGeneration(srcRegion)))
326                                .Done();
327             Label sameRegionKind(env);
328             Label crossRegion(env);
329             BRANCH_NO_WEIGHT(sameKind, &sameRegionKind, &crossRegion);
330             Bind(&sameRegionKind);
331             {
332                 // dst and src are in same kind region, copy the bitset of them.
333                 DoMoveBarrierSameRegionKind(srcAddr, srcRegion, CrossRegion);
334                 Jump(&handleMark);
335             }
336             Bind(&crossRegion);
337             {
338                 Label copyLocalToShare(env);
339                 BRANCH_UNLIKELY(IsLocalToShareSwapped(srcRegion), &batchBarrier, &copyLocalToShare);
340                 Bind(&copyLocalToShare);
341                 {
342                     // dst and src are in different kind region, localToShare bitset can be copied unconditionally,
343                     GateRef srcBitStartIdx = Int64LSR(Int64Sub(srcAddr, srcRegion), Int64(TAGGED_TYPE_SIZE_LOG));
344                     GateRef dstBitStartIdx = Int64LSR(Int64Sub(dstAddr_, objectRegion_), Int64(TAGGED_TYPE_SIZE_LOG));
345 
346                     GateRef localToShareOffset = IntPtr(Region::PackedData::GetLocalToShareSetOffset(env->Is32Bit()));
347                     GateRef localToShareBitSetAddr =
348                         GetBitSetDataAddr(objectRegion_, localToShareOffset, RTSTUB_ID(CreateLocalToShare));
349                     GateRef srcLocalToShareBitSetAddr =
350                         GetBitSetDataAddr(srcRegion, localToShareOffset, RTSTUB_ID(CreateLocalToShare));
351                     BitSetRangeMoveForward(srcLocalToShareBitSetAddr, localToShareBitSetAddr, srcBitStartIdx,
352                                            dstBitStartIdx, ZExtInt32ToInt64(slotCount_));
353                     Label inOld(env);
354                     BRANCH_NO_WEIGHT(InYoungGeneration(objectRegion_), &handleMark, &inOld);
355                     Bind(&inOld);
356                     {
357                         // copy young object to old region, do BarrierBatchBitSet bitset for oldToNew bitset.
358                         BarrierBatchBitSet(OldToNew);
359                         Jump(&handleMark);
360                     }
361                 }
362             }
363         }
364         Bind(&batchBarrier);
365         {
366             DoBatchBarrierInternal();
367             Jump(&handleMark);
368         }
369     }
370     Bind(&handleMark);
371     HandleMark();
372     Jump(&exit);
373     Bind(&exit);
374     env->SubCfgExit();
375 }
376 
DoMoveBarrierInRegion(GateRef srcAddr)377 void BarrierStubBuilder::DoMoveBarrierInRegion(GateRef srcAddr)
378 {
379     auto env = GetEnvironment();
380     Label entry(env);
381     env->SubCfgEntry(&entry);
382     Label exit(env);
383     Label checkNext(env);
384     BRANCH_UNLIKELY(
385         LoadPrimitive(VariableType::BOOL(), glue_, IntPtr(JSThread::GlueData::GetIsEnableCMCGCOffset(env->Is32Bit()))),
386         &exit, &checkNext);
387     Bind(&checkNext);
388     Label handleMark(env);
389     Label handleBitSet(env);
390     Label doMove(env);
391     BRANCH_NO_WEIGHT(Int32Equal(slotCount_, Int32(0)), &exit, &doMove);
392     Bind(&doMove);
393     BRANCH_NO_WEIGHT(InSharedHeap(objectRegion_), &handleMark, &handleBitSet);
394     Bind(&handleBitSet);
395     {
396         DoMoveBarrierSameRegionKind(srcAddr, objectRegion_, InSameRegion);
397         Jump(&handleMark);
398     }
399     Bind(&handleMark);
400     HandleMark();
401     Jump(&exit);
402     Bind(&exit);
403     env->SubCfgExit();
404 }
405 
DoMoveBarrierSameRegionKind(GateRef srcAddr,GateRef srcRegion,RegionKind regionKind)406 void BarrierStubBuilder::DoMoveBarrierSameRegionKind(GateRef srcAddr, GateRef srcRegion, RegionKind regionKind)
407 {
408     auto env = GetEnvironment();
409     Label entry(env);
410     env->SubCfgEntry(&entry);
411     Label exit(env);
412     Label inYoung(env);
413     Label inOld(env);
414     Label copyBitSet(env);
415 
416     DEFVARIABLE(dstBitSetAddr, VariableType::NATIVE_POINTER(), IntPtr(0));
417     DEFVARIABLE(dstBitSetAddr2, VariableType::NATIVE_POINTER(), IntPtr(0));
418     DEFVARIABLE(srcBitSetAddr, VariableType::NATIVE_POINTER(), IntPtr(0));
419     DEFVARIABLE(srcBitSetAddr2, VariableType::NATIVE_POINTER(), IntPtr(0));
420 
421     GateRef localToShareOffset = IntPtr(Region::PackedData::GetLocalToShareSetOffset(env->Is32Bit()));
422     GateRef localToShareBitSetAddr =
423         GetBitSetDataAddr(objectRegion_, localToShareOffset, RTSTUB_ID(CreateLocalToShare));
424     GateRef srcLocalToShareBitSetAddr = Gate::InvalidGateRef;
425     if (regionKind == InSameRegion) {
426         srcLocalToShareBitSetAddr = localToShareBitSetAddr;
427     } else {
428         ASSERT(regionKind == CrossRegion);
429         srcLocalToShareBitSetAddr = GetBitSetDataAddr(srcRegion, localToShareOffset, RTSTUB_ID(CreateLocalToShare));
430     }
431     GateRef localToShareSwapped = IsLocalToShareSwapped(srcRegion);
432     BRANCH_NO_WEIGHT(InYoungGeneration(objectRegion_), &inYoung, &inOld);
433     Bind(&inYoung);
434     {
435         Label batchBarrier(env);
436         Label copyLocalToShare(env);
437         BRANCH_UNLIKELY(localToShareSwapped, &batchBarrier, &copyLocalToShare);
438         Bind(&batchBarrier);
439         {
440             // slowpath, localToShareRSet is swapped, it can't be copied, just set the bitset bit by bit.
441             BarrierBatchBitSet(LocalToShared);
442             Jump(&exit);
443         }
444         Bind(&copyLocalToShare);
445         {
446             dstBitSetAddr = localToShareBitSetAddr;
447             srcBitSetAddr = srcLocalToShareBitSetAddr;
448             Jump(&copyBitSet);
449         }
450     }
451     Bind(&inOld);
452     {
453         GateRef oldToNewOffset = IntPtr(Region::PackedData::GetOldToNewSetOffset(env->Is32Bit()));
454         GateRef oldToNewBitSetAddr = GetBitSetDataAddr(objectRegion_, oldToNewOffset, RTSTUB_ID(CreateOldToNew));
455         GateRef srcOldToNewBitSetAddr = GetBitSetDataAddr(srcRegion, oldToNewOffset, RTSTUB_ID(CreateOldToNew));
456         // CreateOldToNew may change the RSetFlag, so load it again.
457         GateRef oldToNewSwapped = IsOldToNewSwapped(srcRegion);
458         Label batchBarrier(env);
459         Label tryBatchBarrier(env);
460         Label copyBoth(env);
461         // both localToShareSwapped and oldToNewSwapped are not swapped.
462         BRANCH_LIKELY(BitAnd(BoolNot(localToShareSwapped), BoolNot(oldToNewSwapped)), &copyBoth, &tryBatchBarrier);
463         Bind(&copyBoth);
464         {
465             dstBitSetAddr = localToShareBitSetAddr;
466             srcBitSetAddr = srcLocalToShareBitSetAddr;
467             dstBitSetAddr2 = oldToNewBitSetAddr;
468             srcBitSetAddr2 = srcOldToNewBitSetAddr;
469             Jump(&copyBitSet);
470         }
471         Bind(&tryBatchBarrier);
472         {
473             Label copyOne(env);
474             BRANCH_UNLIKELY(BitAnd(localToShareSwapped, oldToNewSwapped), &batchBarrier, &copyOne);
475             Bind(&batchBarrier);
476             {
477                 // slowpath, localToShareRSet and oldToNewRSet are swapped,
478                 // it can't be copied, just set the bitset bit by bit.
479                 BarrierBatchBitSet(LocalToShared | OldToNew);
480                 Jump(&exit);
481             }
482             Bind(&copyOne);
483             {
484                 Label localToShareBatchBarrier(env);
485                 Label oldToNewBatchBarrier(env);
486                 BRANCH_NO_WEIGHT(localToShareSwapped, &localToShareBatchBarrier, &oldToNewBatchBarrier);
487                 Bind(&localToShareBatchBarrier);
488                 {
489                     // slowpath, localToShareRSet is swapped, it can't be copied, just set the bitset bit by bit.
490                     // And copy oldToNewRSet.
491                     BarrierBatchBitSet(LocalToShared);
492                     dstBitSetAddr = oldToNewBitSetAddr;
493                     srcBitSetAddr = srcOldToNewBitSetAddr;
494                     Jump(&copyBitSet);
495                 }
496                 Bind(&oldToNewBatchBarrier);
497                 {
498                     // slowpath, oldToNewRSet is swapped, it can't be copied, just set the bitset bit by bit.
499                     // And copy localToShareRSet.
500                     BarrierBatchBitSet(OldToNew);
501                     dstBitSetAddr = localToShareBitSetAddr;
502                     srcBitSetAddr = srcLocalToShareBitSetAddr;
503                     Jump(&copyBitSet);
504                 }
505             }
506         }
507     }
508     Bind(&copyBitSet);
509     {
510         GateRef srcBitStartIdx = Int64LSR(Int64Sub(srcAddr, srcRegion), Int64(TAGGED_TYPE_SIZE_LOG));
511         GateRef dstBitStartIdx = Int64LSR(Int64Sub(dstAddr_, objectRegion_), Int64(TAGGED_TYPE_SIZE_LOG));
512         Label begin(env);
513         Label endLoop(env);
514         Label next(env);
515         Jump(&begin);
516         LoopBegin(&begin);
517         {
518             if (regionKind == InSameRegion) {
519                 BitSetRangeMove(*srcBitSetAddr, *dstBitSetAddr, srcBitStartIdx, dstBitStartIdx,
520                                 ZExtInt32ToInt64(slotCount_));
521             } else {
522                 ASSERT(regionKind == CrossRegion);
523                 BitSetRangeMoveForward(*srcBitSetAddr, *dstBitSetAddr, srcBitStartIdx, dstBitStartIdx,
524                                        ZExtInt32ToInt64(slotCount_));
525             }
526             BRANCH_UNLIKELY(IntPtrEqual(*dstBitSetAddr2, IntPtr(0)), &exit, &next);
527             Bind(&next);
528             {
529                 dstBitSetAddr = *dstBitSetAddr2;
530                 srcBitSetAddr = *srcBitSetAddr2;
531                 dstBitSetAddr2 = IntPtr(0);
532                 srcBitSetAddr2 = IntPtr(0);
533                 Jump(&endLoop);
534             }
535         }
536         Bind(&endLoop);
537         LoopEnd(&begin);
538     }
539     Bind(&exit);
540     env->SubCfgExit();
541 }
542 
BitSetRangeMove(GateRef srcBitSet,GateRef dstBitSet,GateRef srcStart,GateRef dstStart,GateRef length)543 void BarrierStubBuilder::BitSetRangeMove(GateRef srcBitSet, GateRef dstBitSet, GateRef srcStart, GateRef dstStart,
544                                          GateRef length)
545 {
546     auto env = GetEnvironment();
547     Label entry(env);
548     env->SubCfgEntry(&entry);
549     Label exit(env);
550     length = ZExtInt32ToInt64(length);
551 
552     GateRef forward = LogicOrBuilder(env)
553                       .Or(Int64LessThan(dstStart, srcStart))
554                       .Or(Int64GreaterThanOrEqual(dstStart, Int64Add(srcStart, length))).Done();
555     Label moveForward(env);
556     Label moveBackward(env);
557     BRANCH_NO_WEIGHT(forward, &moveForward, &moveBackward);
558     Bind(&moveForward);
559     {
560         BitSetRangeMoveForward(srcBitSet, dstBitSet, srcStart, dstStart, length);
561         Jump(&exit);
562     }
563     Bind(&moveBackward);
564     {
565         BitSetRangeMoveBackward(srcBitSet, dstBitSet, srcStart, dstStart, length);
566         Jump(&exit);
567     }
568     Bind(&exit);
569     env->SubCfgExit();
570 }
571 
BitSetRangeMoveForward(GateRef srcBitSet,GateRef dstBitSet,GateRef srcStart,GateRef dstStart,GateRef length)572 void BarrierStubBuilder::BitSetRangeMoveForward(GateRef srcBitSet, GateRef dstBitSet, GateRef srcStart,
573                                                 GateRef dstStart, GateRef length)
574 {
575     auto env = GetEnvironment();
576     Label entry(env);
577     env->SubCfgEntry(&entry);
578     Label exit(env);
579 
580     DEFVARIABLE(remainLength, VariableType::INT64(), length);
581     // srcQuad <- srcStart / 64;  // 源起始 uint64_t 元素索引
582     // dstQuad <- dstStart / 64; // 目标起始 uint64_t 元素索引
583     // srcBitOffset <- srcStart % 64; // 源起始元素的位偏移
584     // dstBitOffset <- dstStart % 64; // 目标起始元素的位偏移
585     DEFVARIABLE(srcQuad, VariableType::INT64(), Int64LSR(srcStart, Int64(BIT_PER_QUAD_LOG2)));
586     DEFVARIABLE(dstQuad, VariableType::INT64(), Int64LSR(dstStart, Int64(BIT_PER_QUAD_LOG2)));
587     DEFVARIABLE(srcBitOffset, VariableType::INT64(), Int64And(srcStart, Int64(BIT_PER_QUAD_MASK)));
588     DEFVARIABLE(dstBitOffset, VariableType::INT64(), Int64And(dstStart, Int64(BIT_PER_QUAD_MASK)));
589 
590     Label begin(env);
591     Label body(env);
592     Label endLoop(env);
593     Jump(&begin);
594     LoopBegin(&begin);
595 
596     // while remainLength > 0
597     // do
598     BRANCH_LIKELY(Int64GreaterThan(*remainLength, Int64(0)), &body, &exit);
599     Bind(&body);
600     {
601         Label beforeEndLoop(env);
602         // bitsInCurrentQuad <- min of {64 - srcBitOffset, 64 - dstBitOffset, remainLength};
603         GateRef bitsInCurrentQuad = ThreeInt64Min(Int64Sub(Int64(BIT_PER_QUAD), *srcBitOffset),
604                                                   Int64Sub(Int64(BIT_PER_QUAD), *dstBitOffset),
605                                                   *remainLength);
606         GateRef srcQuadData = LoadPrimitive(VariableType::INT64(), srcBitSet,
607             Int64LSL(*srcQuad, Int64(BYTE_PER_QUAD_LOG2)));
608         Label setValue(env);
609         BRANCH_NO_WEIGHT(Int64Equal(srcQuadData, Int64(0)), &beforeEndLoop, &setValue);
610         Bind(&setValue);
611         {
612             // srcMask <- 0xFFFFFFFFFFFFFFFF >> (64 - bitsInCurrentQuad);
613             GateRef srcMask = Int64LSR(Int64(ALL_ONE_MASK), Int64Sub(Int64(BIT_PER_QUAD), bitsInCurrentQuad));
614             // srcData <- (srcBitSet[srcQuad * 8] >> srcBitOffset) & srcMask;
615             GateRef srcData = Int64And(Int64LSR(srcQuadData, *srcBitOffset), srcMask);
616             // zeroMask <- ~(srcMask << dstBitOffset);
617             GateRef zeroMask = Int64Not(Int64LSL(srcMask, *dstBitOffset));
618             // dstData <- load from dstBitSet offset dstQuad * 8;
619             GateRef dstData = LoadPrimitive(VariableType::INT64(), dstBitSet,
620                 Int64LSL(*dstQuad, Int64(BYTE_PER_QUAD_LOG2)));
621             // newDataMask <- (srcData << dstBitOffset);
622             GateRef newDataMask = Int64LSL(srcData, *dstBitOffset);
623             // newData <- dstData & zeroMask | newDataMask;
624             GateRef newData = Int64Or(Int64And(dstData, zeroMask), newDataMask);
625             // bitSet[dstQuad * 8] <- newData;
626             Store(VariableType::INT64(), glue_, dstBitSet, Int64LSL(*dstQuad, Int64(BYTE_PER_QUAD_LOG2)), newData);
627             Jump(&beforeEndLoop);
628         }
629         Bind(&beforeEndLoop);
630         {
631             // remainLength <- remainLength - bitsInCurrentQuad;
632             remainLength = Int64Sub(*remainLength, bitsInCurrentQuad);
633             //  srcBitOffset <- srcBitOffset + bitsInCurrentQuad;
634             srcBitOffset = Int64Add(*srcBitOffset, bitsInCurrentQuad);
635             //  dstBitOffset <- dstBitOffset + bitsInCurrentQuad;
636             dstBitOffset = Int64Add(*dstBitOffset, bitsInCurrentQuad);
637             Label srcAdd(env);
638             Label dstAdd(env);
639             Label checkDst(env);
640             BRANCH_NO_WEIGHT(Int64Equal(*srcBitOffset, Int64(BIT_PER_QUAD)), &srcAdd, &checkDst);
641             Bind(&srcAdd);
642             {
643                 //  if srcBitOffset == 64
644                 //  then srcQuad <- srcQuad + 1; srcBitOffset <- 0
645                 srcQuad = Int64Add(*srcQuad, Int64(1));
646                 srcBitOffset = Int64(0);
647                 Jump(&checkDst);
648             }
649             Bind(&checkDst);
650             BRANCH_NO_WEIGHT(Int64Equal(*dstBitOffset, Int64(BIT_PER_QUAD)), &dstAdd, &endLoop);
651             Bind(&dstAdd);
652             {
653                 // if dstBitOffset == 64
654                 // then dstQuad <- dstQuad + 1; dstBitOffset <- 0}
655                 dstQuad = Int64Add(*dstQuad, Int64(1));
656                 dstBitOffset = Int64(0);
657                 Jump(&endLoop);
658             }
659         }
660         Bind(&endLoop);
661         LoopEnd(&begin);
662     }
663     Bind(&exit);
664     env->SubCfgExit();
665 }
666 
BitSetRangeMoveBackward(GateRef srcBitSet,GateRef dstBitSet,GateRef srcStart,GateRef dstStart,GateRef length)667 void BarrierStubBuilder::BitSetRangeMoveBackward(GateRef srcBitSet, GateRef dstBitSet, GateRef srcStart,
668                                                  GateRef dstStart, GateRef length)
669 {
670     auto env = GetEnvironment();
671     Label entry(env);
672     env->SubCfgEntry(&entry);
673     Label exit(env);
674     DEFVARIABLE(remainLength, VariableType::INT64(), length);
675     // srcEnd <- srcStart + remainLength - 1;
676     // dstEnd <- dstStart + remainLength - 1;
677     DEFVARIABLE(srcEnd, VariableType::INT64(), Int64Sub(Int64Add(srcStart, length), Int64(1)));
678     DEFVARIABLE(dstEnd, VariableType::INT64(), Int64Sub(Int64Add(dstStart, length), Int64(1)));
679 
680     Label begin(env);
681     Label body(env);
682     Label endLoop(env);
683     Jump(&begin);
684     LoopBegin(&begin);
685     //  while remainLength > 0
686     BRANCH_LIKELY(Int64GreaterThan(*remainLength, Int64(0)), &body, &exit);
687     Bind(&body);
688     {
689         Label beforeEndLoop(env);
690         // srcBitOffset <- srcEnd % 64;
691         GateRef srcBitOffset = Int64And(*srcEnd, Int64(BIT_PER_QUAD_MASK));
692         // dstBitOffset <- dstEnd % 64;
693         GateRef dstBitOffset = Int64And(*dstEnd, Int64(BIT_PER_QUAD_MASK));
694         // bitsInCurrentQuad <- min of {srcBitOffset + 1, dstBitOffset + 1, remainLength};
695         GateRef bitsInCurrentQuad = ThreeInt64Min(Int64Add(srcBitOffset, Int64(1)),
696                                                   Int64Add(dstBitOffset, Int64(1)),
697                                                   *remainLength);
698         // srcQuadIndex <- srcEnd / 64;
699         GateRef srcQuadIndex = Int64LSR(*srcEnd, Int64(BIT_PER_QUAD_LOG2));
700         GateRef srcQuadData = LoadPrimitive(VariableType::INT64(), srcBitSet,
701             Int64LSL(srcQuadIndex, Int64(BYTE_PER_QUAD_LOG2)));
702         Label setValue(env);
703         BRANCH_NO_WEIGHT(Int64Equal(srcQuadData, Int64(0)), &beforeEndLoop, &setValue);
704         Bind(&setValue);
705         {
706             // mask <- 0xFFFFFFFFFFFFFFFF >> (64 - bitsInCurrentQuad);
707             GateRef mask = Int64LSR(Int64(ALL_ONE_MASK), Int64Sub(Int64(BIT_PER_QUAD), bitsInCurrentQuad));
708             //  srcData <- (srcBitSet[srcQuadIndex * 8] >> (srcBitOffset - bitsInCurrentQuad + 1)) & mask;
709             GateRef srcData = Int64And(
710                 Int64LSR(srcQuadData, Int64Add(Int64Sub(srcBitOffset, bitsInCurrentQuad), Int64(1))), mask);
711             // zeroMask <- ~(mask << (dstBitOffset - bitsInCurrentQuad + 1));
712             GateRef zeroMask = Int64Not(Int64LSL(mask, Int64Add(Int64Sub(dstBitOffset, bitsInCurrentQuad), Int64(1))));
713             // dstWordIndex <- dstEnd / 64;
714             GateRef dstQuadIndex = Int64LSR(*dstEnd, Int64(BIT_PER_QUAD_LOG2));
715             // dstData <- load from dstBitSet offset dstQuadIndex * 8
716             GateRef dstData = LoadPrimitive(VariableType::INT64(), dstBitSet,
717                 Int64LSL(dstQuadIndex, Int64(BYTE_PER_QUAD_LOG2)));
718             // newDataMask <- (srcData << (dstBitOffset - bitsInCurrentQuad + 1))
719             GateRef newDataMask = Int64LSL(srcData, Int64Add(Int64Sub(dstBitOffset, bitsInCurrentQuad), Int64(1)));
720             // newData <- dstData & zeroMask | newDataMask;
721             GateRef newData = Int64Or(Int64And(dstData, zeroMask), newDataMask);
722             // bitSet[dstQuadIndex * 8] <- newData;
723             Store(VariableType::INT64(), glue_, dstBitSet, Int64LSL(dstQuadIndex, Int64(BYTE_PER_QUAD_LOG2)), newData);
724             Jump(&beforeEndLoop);
725         }
726         Bind(&beforeEndLoop);
727         {
728             // remainLength <- remainLength - bitsInCurrentQuad;
729             remainLength = Int64Sub(*remainLength, bitsInCurrentQuad);
730             // srcEnd <- srcEnd - bitsInCurrentQuad;
731             srcEnd = Int64Sub(*srcEnd, bitsInCurrentQuad);
732             // dstEnd <- dstEnd - bitsInCurrentQuad;
733             dstEnd = Int64Sub(*dstEnd, bitsInCurrentQuad);
734             Jump(&endLoop);
735         }
736         Bind(&endLoop);
737         LoopEnd(&begin);
738     }
739     Bind(&exit);
740     env->SubCfgExit();
741 }
742 
DoReverseBarrier()743 void BarrierStubBuilder::DoReverseBarrier()
744 {
745     auto env = GetEnvironment();
746     Label entry(env);
747     Label exit(env);
748     Label checkNext(env);
749     Label needMarking(env);
750     Label notMarkRSet(env);
751     Label markInBuffer(env);
752     Label continueProcessing(env);
753     Label isTaggedObject(env);
754     Label RefisTaggedObject(env);
755     Label markRSet(env);
756     Label continueLoopHead(env);
757     Label continueLoopEnd(env);
758     Label notMarkRSetLoopHead(env);
759     Label notMarkRSetLoopEnd(env);
760     Label iLessLength(env);
761     Label indexLessLength(env);
762     Label notIdlePhase(env);
763     env->SubCfgEntry(&entry);
764 
765     BRANCH_UNLIKELY(LoadPrimitive(
766         VariableType::BOOL(), glue_, IntPtr(JSThread::GlueData::GetIsEnableCMCGCOffset(env->Is32Bit()))),
767         &needMarking, &checkNext);
768     Bind(&needMarking);
769     {
770         GateRef gcPhase = GetGCPhase(glue_);
771         GateRef objRegionType = GetCMCRegionType(dstObj_);
772         GateRef shouldProcessSATB = ShouldProcessSATB(gcPhase);
773         BRANCH(Int8Equal(gcPhase, Int8(common::GCPhase::GC_PHASE_IDLE)), &exit, &notIdlePhase);
774         Bind(&notIdlePhase);
775         {
776             BRANCH(CMCIsInYoungSpace(objRegionType), &notMarkRSet, &continueProcessing);
777             Bind(&continueProcessing);
778             {
779                 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
780                 Label checkOldToYoung(env);
781                 BRANCH(ShouldUpdateRememberSet(glue_, gcPhase), &checkOldToYoung, &notMarkRSet);
782                 Bind(&checkOldToYoung);
783                 Jump(&continueLoopHead);
784                 LoopBegin(&continueLoopHead);
785                 {
786                     BRANCH(Int32UnsignedLessThan(*i, slotCount_), &iLessLength, &notMarkRSet);
787                     Bind(&iLessLength);
788                     {
789                         GateRef offset = PtrMul(ZExtInt32ToPtr(*i), IntPtr(JSTaggedValue::TaggedTypeSize()));
790                         GateRef ref = LoadPrimitive(VariableType::JS_ANY(), dstAddr_, offset);
791                         BRANCH(TaggedIsHeapObject(ref), &isTaggedObject, &continueLoopEnd);
792                     }
793                     Bind(&isTaggedObject);
794                     MarkRSetCardTable(dstObj_, &notMarkRSet);
795                     Bind(&continueLoopEnd);
796                     i = Int32Add(*i, Int32(1));
797                     LoopEnd(&continueLoopHead);
798                 }
799             }
800             Bind(&notMarkRSet);
801             {
802                 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
803                 GateRef shouldProcessSATB = ShouldProcessSATB(gcPhase);
804                 Jump(&notMarkRSetLoopHead);
805                 LoopBegin(&notMarkRSetLoopHead);
806                 {
807                     BRANCH_LIKELY(Int32UnsignedLessThan(*index, slotCount_), &indexLessLength, &exit);
808                     Bind(&indexLessLength);
809                     GateRef offset = PtrMul(ZExtInt32ToPtr(*index), IntPtr(JSTaggedValue::TaggedTypeSize()));
810                     GateRef ref = LoadPrimitive(VariableType::JS_ANY(), dstAddr_, offset);
811                     BRANCH(TaggedIsHeapObject(ref), &RefisTaggedObject, &notMarkRSetLoopEnd);
812                     Bind(&RefisTaggedObject);
813                     BRANCH_UNLIKELY(shouldProcessSATB, &markInBuffer, &exit);
814                     Bind(&markInBuffer);
815                     {
816                         ASSERT(RuntimeStubCSigns::Get(RTSTUB_ID(MarkInBuffer))->IsNoTailCall());
817                         CallNGCRuntime(glue_, RTSTUB_ID(MarkInBuffer), {ref});
818                         Jump(&notMarkRSetLoopEnd);
819                     }
820 
821                     Bind(&notMarkRSetLoopEnd);
822                     index = Int32Add(*index, Int32(1));
823                     LoopEnd(&notMarkRSetLoopHead);
824                 }
825             }
826         }
827     }
828     Bind(&checkNext);
829     {
830         Label handleMark(env);
831         Label handleBitSet(env);
832         Label doReverse(env);
833         BRANCH_NO_WEIGHT(Int32Equal(slotCount_, Int32(0)), &exit, &doReverse);
834         Bind(&doReverse);
835         BRANCH_NO_WEIGHT(InSharedHeap(objectRegion_), &handleMark, &handleBitSet);
836         Bind(&handleBitSet);
837         {
838             DoReverseBarrierInternal();
839             Jump(&handleMark);
840         }
841         Bind(&handleMark);
842         HandleMark();
843         Jump(&exit);
844     }
845     Bind(&exit);
846     env->SubCfgExit();
847 }
848 
849 
DoReverseBarrierInternal()850 void BarrierStubBuilder::DoReverseBarrierInternal()
851 {
852     auto env = GetEnvironment();
853     Label entry(env);
854     env->SubCfgEntry(&entry);
855     Label exit(env);
856     Label inYoung(env);
857     Label inOld(env);
858     Label copyBitSet(env);
859 
860     DEFVARIABLE(bitSetAddr, VariableType::NATIVE_POINTER(), IntPtr(0));
861     DEFVARIABLE(bitSetAddr2, VariableType::NATIVE_POINTER(), IntPtr(0));
862 
863     GateRef localToShareOffset = IntPtr(Region::PackedData::GetLocalToShareSetOffset(env->Is32Bit()));
864     GateRef localToShareBitSetAddr =
865         GetBitSetDataAddr(objectRegion_, localToShareOffset, RTSTUB_ID(CreateLocalToShare));
866 
867     GateRef localToShareSwapped = IsLocalToShareSwapped(objectRegion_);
868     BRANCH_NO_WEIGHT(InYoungGeneration(objectRegion_), &inYoung, &inOld);
869     Bind(&inYoung);
870     {
871         Label batchBarrier(env);
872         Label reverseLocalToShare(env);
873         BRANCH_UNLIKELY(localToShareSwapped, &batchBarrier, &reverseLocalToShare);
874         Bind(&batchBarrier);
875         {
876             // slowpath, localToShareRSet is swapped, it can't be reversed, just set the bitset bit by bit.
877             BarrierBatchBitSet(LocalToShared);
878             Jump(&exit);
879         }
880         Bind(&reverseLocalToShare);
881         {
882             bitSetAddr = localToShareBitSetAddr;
883             Jump(&copyBitSet);
884         }
885     }
886     Bind(&inOld);
887     {
888         GateRef oldToNewOffset = IntPtr(Region::PackedData::GetOldToNewSetOffset(env->Is32Bit()));
889         GateRef oldToNewBitSetAddr = GetBitSetDataAddr(objectRegion_, oldToNewOffset, RTSTUB_ID(CreateOldToNew));
890         // CreateOldToNew may change the RSetFlag, so load it again.
891         GateRef oldToNewSwapped = IsOldToNewSwapped(objectRegion_);
892         Label batchBarrier(env);
893         Label tryBatchBarrier(env);
894         Label copyBoth(env);
895         // both localToShareSwapped and oldToNewSwapped are not swapped.
896         BRANCH_LIKELY(BitAnd(BoolNot(localToShareSwapped), BoolNot(oldToNewSwapped)), &copyBoth, &tryBatchBarrier);
897         Bind(&copyBoth);
898         {
899             bitSetAddr = localToShareBitSetAddr;
900             bitSetAddr2 = oldToNewBitSetAddr;
901             Jump(&copyBitSet);
902         }
903         Bind(&tryBatchBarrier);
904         {
905             Label reverseOne(env);
906             BRANCH_UNLIKELY(BitAnd(localToShareSwapped, oldToNewSwapped), &batchBarrier, &reverseOne);
907             Bind(&batchBarrier);
908             {
909                 // slowpath, localToShareRSet and oldToNewRSet are swapped,
910                 // it can't be reversed, just set the bitset bit by bit.
911                 BarrierBatchBitSet(LocalToShared | OldToNew);
912                 Jump(&exit);
913             }
914             Bind(&reverseOne);
915             {
916                 Label localToShareBatchBarrier(env);
917                 Label oldToNewBatchBarrier(env);
918                 BRANCH_NO_WEIGHT(localToShareSwapped, &localToShareBatchBarrier, &oldToNewBatchBarrier);
919                 Bind(&localToShareBatchBarrier);
920                 {
921                     // slowpath, localToShareRSet is swapped, it can't be reversed, just set the bitset bit by bit.
922                     // And copy oldToNewRSet.
923                     BarrierBatchBitSet(LocalToShared);
924                     bitSetAddr = oldToNewBitSetAddr;
925                     Jump(&copyBitSet);
926                 }
927                 Bind(&oldToNewBatchBarrier);
928                 {
929                     // slowpath, oldToNewRSet is swapped, it can't be reversed, just set the bitset bit by bit.
930                     // And copy localToShareRSet.
931                     BarrierBatchBitSet(OldToNew);
932                     bitSetAddr = localToShareBitSetAddr;
933                     Jump(&copyBitSet);
934                 }
935             }
936         }
937     }
938     Bind(&copyBitSet);
939     {
940         GateRef dstBitStartIdx = Int64LSR(Int64Sub(dstAddr_, objectRegion_), Int64(TAGGED_TYPE_SIZE_LOG));
941         Label begin(env);
942         Label endLoop(env);
943         Label next(env);
944         Jump(&begin);
945         LoopBegin(&begin);
946         {
947             BitSetRangeReverse(*bitSetAddr, dstBitStartIdx, ZExtInt32ToInt64(slotCount_));
948             BRANCH_UNLIKELY(IntPtrEqual(*bitSetAddr2, IntPtr(0)), &exit, &next);
949             Bind(&next);
950             {
951                 bitSetAddr = *bitSetAddr2;
952                 bitSetAddr2 = IntPtr(0);
953                 Jump(&endLoop);
954             }
955         }
956         Bind(&endLoop);
957         LoopEnd(&begin);
958     }
959     Bind(&exit);
960     env->SubCfgExit();
961 }
962 
BitSetRangeReverse(GateRef bitSet,GateRef startIdx,GateRef length)963 void BarrierStubBuilder::BitSetRangeReverse(GateRef bitSet, GateRef startIdx, GateRef length)
964 {
965     auto env = GetEnvironment();
966     Label entry(env);
967     env->SubCfgEntry(&entry);
968     Label exit(env);
969     // startOf <- startIdx % 64
970     GateRef startOf = Int64And(startIdx, Int64(BIT_PER_QUAD_MASK));
971     // endOf <- (startIdx + len) % 64
972     GateRef endOf = Int64And(Int64Add(startIdx, length), Int64(BIT_PER_QUAD_MASK));
973 
974     // startItemIndex <- startIdx / 64
975     GateRef startItemIndex = Int64LSR(startIdx, Int64(BIT_PER_QUAD_LOG2));
976     // endItemIndex <- (startIdx + len - 1) / 64
977     GateRef endItemIndex = Int64LSR(Int64Sub(Int64Add(startIdx, length), Int64(1)), Int64(BIT_PER_QUAD_LOG2));
978 
979     GateRef dstOffset = startIdx;
980     // srcOffset <- startIdx + ((64 - endOf) % 64 - startOf)
981     GateRef srcOffset = Int64Add(startIdx,
982         Int64Sub(Int64And(Int64Sub(Int64(BIT_PER_QUAD), endOf), Int64(BIT_PER_QUAD_MASK)), startOf));
983 
984     // startByteIndex <- startItemIndex * 8
985     GateRef startByteIndex = Int64LSL(startItemIndex, Int64(BIT_PER_BYTE_LOG2));
986     // endByteIndex <- endItemIndex * 8
987     GateRef endByteIndex = Int64LSL(endItemIndex, Int64(BIT_PER_BYTE_LOG2));
988 
989     GateRef startItem = LoadPrimitive(VariableType::INT64(), bitSet, startByteIndex);
990     GateRef endItem = LoadPrimitive(VariableType::INT64(), bitSet, endByteIndex);
991 
992     // startMask <- (1 << startOf) - 1
993     GateRef startMask = Int64Sub(Int64LSL(Int64(1), startOf), Int64(1));
994     Label notZero(env);
995     Label next(env);
996     DEFVARIABLE(endMask, VariableType::INT64(), Int64(0));
997     BRANCH_UNLIKELY(Int64Equal(endOf, Int64(0)), &next, &notZero);
998     Bind(&notZero);
999     {
1000         // endMask <- ~((1 << endOf) - 1)
1001         endMask = Int64Not(Int64Sub(Int64LSL(Int64(1), endOf), Int64(1)));
1002         Jump(&next);
1003     }
1004 
1005     Bind(&next);
1006     DEFVARIABLE(vstartByteIndex, VariableType::INT64(), startByteIndex);
1007     DEFVARIABLE(vendByteIndex, VariableType::INT64(), endByteIndex);
1008 
1009     Label loopBegin1(env);
1010     Label loopEnd1(env);
1011     Label loopExit1(env);
1012     Label startReverse(env);
1013     Jump(&loopBegin1);
1014     LoopBegin(&loopBegin1);
1015     {
1016         BRANCH_LIKELY(Int64LessThanOrEqual(*vstartByteIndex, *vendByteIndex), &startReverse, &loopExit1);
1017         Bind(&startReverse);
1018         {
1019             GateRef item1 = LoadPrimitive(VariableType::INT64(), bitSet, *vstartByteIndex);
1020             GateRef item2 = LoadPrimitive(VariableType::INT64(), bitSet, *vendByteIndex);
1021 
1022             // revStart <- Int64BitReverse(bitSet[vstartByteIndex])
1023             // revEnd <- Int64BitReverse(bitSet[vendByteIndex])
1024             GateRef revStart = Int64BitReverse(item1);
1025             GateRef revEnd = Int64BitReverse(item2);
1026 
1027             // bitSet[vstartByteIndex] <- revEnd
1028             // bitSet[vendByteIndex] <- revStart
1029             Store(VariableType::INT64(), glue_, bitSet, *vstartByteIndex, revEnd, MemoryAttribute::NoBarrier());
1030             Store(VariableType::INT64(), glue_, bitSet, *vendByteIndex, revStart, MemoryAttribute::NoBarrier());
1031 
1032             // vstartByteIndex <- vstartByteIndex + 8
1033             // vendByteIndex <- vendByteIndex - 8
1034             vstartByteIndex = Int64Add(*vstartByteIndex, Int64(BYTE_PER_QUAD));
1035             vendByteIndex = Int64Sub(*vendByteIndex, Int64(BYTE_PER_QUAD));
1036             Jump(&loopEnd1);
1037         }
1038     }
1039     Bind(&loopEnd1);
1040     LoopEnd(&loopBegin1);
1041     Bind(&loopExit1);
1042     BitSetRangeMove(bitSet, bitSet, srcOffset, dstOffset, length);
1043 
1044     GateRef neStartMask = Int64Not(startMask);
1045     GateRef neEndMask = Int64Not(*endMask);
1046 
1047     // bitSet[startByteIndex] <- (startItem & startMask) | (startItem1 & neStartMask);
1048     GateRef startItem1 = LoadPrimitive(VariableType::INT64(), bitSet, startByteIndex);
1049     GateRef resStartItem = Int64Or(Int64And(startItem, startMask), Int64And(startItem1, neStartMask));
1050     Store(VariableType::INT64(), glue_, bitSet, startByteIndex, resStartItem, MemoryAttribute::NoBarrier());
1051 
1052     // bitSet[endByteIndex] <- (resEndItem & endMask) | (endItem1 & neEndMask);
1053     GateRef endItem1 = LoadPrimitive(VariableType::INT64(), bitSet, endByteIndex);
1054     GateRef resEndItem = Int64Or(Int64And(endItem, *endMask), Int64And(endItem1, neEndMask));
1055     Store(VariableType::INT64(), glue_, bitSet, endByteIndex, resEndItem, MemoryAttribute::NoBarrier());
1056     Jump(&exit);
1057     Bind(&exit);
1058     env->SubCfgExit();
1059 }
1060 
IsLocalToShareSwapped(GateRef region)1061 GateRef BarrierStubBuilder::IsLocalToShareSwapped(GateRef region)
1062 {
1063     auto env = GetEnvironment();
1064     GateRef RSetSwapFlagOffset = IntPtr(Region::PackedData::GetRSetSwapFlagOffset(env->Is32Bit()));
1065     GateRef RSetFlag = LoadPrimitive(VariableType::INT8(), region, RSetSwapFlagOffset);
1066     return NotEqual(Int8And(RSetFlag, Int8(LOCAL_TO_SHARE_SWAPPED_MASK)), Int8(0));
1067 }
1068 
IsOldToNewSwapped(GateRef region)1069 GateRef BarrierStubBuilder::IsOldToNewSwapped(GateRef region)
1070 {
1071     auto env = GetEnvironment();
1072     GateRef RSetSwapFlagOffset = IntPtr(Region::PackedData::GetRSetSwapFlagOffset(env->Is32Bit()));
1073     GateRef RSetFlag = LoadPrimitive(VariableType::INT8(), region, RSetSwapFlagOffset);
1074     return NotEqual(Int8And(RSetFlag, Int8(OLD_TO_NEW_SWAPPED_MASK)), Int8(0));
1075 }
1076 }
1077