1 /*
2 * Copyright (c) 2023 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/post_schedule.h"
17
18
19 #include "ecmascript/compiler/circuit_builder-inl.h"
20
21 namespace panda::ecmascript::kungfu {
Run(ControlFlowGraph & cfg)22 void PostSchedule::Run(ControlFlowGraph &cfg)
23 {
24 GenerateExtraBB(cfg);
25
26 if (IsLogEnabled()) {
27 LOG_COMPILER(INFO) << "";
28 LOG_COMPILER(INFO) << "\033[34m"
29 << "===================="
30 << " After post schedule "
31 << "[" << GetMethodName() << "]"
32 << "===================="
33 << "\033[0m";
34 PrintGraph("Build extra basic block for scheduled gates", cfg);
35 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
36 }
37 }
38
GenerateExtraBB(ControlFlowGraph & cfg)39 void PostSchedule::GenerateExtraBB(ControlFlowGraph &cfg)
40 {
41 size_t bbNum = cfg.size();
42 size_t bbIdx = 0;
43 while (bbIdx < bbNum) {
44 const std::vector<GateRef>& bb = cfg.at(bbIdx);
45 size_t instNum = bb.size();
46 size_t instIdx = 0;
47 while (instIdx < instNum) {
48 const std::vector<GateRef>& currentBB = cfg.at(bbIdx);
49 GateRef current = currentBB[instIdx];
50 OpCode opcode = acc_.GetOpCode(current);
51 bool needRetraverse = false;
52 switch (opcode) {
53 case OpCode::HEAP_ALLOC: {
54 needRetraverse = VisitHeapAlloc(current, cfg, bbIdx, instIdx);
55 break;
56 }
57 case OpCode::STORE: {
58 needRetraverse = VisitStore(current, cfg, bbIdx, instIdx);
59 break;
60 }
61 default: {
62 break;
63 }
64 }
65 const std::vector<GateRef>& refreshedBB = cfg.at(bbIdx);
66 instNum = refreshedBB.size();
67 instIdx = needRetraverse ? 0 : (instIdx + 1);
68 }
69 bbNum = cfg.size();
70 bbIdx++;
71 }
72 }
73
VisitHeapAlloc(GateRef gate,ControlFlowGraph & cfg,size_t bbIdx,size_t instIdx)74 bool PostSchedule::VisitHeapAlloc(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
75 {
76 int64_t flag = static_cast<int64_t>(acc_.TryGetValue(gate));
77 ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE ||
78 flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE ||
79 flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE ||
80 flag == RegionSpaceFlag::IN_OLD_SPACE);
81 std::vector<GateRef> currentBBGates;
82 std::vector<GateRef> successBBGates;
83 std::vector<GateRef> failBBGates;
84 std::vector<GateRef> endBBGates;
85 if (flag == RegionSpaceFlag::IN_OLD_SPACE) {
86 LoweringHeapAllocate(gate, currentBBGates, successBBGates, failBBGates, endBBGates, flag);
87 ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
88 return false;
89 } else {
90 LoweringHeapAllocAndPrepareScheduleGate(gate, currentBBGates, successBBGates, failBBGates, endBBGates, flag);
91 }
92 #ifdef ARK_ASAN_ON
93 ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
94 return false;
95 #else
96 ReplaceBBState(cfg, bbIdx, currentBBGates, endBBGates);
97 ScheduleEndBB(endBBGates, cfg, bbIdx, instIdx);
98 ScheduleNewBB(successBBGates, cfg, bbIdx);
99 ScheduleNewBB(failBBGates, cfg, bbIdx);
100 ScheduleCurrentBB(currentBBGates, cfg, bbIdx, instIdx);
101 return true;
102 #endif
103 }
104
ReplaceGateDirectly(std::vector<GateRef> & gates,ControlFlowGraph & cfg,size_t bbIdx,size_t instIdx)105 void PostSchedule::ReplaceGateDirectly(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
106 {
107 std::vector<GateRef>& bb = cfg.at(bbIdx);
108 bb.insert(bb.begin() + instIdx, gates.begin(), gates.end());
109 bb.erase(bb.begin() + instIdx + gates.size());
110 }
111
ScheduleEndBB(std::vector<GateRef> & gates,ControlFlowGraph & cfg,size_t bbIdx,size_t instIdx)112 void PostSchedule::ScheduleEndBB(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
113 {
114 std::vector<GateRef>& bb = cfg.at(bbIdx);
115 if (instIdx > 0) {
116 gates.insert(gates.begin() + 1, bb.begin(), bb.begin() + instIdx); // 1: after state gate
117 }
118 cfg.insert(cfg.begin() + bbIdx + 1, std::move(gates)); // 1: after current bb
119 }
120
ScheduleNewBB(std::vector<GateRef> & gates,ControlFlowGraph & cfg,size_t bbIdx)121 void PostSchedule::ScheduleNewBB(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx)
122 {
123 if (!gates.empty()) {
124 cfg.insert(cfg.begin() + bbIdx + 1, std::move(gates));
125 }
126 }
127
ScheduleCurrentBB(const std::vector<GateRef> & gates,ControlFlowGraph & cfg,size_t bbIdx,size_t instIdx)128 void PostSchedule::ScheduleCurrentBB(const std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx,
129 size_t instIdx)
130 {
131 std::vector<GateRef>& bb = cfg.at(bbIdx);
132 if (instIdx == 0) {
133 bb.erase(bb.begin());
134 } else {
135 bb.erase(bb.begin(), bb.begin() + instIdx + 1); // 1: include current gate
136 }
137 bb.insert(bb.begin(), gates.begin(), gates.end());
138 }
139
PrepareToScheduleNewGate(GateRef gate,std::vector<GateRef> & gates)140 void PostSchedule::PrepareToScheduleNewGate(GateRef gate, std::vector<GateRef> &gates)
141 {
142 gates.emplace_back(gate);
143 }
144
ReplaceBBState(ControlFlowGraph & cfg,size_t bbIdx,std::vector<GateRef> & currentBBGates,std::vector<GateRef> & endBBGates)145 void PostSchedule::ReplaceBBState(ControlFlowGraph &cfg, size_t bbIdx, std::vector<GateRef> ¤tBBGates,
146 std::vector<GateRef> &endBBGates)
147 {
148 GateRef floatBranch = currentBBGates[0];
149 ASSERT(acc_.GetOpCode(floatBranch) == OpCode::IF_BRANCH);
150 GateRef endBBState = endBBGates[0];
151 ASSERT(acc_.GetOpCode(endBBState) == OpCode::MERGE);
152 std::vector<GateRef>& bb = cfg.at(bbIdx);
153 GateRef currentBBState = bb[0];
154 ASSERT(acc_.IsState(currentBBState));
155
156 OpCode opcode = acc_.GetOpCode(currentBBState);
157 switch (opcode) {
158 case OpCode::DEOPT_CHECK:
159 case OpCode::RETURN:
160 case OpCode::RETURN_VOID:
161 case OpCode::IF_BRANCH:
162 case OpCode::SWITCH_BRANCH: {
163 GateRef stateIn = acc_.GetState(currentBBState, 0);
164 acc_.ReplaceStateIn(floatBranch, stateIn);
165 acc_.ReplaceStateIn(currentBBState, endBBState);
166 break;
167 }
168 case OpCode::STATE_ENTRY:
169 case OpCode::ORDINARY_BLOCK:
170 case OpCode::IF_TRUE:
171 case OpCode::IF_FALSE:
172 case OpCode::SWITCH_CASE:
173 case OpCode::DEFAULT_CASE:
174 case OpCode::MERGE:
175 case OpCode::LOOP_BEGIN:
176 case OpCode::LOOP_BACK: {
177 acc_.ReplaceControlGate(currentBBState, endBBState);
178 acc_.ReplaceStateIn(floatBranch, currentBBState);
179 currentBBGates.insert(currentBBGates.begin(), currentBBState);
180 bb[0] = builder_.Nop();
181 break;
182 }
183 default: {
184 LOG_ECMA(FATAL) << "this branch is unreachable with opcode:" << opcode;
185 UNREACHABLE();
186 }
187 }
188 }
189
LoweringHeapAllocAndPrepareScheduleGate(GateRef gate,std::vector<GateRef> & currentBBGates,std::vector<GateRef> & successBBGates,std::vector<GateRef> & failBBGates,std::vector<GateRef> & endBBGates,int64_t flag)190 void PostSchedule::LoweringHeapAllocAndPrepareScheduleGate(GateRef gate,
191 std::vector<GateRef> ¤tBBGates,
192 std::vector<GateRef> &successBBGates,
193 std::vector<GateRef> &failBBGates,
194 std::vector<GateRef> &endBBGates,
195 [[maybe_unused]] int64_t flag)
196 {
197 #ifdef ARK_ASAN_ON
198 LoweringHeapAllocate(gate, currentBBGates, successBBGates, failBBGates, endBBGates, flag);
199 #else
200 Environment env(gate, circuit_, &builder_);
201 Label exit(&builder_);
202 GateRef glue = acc_.GetValueIn(gate, 0);
203 GateRef size = acc_.GetValueIn(gate, 1);
204 GateRef hole = circuit_->GetConstantGateWithoutCache(
205 MachineType::I64, JSTaggedValue::VALUE_HOLE, GateType::TaggedValue());
206 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), hole);
207 Label success(&builder_);
208 Label callRuntime(&builder_);
209 size_t topOffset;
210 size_t endOffset;
211 if (flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE) {
212 topOffset = JSThread::GlueData::GetSOldSpaceAllocationTopAddressOffset(false);
213 endOffset = JSThread::GlueData::GetSOldSpaceAllocationEndAddressOffset(false);
214 } else if (flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE) {
215 topOffset = JSThread::GlueData::GetSNonMovableSpaceAllocationTopAddressOffset(false);
216 endOffset = JSThread::GlueData::GetSNonMovableSpaceAllocationEndAddressOffset(false);
217 } else {
218 ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE);
219 topOffset = JSThread::GlueData::GetNewSpaceAllocationTopAddressOffset(false);
220 endOffset = JSThread::GlueData::GetNewSpaceAllocationEndAddressOffset(false);
221 }
222 GateRef topAddrOffset = circuit_->GetConstantGateWithoutCache(MachineType::I64, topOffset, GateType::NJSValue());
223 GateRef endAddrOffset = circuit_->GetConstantGateWithoutCache(MachineType::I64, endOffset, GateType::NJSValue());
224 GateRef topAddrAddr = builder_.PtrAdd(glue, topAddrOffset);
225 GateRef endAddrAddr = builder_.PtrAdd(glue, endAddrOffset);
226 GateRef topAddress = builder_.Load(VariableType::NATIVE_POINTER(), topAddrAddr);
227 GateRef endAddress = builder_.Load(VariableType::NATIVE_POINTER(), endAddrAddr);
228 GateRef addrOffset = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
229 GateRef rawTopAddr = builder_.PtrAdd(topAddress, addrOffset);
230 GateRef rawEndAddr = builder_.PtrAdd(endAddress, addrOffset);
231 GateRef top = builder_.Load(VariableType::JS_POINTER(), rawTopAddr);
232 GateRef end = builder_.Load(VariableType::JS_POINTER(), rawEndAddr);
233
234 GateRef newTop = builder_.PtrAdd(top, size);
235 GateRef condition = builder_.Int64GreaterThan(newTop, end);
236 Label *currentLabel = env.GetCurrentLabel();
237 BRANCH_CIR(condition, &callRuntime, &success);
238 {
239 GateRef ifBranch = currentLabel->GetControl();
240 PrepareToScheduleNewGate(ifBranch, currentBBGates);
241 PrepareToScheduleNewGate(condition, currentBBGates);
242 PrepareToScheduleNewGate(newTop, currentBBGates);
243 PrepareToScheduleNewGate(end, currentBBGates);
244 PrepareToScheduleNewGate(top, currentBBGates);
245 PrepareToScheduleNewGate(rawEndAddr, currentBBGates);
246 PrepareToScheduleNewGate(rawTopAddr, currentBBGates);
247 PrepareToScheduleNewGate(topAddress, currentBBGates);
248 PrepareToScheduleNewGate(endAddress, currentBBGates);
249 PrepareToScheduleNewGate(addrOffset, currentBBGates);
250 PrepareToScheduleNewGate(topAddrAddr, currentBBGates);
251 PrepareToScheduleNewGate(endAddrAddr, currentBBGates);
252 PrepareToScheduleNewGate(topAddrOffset, currentBBGates);
253 PrepareToScheduleNewGate(endAddrOffset, currentBBGates);
254 PrepareToScheduleNewGate(hole, currentBBGates);
255 }
256 builder_.Bind(&success);
257 {
258 GateRef ifFalse = builder_.GetState();
259 GateRef addr = builder_.PtrAdd(topAddress, addrOffset);
260 builder_.StoreWithoutBarrier(VariableType::NATIVE_POINTER(), addr, newTop);
261 GateRef store = builder_.GetDepend();
262 result = top;
263 builder_.Jump(&exit);
264 {
265 GateRef ordinaryBlock = success.GetControl();
266 PrepareToScheduleNewGate(ordinaryBlock, successBBGates);
267 PrepareToScheduleNewGate(store, successBBGates);
268 PrepareToScheduleNewGate(addr, successBBGates);
269 PrepareToScheduleNewGate(ifFalse, successBBGates);
270 }
271 }
272 builder_.Bind(&callRuntime);
273 {
274 GateRef ifTrue = builder_.GetState();
275 GateRef taggedIntMask = circuit_->GetConstantGateWithoutCache(
276 MachineType::I64, JSTaggedValue::TAG_INT, GateType::NJSValue());
277 GateRef taggedSize = builder_.Int64Or(size, taggedIntMask);
278 GateRef target = Circuit::NullGate();
279 if (flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE) {
280 target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, RTSTUB_ID(AllocateInSOld),
281 GateType::NJSValue());
282 } else if (flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE) {
283 target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, RTSTUB_ID(AllocateInSNonMovable),
284 GateType::NJSValue());
285 } else {
286 ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE);
287 target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, RTSTUB_ID(AllocateInYoung),
288 GateType::NJSValue());
289 }
290 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
291 ASSERT(cs->IsRuntimeStub());
292 GateRef reseverdFrameArgs = Circuit::NullGate();
293 GateRef reseverdPc = Circuit::NullGate();
294 std::vector<GateRef> args { taggedSize };
295 // keep same with CircuitBuilder::Call: only when condition is true, we pass the other two args.
296 if (builder_.GetCircuit()->IsOptimizedOrFastJit()) {
297 reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
298 reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
299 args.push_back(reseverdFrameArgs);
300 args.push_back(reseverdPc);
301 }
302 // here in order to schedule all the intermediate value,
303 // frameargs and pcoffset are solved out from CircuitBuilder::Call,
304 // so hirGate must be NullGate to prevent duplicated operation.
305 GateRef slowResult = builder_.Call(cs, glue, target, builder_.GetDepend(),
306 args, Circuit::NullGate(), "Heap alloc");
307 result = slowResult;
308 builder_.Jump(&exit);
309 {
310 GateRef ordinaryBlock = callRuntime.GetControl();
311 PrepareToScheduleNewGate(ordinaryBlock, failBBGates);
312 PrepareToScheduleNewGate(slowResult, failBBGates);
313 PrepareToScheduleNewGate(target, failBBGates);
314 PrepareToScheduleNewGate(taggedSize, failBBGates);
315 if (builder_.GetCircuit()->IsOptimizedOrFastJit()) {
316 PrepareToScheduleNewGate(reseverdFrameArgs, failBBGates);
317 PrepareToScheduleNewGate(reseverdPc, failBBGates);
318 }
319 PrepareToScheduleNewGate(taggedIntMask, failBBGates);
320 PrepareToScheduleNewGate(ifTrue, failBBGates);
321 }
322 }
323 builder_.Bind(&exit);
324 {
325 GateRef merge = builder_.GetState();
326 GateRef phi = *result;
327 PrepareToScheduleNewGate(merge, endBBGates);
328 PrepareToScheduleNewGate(phi, endBBGates);
329 }
330 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
331 #endif
332 }
333
LoweringHeapAllocate(GateRef gate,std::vector<GateRef> & currentBBGates,std::vector<GateRef> & successBBGates,std::vector<GateRef> & failBBGates,std::vector<GateRef> & endBBGates,int64_t flag)334 void PostSchedule::LoweringHeapAllocate(GateRef gate,
335 std::vector<GateRef> ¤tBBGates,
336 std::vector<GateRef> &successBBGates,
337 std::vector<GateRef> &failBBGates,
338 std::vector<GateRef> &endBBGates,
339 int64_t flag)
340 {
341 Environment env(gate, circuit_, &builder_);
342 (void)successBBGates;
343 (void)failBBGates;
344 (void)endBBGates;
345 GateRef glue = acc_.GetValueIn(gate, 0);
346 GateRef size = acc_.GetValueIn(gate, 1);
347 GateRef taggedIntMask = circuit_->GetConstantGateWithoutCache(
348 MachineType::I64, JSTaggedValue::TAG_INT, GateType::NJSValue());
349 GateRef taggedSize = builder_.Int64Or(size, taggedIntMask);
350 auto id = RTSTUB_ID(AllocateInYoung);
351 if (flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE) {
352 id = RTSTUB_ID(AllocateInSOld);
353 } else if (flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE) {
354 id = RTSTUB_ID(AllocateInSNonMovable);
355 } else if (flag == RegionSpaceFlag::IN_OLD_SPACE) {
356 id = RTSTUB_ID(AllocateInOld);
357 } else {
358 ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE);
359 }
360 GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, id, GateType::NJSValue());
361 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
362 ASSERT(cs->IsRuntimeStub());
363 GateRef reseverdFrameArgs = Circuit::NullGate();
364 GateRef reseverdPc = Circuit::NullGate();
365 std::vector<GateRef> args { taggedSize };
366 // keep same with CircuitBuilder::Call: only when condition is true, we pass the other two args.
367 if (builder_.GetCircuit()->IsOptimizedOrFastJit()) {
368 reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
369 reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
370 args.push_back(reseverdFrameArgs);
371 args.push_back(reseverdPc);
372 }
373 // here in order to schedule all the intermediate value,
374 // frameargs and pcoffset are solved out from CircuitBuilder::Call,
375 // so hirGate must be NullGate to prevent duplicated operation.
376 GateRef result = builder_.Call(cs, glue, target, builder_.GetDepend(), args, Circuit::NullGate(), "Heap alloc");
377 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
378
379 // Must keep the order of value-in/depend-in
380 PrepareToScheduleNewGate(result, currentBBGates);
381 PrepareToScheduleNewGate(target, currentBBGates);
382 PrepareToScheduleNewGate(taggedSize, currentBBGates);
383 if (builder_.GetCircuit()->IsOptimizedOrFastJit()) {
384 PrepareToScheduleNewGate(reseverdFrameArgs, currentBBGates);
385 PrepareToScheduleNewGate(reseverdPc, currentBBGates);
386 }
387 PrepareToScheduleNewGate(taggedIntMask, currentBBGates);
388 return;
389 }
390
VisitStore(GateRef gate,ControlFlowGraph & cfg,size_t bbIdx,size_t instIdx)391 bool PostSchedule::VisitStore(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
392 {
393 std::vector<GateRef> currentBBGates;
394 std::vector<GateRef> barrierBBGates;
395 std::vector<GateRef> endBBGates;
396 MemoryAttribute::Barrier kind = GetWriteBarrierKind(gate);
397 switch (kind) {
398 case MemoryAttribute::Barrier::UNKNOWN_BARRIER: {
399 LoweringStoreUnknownBarrierAndPrepareScheduleGate(gate, currentBBGates, barrierBBGates, endBBGates);
400 ReplaceBBState(cfg, bbIdx, currentBBGates, endBBGates);
401 ScheduleEndBB(endBBGates, cfg, bbIdx, instIdx);
402 ScheduleNewBB(barrierBBGates, cfg, bbIdx);
403 ScheduleCurrentBB(currentBBGates, cfg, bbIdx, instIdx);
404 return true;
405 }
406 case MemoryAttribute::Barrier::NEED_BARRIER: {
407 LoweringStoreWithBarrierAndPrepareScheduleGate(gate, currentBBGates);
408 ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
409 return false;
410 }
411 case MemoryAttribute::Barrier::NO_BARRIER: {
412 LoweringStoreNoBarrierAndPrepareScheduleGate(gate, currentBBGates);
413 ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
414 return false;
415 }
416 default: {
417 UNREACHABLE();
418 return false;
419 }
420 }
421 return false;
422 }
423
GetWriteBarrierKind(GateRef gate)424 MemoryAttribute::Barrier PostSchedule::GetWriteBarrierKind(GateRef gate)
425 {
426 MemoryAttribute mAttr = acc_.GetMemoryAttribute(gate);
427 if (!acc_.IsGCRelated(gate)) {
428 return MemoryAttribute::Barrier::NO_BARRIER;
429 }
430 return mAttr.GetBarrier();
431 }
432
SelectBarrier(MemoryAttribute::ShareFlag share,const CallSignature * & cs,std::string_view & comment)433 int PostSchedule::SelectBarrier(MemoryAttribute::ShareFlag share, const CallSignature*& cs, std::string_view& comment)
434 {
435 int index = 0;
436 switch (share) {
437 case MemoryAttribute::UNKNOWN:
438 if (fastBarrier_) {
439 index = RuntimeStubCSigns::ID_ASMFastWriteBarrier;
440 cs = RuntimeStubCSigns::Get(index);
441 comment = "asm store barrier\0";
442 } else {
443 index = CommonStubCSigns::SetValueWithBarrier;
444 cs = CommonStubCSigns::Get(index);
445 comment = "store barrier\0";
446 }
447 break;
448 case MemoryAttribute::SHARED:
449 index = CommonStubCSigns::SetSValueWithBarrier;
450 cs = CommonStubCSigns::Get(index);
451 comment = "store share barrier\0";
452 break;
453 case MemoryAttribute::NON_SHARE:
454 index = CommonStubCSigns::SetNonSValueWithBarrier;
455 cs = CommonStubCSigns::Get(index);
456 comment = "store not share barrier\0";
457 break;
458 default:
459 UNREACHABLE();
460 }
461 return index;
462 }
463
LoweringStoreNoBarrierAndPrepareScheduleGate(GateRef gate,std::vector<GateRef> & currentBBGates)464 void PostSchedule::LoweringStoreNoBarrierAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> ¤tBBGates)
465 {
466 Environment env(gate, circuit_, &builder_);
467
468 GateRef base = acc_.GetValueIn(gate, 1); // 1: object
469 GateRef offset = acc_.GetValueIn(gate, 2); // 2: offset
470 GateRef value = acc_.GetValueIn(gate, 3); // 3: value
471 GateRef addr = builder_.PtrAdd(base, offset);
472 VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate));
473 builder_.StoreWithoutBarrier(type, addr, value, acc_.GetMemoryAttribute(gate));
474 GateRef store = builder_.GetDepend();
475 {
476 PrepareToScheduleNewGate(store, currentBBGates);
477 PrepareToScheduleNewGate(addr, currentBBGates);
478 }
479 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
480 }
481
GetShareKind(panda::ecmascript::kungfu::GateRef gate)482 MemoryAttribute::ShareFlag PostSchedule::GetShareKind(panda::ecmascript::kungfu::GateRef gate)
483 {
484 MemoryAttribute mAttr = acc_.GetMemoryAttribute(gate);
485 return mAttr.GetShare();
486 }
487
LoweringStoreWithBarrierAndPrepareScheduleGate(GateRef gate,std::vector<GateRef> & currentBBGates)488 void PostSchedule::LoweringStoreWithBarrierAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> ¤tBBGates)
489 {
490 Environment env(gate, circuit_, &builder_);
491
492 GateRef glue = acc_.GetValueIn(gate, 0);
493 GateRef base = acc_.GetValueIn(gate, 1); // 1: object
494 GateRef offset = acc_.GetValueIn(gate, 2); // 2: offset
495 GateRef value = acc_.GetValueIn(gate, 3); // 3: value
496 GateRef addr = builder_.PtrAdd(base, offset);
497 VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate));
498 builder_.StoreWithoutBarrier(type, addr, value, acc_.GetMemoryAttribute(gate));
499 GateRef store = builder_.GetDepend();
500 MemoryAttribute::ShareFlag share = GetShareKind(gate);
501 std::string_view comment;
502 int index;
503 const CallSignature* cs = nullptr;
504 index = SelectBarrier(share, cs, comment);
505 ASSERT(cs && (cs->IsCommonStub() || cs->IsASMCallBarrierStub()) && "Invalid call signature for barrier");
506 GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, index, GateType::NJSValue());
507 GateRef reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
508 GateRef reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
509 GateRef storeBarrier = builder_.Call(cs, glue, target, builder_.GetDepend(),
510 {glue, base, offset, value, reseverdFrameArgs, reseverdPc},
511 Circuit::NullGate(), comment.data());
512 {
513 PrepareToScheduleNewGate(storeBarrier, currentBBGates);
514 PrepareToScheduleNewGate(reseverdPc, currentBBGates);
515 PrepareToScheduleNewGate(reseverdFrameArgs, currentBBGates);
516 PrepareToScheduleNewGate(target, currentBBGates);
517 PrepareToScheduleNewGate(store, currentBBGates);
518 PrepareToScheduleNewGate(addr, currentBBGates);
519 }
520 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
521 }
522
LoweringStoreUnknownBarrierAndPrepareScheduleGate(GateRef gate,std::vector<GateRef> & currentBBGates,std::vector<GateRef> & barrierBBGates,std::vector<GateRef> & endBBGates)523 void PostSchedule::LoweringStoreUnknownBarrierAndPrepareScheduleGate(GateRef gate,
524 std::vector<GateRef> ¤tBBGates,
525 std::vector<GateRef> &barrierBBGates,
526 std::vector<GateRef> &endBBGates)
527 {
528 Environment env(gate, circuit_, &builder_);
529
530 GateRef glue = acc_.GetValueIn(gate, 0);
531 GateRef base = acc_.GetValueIn(gate, 1); // 1: object
532 GateRef offset = acc_.GetValueIn(gate, 2); // 2: offset
533 GateRef value = acc_.GetValueIn(gate, 3); // 3: value
534 GateRef addr = builder_.PtrAdd(base, offset);
535 VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate));
536 builder_.StoreWithoutBarrier(type, addr, value, acc_.GetMemoryAttribute(gate));
537 GateRef store = builder_.GetDepend();
538
539 GateRef intVal = builder_.ChangeTaggedPointerToInt64(value);
540 GateRef objMask = circuit_->GetConstantGateWithoutCache(
541 MachineType::I64, JSTaggedValue::TAG_HEAPOBJECT_MASK, GateType::NJSValue());
542 GateRef masked = builder_.Int64And(intVal, objMask, GateType::Empty(), "checkHeapObject");
543 GateRef falseVal = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
544 GateRef condition = builder_.Equal(masked, falseVal, "checkHeapObject");
545 Label exit(&builder_);
546 Label isHeapObject(&builder_);
547 Label *currentLabel = env.GetCurrentLabel();
548 BRANCH_CIR(condition, &isHeapObject, &exit);
549 {
550 GateRef ifBranch = currentLabel->GetControl();
551 PrepareToScheduleNewGate(ifBranch, currentBBGates);
552 PrepareToScheduleNewGate(condition, currentBBGates);
553 PrepareToScheduleNewGate(falseVal, currentBBGates);
554 PrepareToScheduleNewGate(masked, currentBBGates);
555 PrepareToScheduleNewGate(intVal, currentBBGates);
556 PrepareToScheduleNewGate(objMask, currentBBGates);
557 PrepareToScheduleNewGate(store, currentBBGates);
558 PrepareToScheduleNewGate(addr, currentBBGates);
559 }
560 GateRef ifTrue = isHeapObject.GetControl();
561 GateRef ifFalse = exit.GetControl();
562 builder_.Bind(&isHeapObject);
563 {
564 MemoryAttribute::ShareFlag share = GetShareKind(gate);
565 std::string_view comment;
566 int index;
567 const CallSignature* cs = nullptr;
568 index = SelectBarrier(share, cs, comment);
569 ASSERT(cs && (cs->IsCommonStub() || cs->IsASMCallBarrierStub()) && "Invalid call signature for barrier");
570 GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, index, GateType::NJSValue());
571 GateRef reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
572 GateRef reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
573 #ifndef NDEBUG
574 GateRef verifyTarget = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, CommonStubCSigns::VerifyBarrier,
575 GateType::NJSValue());
576 const CallSignature* verifyBarrierCs = CommonStubCSigns::Get(CommonStubCSigns::VerifyBarrier);
577 GateRef verifyBarrier = builder_.Call(verifyBarrierCs, glue, verifyTarget, builder_.GetDepend(),
578 {glue, base, offset, value, reseverdFrameArgs, reseverdPc},
579 Circuit::NullGate(), "verify barrier");
580 #endif
581 GateRef storeBarrier = builder_.Call(cs, glue, target, builder_.GetDepend(),
582 { glue, base, offset, value, reseverdFrameArgs, reseverdPc },
583 Circuit::NullGate(), comment.data());
584 builder_.Jump(&exit);
585 {
586 GateRef ordinaryBlock = isHeapObject.GetControl();
587 PrepareToScheduleNewGate(ordinaryBlock, barrierBBGates);
588 PrepareToScheduleNewGate(storeBarrier, barrierBBGates);
589 #ifndef NDEBUG
590 PrepareToScheduleNewGate(verifyBarrier, barrierBBGates);
591 #endif
592 PrepareToScheduleNewGate(reseverdFrameArgs, barrierBBGates);
593 PrepareToScheduleNewGate(reseverdPc, barrierBBGates);
594 PrepareToScheduleNewGate(ifTrue, barrierBBGates);
595 }
596 }
597 builder_.Bind(&exit);
598 {
599 GateRef merge = builder_.GetState();
600 PrepareToScheduleNewGate(merge, endBBGates);
601 PrepareToScheduleNewGate(ifFalse, endBBGates);
602 }
603 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
604 }
605
PrintGraph(const char * title,ControlFlowGraph & cfg)606 void PostSchedule::PrintGraph(const char* title, ControlFlowGraph &cfg)
607 {
608 LOG_COMPILER(INFO) << "======================== " << title << " ========================";
609 for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) {
610 LOG_COMPILER(INFO) << "B" << bbIdx << ":";
611 const std::vector<GateRef>& bb = cfg.at(bbIdx);
612 for (size_t instIdx = 0; instIdx < bb.size(); instIdx++) {
613 GateRef gate = bb[instIdx];
614 acc_.Print(gate);
615 }
616 LOG_COMPILER(INFO) << "";
617 }
618 }
619 } // namespace panda::ecmascript::kungfu
620