• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/hcr_circuit_builder.h"
17 #include "ecmascript/compiler/common_stubs.h"
18 #include "ecmascript/js_thread.h"
19 
20 namespace panda::ecmascript::kungfu {
21 
NoLabelCallRuntime(GateRef glue,GateRef depend,size_t index,std::vector<GateRef> & args,GateRef hirGate)22 GateRef CircuitBuilder::NoLabelCallRuntime(GateRef glue, GateRef depend, size_t index, std::vector<GateRef> &args,
23                                            GateRef hirGate)
24 {
25     const std::string name = RuntimeStubCSigns::GetRTName(RTSTUB_ID(CallRuntime));
26     const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
27     GateRef target = IntPtr(index);
28     std::vector<GateRef> inputs { depend, target, glue };
29     inputs.insert(inputs.end(), args.begin(), args.end());
30     auto numValuesIn = args.size() + 2; // 2: target & glue
31     inputs.emplace_back(IntPtr(0));  // framestate slot
32     numValuesIn += 1;
33     GateRef pcOffset = Int64(acc_.TryGetPcOffset(hirGate));
34     inputs.emplace_back(pcOffset);
35     numValuesIn += 1;
36 
37     const GateMetaData* meta = circuit_->RuntimeCall(numValuesIn);
38     MachineType machineType = cs->GetReturnType().GetMachineType();
39     GateType type = cs->GetReturnType().GetGateType();
40     GateRef result = circuit_->NewGate(meta, machineType, inputs.size(), inputs.data(), type, name.c_str());
41     return result;
42 }
43 
ToLength(GateRef receiver)44 GateRef CircuitBuilder::ToLength(GateRef receiver)
45 {
46     auto currentLabel = env_->GetCurrentLabel();
47     auto currentControl = currentLabel->GetControl();
48     auto currentDepend = currentLabel->GetDepend();
49     auto ret = GetCircuit()->NewGate(circuit_->ToLength(), MachineType::I64,
50                                      { currentControl, currentDepend, receiver }, GateType::NumberType());
51     currentLabel->SetControl(ret);
52     currentLabel->SetDepend(ret);
53     return ret;
54 }
55 
CallStub(GateRef glue,GateRef hirGate,int index,const std::vector<GateRef> & args,const char * comment)56 GateRef CircuitBuilder::CallStub(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
57                                  const char* comment)
58 {
59     const CallSignature *cs = CommonStubCSigns::Get(index);
60     ASSERT(cs->IsCommonStub());
61     GateRef target = IntPtr(index);
62     auto label = GetCurrentLabel();
63     auto depend = label->GetDepend();
64     GateRef result;
65     if (GetCircuit()->IsOptimizedJSFunctionFrame()) {
66         ASSERT(hirGate != Circuit::NullGate());
67         result = Call(cs, glue, target, depend, args, hirGate, comment);
68     } else {
69         result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
70     }
71     return result;
72 }
73 
CallBuiltinRuntime(GateRef glue,GateRef depend,const std::vector<GateRef> & args,bool isNew,const char * comment)74 GateRef CircuitBuilder::CallBuiltinRuntime(GateRef glue, GateRef depend, const std::vector<GateRef> &args,
75                                            bool isNew, const char* comment)
76 {
77     ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());
78     int index = 0;
79     if (!isNew) {
80         index = static_cast<int>(RTSTUB_ID(PushCallArgsAndDispatchNative));
81     } else {
82         index = static_cast<int>(RTSTUB_ID(PushCallNewAndDispatchNative));
83     }
84 
85     const CallSignature *cs = RuntimeStubCSigns::Get(index);
86     GateRef target = IntPtr(index);
87     auto label = GetCurrentLabel();
88     if (depend == Gate::InvalidGateRef) {
89         depend = label->GetDepend();
90     }
91     GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
92     return result;
93 }
94 
CallBuiltinRuntimeWithNewTarget(GateRef glue,GateRef depend,const std::vector<GateRef> & args,const char * comment)95 GateRef CircuitBuilder::CallBuiltinRuntimeWithNewTarget(GateRef glue, GateRef depend, const std::vector<GateRef> &args,
96                                                         const char* comment)
97 {
98     ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());
99     int index = 0;
100 
101     index = static_cast<int>(RTSTUB_ID(PushNewTargetAndDispatchNative));
102 
103     const CallSignature *cs = RuntimeStubCSigns::Get(index);
104     GateRef target = IntPtr(index);
105     auto label = GetCurrentLabel();
106     if (depend == Gate::InvalidGateRef) {
107         depend = label->GetDepend();
108     }
109     GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
110     return result;
111 }
112 
Call(const CallSignature * cs,GateRef glue,GateRef target,GateRef depend,const std::vector<GateRef> & args,GateRef hirGate,const char * comment)113 GateRef CircuitBuilder::Call(const CallSignature* cs, GateRef glue, GateRef target, GateRef depend,
114                              const std::vector<GateRef> &args, GateRef hirGate, const char* comment)
115 {
116     std::vector<GateRef> inputs { depend, target, glue };
117     inputs.insert(inputs.end(), args.begin(), args.end());
118     auto numValuesIn = args.size() + 2; // 2: target & glue
119     if (GetCircuit()->IsOptimizedJSFunctionFrame() && hirGate != Circuit::NullGate()) {
120         AppendFrameArgs(inputs, hirGate);
121         numValuesIn += 1;
122 
123         GateRef pcOffset = Int64(acc_.TryGetPcOffset(hirGate));
124         inputs.emplace_back(pcOffset);
125         numValuesIn += 1;
126     }
127 
128     const GateMetaData* meta = nullptr;
129     if (cs->IsCommonStub()) {
130         meta = circuit_->Call(numValuesIn);
131     } else if (cs->IsRuntimeVAStub()) {
132         meta = circuit_->RuntimeCallWithArgv(numValuesIn);
133     } else if (cs->IsRuntimeStub()) {
134         meta = circuit_->RuntimeCall(numValuesIn);
135     } else if (cs->IsBCDebuggerStub()) {
136         meta = circuit_->DebuggerBytecodeCall(numValuesIn);
137     } else if (cs->IsBCHandlerStub()) {
138         meta = circuit_->BytecodeCall(numValuesIn);
139     } else if (cs->IsBuiltinsStub()) {
140         meta = circuit_->BuiltinsCall(numValuesIn);
141     } else if (cs->IsBuiltinsWithArgvStub()) {
142         meta = circuit_->BuiltinsCallWithArgv(numValuesIn);
143     } else if (cs->IsRuntimeNGCStub()) {
144         meta = circuit_->NoGcRuntimeCall(numValuesIn);
145     } else if (cs->IsOptimizedStub()) {
146         bool isNoGC = acc_.GetNoGCFlag(hirGate);
147         meta = circuit_->CallOptimized(numValuesIn, isNoGC);
148     } else if (cs->IsOptimizedFastCallStub()) {
149         bool isNoGC = acc_.GetNoGCFlag(hirGate);
150         meta = circuit_->FastCallOptimized(numValuesIn, isNoGC);
151     } else {
152         LOG_ECMA(FATAL) << "unknown call operator";
153         UNREACHABLE();
154     }
155     MachineType machineType = cs->GetReturnType().GetMachineType();
156     GateType type = cs->GetReturnType().GetGateType();
157     GateRef result = GetCircuit()->NewGate(meta, machineType, inputs.size(), inputs.data(), type, comment);
158     auto label = GetCurrentLabel();
159     label->SetDepend(result);
160     return result;
161 }
162 
CallBCHandler(GateRef glue,GateRef target,const std::vector<GateRef> & args,const char * comment)163 GateRef CircuitBuilder::CallBCHandler(GateRef glue, GateRef target, const std::vector<GateRef> &args,
164                                       const char* comment)
165 {
166     ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());
167     const CallSignature *cs = BytecodeStubCSigns::BCHandler();
168     ASSERT(cs->IsBCStub());
169     auto label = GetCurrentLabel();
170     auto depend = label->GetDepend();
171     GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
172     return result;
173 }
174 
CallBuiltin(GateRef glue,GateRef target,const std::vector<GateRef> & args,const char * comment)175 GateRef CircuitBuilder::CallBuiltin(GateRef glue, GateRef target, const std::vector<GateRef> &args,
176                                     const char* comment)
177 {
178     ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());
179     const CallSignature *cs = BuiltinsStubCSigns::BuiltinsCSign();
180     ASSERT(cs->IsBuiltinsStub());
181     auto label = GetCurrentLabel();
182     auto depend = label->GetDepend();
183     GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
184     return result;
185 }
186 
CallBuiltinWithArgv(GateRef glue,GateRef target,const std::vector<GateRef> & args,const char * comment)187 GateRef CircuitBuilder::CallBuiltinWithArgv(GateRef glue, GateRef target, const std::vector<GateRef> &args,
188                                             const char* comment)
189 {
190     ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());
191     const CallSignature *cs = BuiltinsStubCSigns::BuiltinsWithArgvCSign();
192     ASSERT(cs->IsBuiltinsWithArgvStub());
193     auto label = GetCurrentLabel();
194     auto depend = label->GetDepend();
195     GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
196     return result;
197 }
198 
CallBCDebugger(GateRef glue,GateRef target,const std::vector<GateRef> & args,const char * comment)199 GateRef CircuitBuilder::CallBCDebugger(GateRef glue, GateRef target, const std::vector<GateRef> &args,
200                                        const char* comment)
201 {
202     ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());
203     const CallSignature *cs = BytecodeStubCSigns::BCDebuggerHandler();
204     ASSERT(cs->IsBCDebuggerStub());
205     auto label = GetCurrentLabel();
206     auto depend = label->GetDepend();
207     GateRef result = Call(cs, glue, target, depend, args, Circuit::NullGate(), comment);
208     return result;
209 }
210 
CallRuntime(GateRef glue,int index,GateRef depend,const std::vector<GateRef> & args,GateRef hirGate,const char * comment)211 GateRef CircuitBuilder::CallRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args,
212                                     GateRef hirGate, const char* comment)
213 {
214     GateRef target = IntPtr(index);
215     const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
216     ASSERT(cs->IsRuntimeStub());
217     auto label = GetCurrentLabel();
218     if (depend == Gate::InvalidGateRef) {
219         depend = label->GetDepend();
220     }
221     GateRef filteredHirGate = Circuit::NullGate();
222     if (GetCircuit()->IsOptimizedJSFunctionFrame()) {
223         ASSERT(hirGate != Circuit::NullGate());
224         filteredHirGate = hirGate;
225     }
226     GateRef result = Call(cs, glue, target, depend, args, filteredHirGate, comment);
227     return result;
228 }
229 
CallRuntimeVarargs(GateRef glue,int index,GateRef argc,GateRef argv,const char * comment)230 GateRef CircuitBuilder::CallRuntimeVarargs(GateRef glue, int index, GateRef argc, GateRef argv, const char* comment)
231 {
232     ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame());
233     const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntimeWithArgv));
234     GateRef target = IntPtr(index);
235     auto label = GetCurrentLabel();
236     auto depend = label->GetDepend();
237     ASSERT(cs->IsRuntimeVAStub());
238     GateRef result = Call(cs, glue, target, depend, {argc, argv}, Circuit::NullGate(), comment);
239     return result;
240 }
241 
CallNGCRuntime(GateRef glue,int index,GateRef depend,const std::vector<GateRef> & args,GateRef hirGate,const char * comment)242 GateRef CircuitBuilder::CallNGCRuntime(GateRef glue, int index, GateRef depend, const std::vector<GateRef> &args,
243                                        GateRef hirGate, const char* comment)
244 {
245     const CallSignature *cs = RuntimeStubCSigns::Get(index);
246     ASSERT(cs->IsRuntimeNGCStub());
247     GateRef target = IntPtr(index);
248     auto label = GetCurrentLabel();
249     if (depend == Gate::InvalidGateRef) {
250         depend = label->GetDepend();
251     }
252     GateRef filteredHirGate = Circuit::NullGate();
253     if (GetCircuit()->IsOptimizedJSFunctionFrame() && RuntimeStubCSigns::IsAsmStub(index)) {
254         ASSERT(hirGate != Circuit::NullGate());
255         filteredHirGate = hirGate;
256     }
257     GateRef result = Call(cs, glue, target, depend, args, filteredHirGate, comment);
258     return result;
259 }
260 
CallNGCRuntime(GateRef glue,GateRef gate,int index,const std::vector<GateRef> & args,bool useLabel)261 GateRef CircuitBuilder::CallNGCRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args,
262                                        bool useLabel)
263 {
264     const std::string name = RuntimeStubCSigns::GetRTName(index);
265     if (useLabel) {
266         GateRef result = CallNGCRuntime(glue, index, Gate::InvalidGateRef, args, gate, name.c_str());
267         return result;
268     } else {
269         const CallSignature *cs = RuntimeStubCSigns::Get(index);
270         GateRef target = IntPtr(index);
271         GateRef result = Call(cs, glue, target, GetDepend(), args, gate, name.c_str());
272         return result;
273     }
274 }
275 
StartCallTimer(GateRef glue,GateRef gate,const std::vector<GateRef> & args,bool useLabel)276 void CircuitBuilder::StartCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel)
277 {
278     (void)glue;
279     (void)gate;
280     (void)args;
281     (void)useLabel;
282 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
283     CallNGCRuntime(glue, gate, RTSTUB_ID(StartCallTimer), args, useLabel);
284 #endif
285 }
286 
EndCallTimer(GateRef glue,GateRef gate,const std::vector<GateRef> & args,bool useLabel)287 void CircuitBuilder::EndCallTimer(GateRef glue, GateRef gate, const std::vector<GateRef> &args, bool useLabel)
288 {
289     (void)glue;
290     (void)gate;
291     (void)args;
292     (void)useLabel;
293 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
294     CallNGCRuntime(glue, gate, RTSTUB_ID(EndCallTimer), args, useLabel);
295 #endif
296 }
297 
FastCallOptimized(GateRef glue,GateRef code,GateRef depend,const std::vector<GateRef> & args,GateRef hirGate)298 GateRef CircuitBuilder::FastCallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args,
299                                           GateRef hirGate)
300 {
301     const CallSignature *cs = RuntimeStubCSigns::GetOptimizedFastCallSign();
302     ASSERT(cs->IsOptimizedFastCallStub());
303     auto label = GetCurrentLabel();
304     if (depend == Gate::InvalidGateRef) {
305         depend = label->GetDepend();
306     }
307     GateRef filteredHirGate = Circuit::NullGate();
308     if (GetCircuit()->IsOptimizedJSFunctionFrame()) {
309         ASSERT(hirGate != Circuit::NullGate());
310         filteredHirGate = hirGate;
311     }
312     GateRef result = Call(cs, glue, code, depend, args, filteredHirGate);
313     return result;
314 }
315 
CallOptimized(GateRef glue,GateRef code,GateRef depend,const std::vector<GateRef> & args,GateRef hirGate)316 GateRef CircuitBuilder::CallOptimized(GateRef glue, GateRef code, GateRef depend, const std::vector<GateRef> &args,
317                                       GateRef hirGate)
318 {
319     const CallSignature *cs = RuntimeStubCSigns::GetOptimizedCallSign();
320     ASSERT(cs->IsOptimizedStub());
321     auto label = GetCurrentLabel();
322     if (depend == Gate::InvalidGateRef) {
323         depend = label->GetDepend();
324     }
325     GateRef filteredHirGate = Circuit::NullGate();
326     if (GetCircuit()->IsOptimizedJSFunctionFrame()) {
327         ASSERT(hirGate != Circuit::NullGate());
328         filteredHirGate = hirGate;
329     }
330     GateRef result = Call(cs, glue, code, depend, args, filteredHirGate);
331     return result;
332 }
333 
GetCallBuiltinId(GateRef method)334 GateRef CircuitBuilder::GetCallBuiltinId(GateRef method)
335 {
336     GateRef extraLiteralInfoOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET);
337     GateRef extraLiteralInfo = Load(VariableType::INT64(), method, extraLiteralInfoOffset);
338     return Int64And(
339         Int64LSR(extraLiteralInfo, Int64(MethodLiteral::BuiltinIdBits::START_BIT)),
340         Int64((1LU << MethodLiteral::BuiltinIdBits::SIZE) - 1));
341 }
342 
CallGetter(GateRef hirGate,GateRef receiver,GateRef holder,GateRef propertyLookupResult,const char * comment)343 GateRef CircuitBuilder::CallGetter(GateRef hirGate, GateRef receiver, GateRef holder, GateRef propertyLookupResult,
344                                    const char* comment)
345 {
346     ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
347     uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
348     ASSERT(pcOffset != 0);
349 
350     auto currentLabel = env_->GetCurrentLabel();
351     auto currentControl = currentLabel->GetControl();
352     auto currentDepend = currentLabel->GetDepend();
353     std::vector<GateRef> args = { currentControl, currentDepend, receiver, propertyLookupResult, holder };
354     AppendFrameArgs(args, hirGate);
355     auto callGate = GetCircuit()->NewGate(circuit_->CallGetter(pcOffset),
356                                           MachineType::I64,
357                                           args.size(),
358                                           args.data(),
359                                           GateType::AnyType(),
360                                           comment);
361     currentLabel->SetControl(callGate);
362     currentLabel->SetDepend(callGate);
363     return callGate;
364 }
365 
CallSetter(GateRef hirGate,GateRef receiver,GateRef holder,GateRef propertyLookupResult,GateRef value,const char * comment)366 GateRef CircuitBuilder::CallSetter(GateRef hirGate, GateRef receiver, GateRef holder, GateRef propertyLookupResult,
367                                    GateRef value, const char* comment)
368 {
369     ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
370     uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
371     ASSERT(pcOffset != 0);
372 
373     auto currentLabel = env_->GetCurrentLabel();
374     auto currentControl = currentLabel->GetControl();
375     auto currentDepend = currentLabel->GetDepend();
376     std::vector<GateRef> args = { currentControl, currentDepend, receiver, propertyLookupResult, holder, value };
377     AppendFrameArgs(args, hirGate);
378     auto callGate = GetCircuit()->NewGate(circuit_->CallSetter(pcOffset),
379                                           MachineType::I64,
380                                           args.size(),
381                                           args.data(),
382                                           GateType::AnyType(),
383                                           comment);
384     currentLabel->SetControl(callGate);
385     currentLabel->SetDepend(callGate);
386     return callGate;
387 }
388 
Construct(GateRef hirGate,std::vector<GateRef> args)389 GateRef CircuitBuilder::Construct(GateRef hirGate, std::vector<GateRef> args)
390 {
391     ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
392     auto currentLabel = env_->GetCurrentLabel();
393     auto currentControl = currentLabel->GetControl();
394     auto currentDepend = currentLabel->GetDepend();
395     uint64_t bitfield = args.size();
396     uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
397     ASSERT(pcOffset != 0);
398     args.insert(args.begin(), currentDepend);
399     args.insert(args.begin(), currentControl);
400     AppendFrameArgs(args, hirGate);
401     auto callGate = GetCircuit()->NewGate(circuit_->Construct(bitfield, pcOffset), MachineType::I64,
402                                           args.size(), args.data(), GateType::AnyType());
403     currentLabel->SetControl(callGate);
404     currentLabel->SetDepend(callGate);
405     return callGate;
406 }
407 
CreateArray(ElementsKind kind,uint32_t arraySize,GateRef elementsLength)408 GateRef CircuitBuilder::CreateArray(ElementsKind kind, uint32_t arraySize, GateRef elementsLength)
409 {
410     auto currentLabel = env_->GetCurrentLabel();
411     auto currentControl = currentLabel->GetControl();
412     auto currentDepend = currentLabel->GetDepend();
413     ArrayMetaDataAccessor accessor(kind, ArrayMetaDataAccessor::Mode::CREATE, arraySize);
414     GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArray(accessor.ToValue()), MachineType::I64,
415                                             { currentControl, currentDepend, elementsLength },
416                                             GateType::TaggedValue());
417     currentLabel->SetControl(newGate);
418     currentLabel->SetDepend(newGate);
419     return newGate;
420 }
421 
CreateArrayWithBuffer(ElementsKind kind,ArrayMetaDataAccessor::Mode mode,GateRef cpId,GateRef constPoolIndex,GateRef elementIndex)422 GateRef CircuitBuilder::CreateArrayWithBuffer(ElementsKind kind, ArrayMetaDataAccessor::Mode mode, GateRef cpId,
423                                               GateRef constPoolIndex, GateRef elementIndex)
424 {
425     auto currentLabel = env_->GetCurrentLabel();
426     auto currentControl = currentLabel->GetControl();
427     auto currentDepend = currentLabel->GetDepend();
428     auto frameState = acc_.FindNearestFrameState(currentDepend);
429     ArrayMetaDataAccessor accessor(kind, mode);
430     GateRef newGate = GetCircuit()->NewGate(circuit_->CreateArrayWithBuffer(accessor.ToValue()),
431                                             MachineType::I64,
432                                             { currentControl, currentDepend, cpId, constPoolIndex,
433                                               elementIndex, frameState },
434                                             GateType::NJSValue());
435     currentLabel->SetControl(newGate);
436     currentLabel->SetDepend(newGate);
437     return newGate;
438 }
439 
SetPropertyInlinedProps(GateRef glue,GateRef obj,GateRef hClass,GateRef value,GateRef attrOffset,VariableType type)440 void CircuitBuilder::SetPropertyInlinedProps(GateRef glue, GateRef obj, GateRef hClass,
441     GateRef value, GateRef attrOffset, VariableType type)
442 {
443     GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
444     GateRef inlinedPropsStart = Int32And(Int32LSR(bitfield,
445         Int32(JSHClass::InlinedPropsStartBits::START_BIT)),
446         Int32((1LU << JSHClass::InlinedPropsStartBits::SIZE) - 1));
447     GateRef propOffset = Int32Mul(Int32Add(inlinedPropsStart, attrOffset),
448         Int32(JSTaggedValue::TaggedTypeSize()));
449     Store(type, glue, obj, ZExtInt32ToPtr(propOffset), value);
450 }
451 
IsStabelArray(GateRef glue,GateRef obj)452 GateRef CircuitBuilder::IsStabelArray(GateRef glue, GateRef obj)
453 {
454     Label subentry(env_);
455     env_->SubCfgEntry(&subentry);
456     DEFVALUE(result, env_, VariableType::BOOL(), False());
457     Label exit(env_);
458     Label targetIsHeapObject(env_);
459     Label targetIsStableArray(env_);
460 
461     Branch(TaggedIsHeapObject(obj), &targetIsHeapObject, &exit);
462     Bind(&targetIsHeapObject);
463     {
464         GateRef jsHclass = LoadHClass(obj);
465         Branch(IsStableArray(jsHclass), &targetIsStableArray, &exit);
466         Bind(&targetIsStableArray);
467         {
468             GateRef guardiansOffset =
469                 IntPtr(JSThread::GlueData::GetStableArrayElementsGuardiansOffset(false));
470             result = Load(VariableType::BOOL(), glue, guardiansOffset);
471             Jump(&exit);
472         }
473     }
474     Bind(&exit);
475     auto res = *result;
476     env_->SubCfgExit();
477     return res;
478 }
479 
StoreModuleVar(GateRef jsFunc,GateRef index,GateRef value)480 GateRef CircuitBuilder::StoreModuleVar(GateRef jsFunc, GateRef index, GateRef value)
481 {
482     auto currentLabel = env_->GetCurrentLabel();
483     auto currentControl = currentLabel->GetControl();
484     auto currentDepend = currentLabel->GetDepend();
485     GateRef newGate = GetCircuit()->NewGate(circuit_->StoreModuleVar(), MachineType::I64,
486         { currentControl, currentDepend, jsFunc, index, value }, GateType::TaggedValue());
487     currentLabel->SetControl(newGate);
488     currentLabel->SetDepend(newGate);
489     return newGate;
490 }
491 
LdLocalModuleVar(GateRef jsFunc,GateRef index)492 GateRef CircuitBuilder::LdLocalModuleVar(GateRef jsFunc, GateRef index)
493 {
494     auto currentLabel = env_->GetCurrentLabel();
495     auto currentControl = currentLabel->GetControl();
496     auto currentDepend = currentLabel->GetDepend();
497     GateRef newGate = GetCircuit()->NewGate(circuit_->LdLocalModuleVar(), MachineType::I64,
498                                             { currentControl, currentDepend, jsFunc, index}, GateType::TaggedValue());
499     currentLabel->SetControl(newGate);
500     currentLabel->SetDepend(newGate);
501     return newGate;
502 }
503 
BuiltinConstructor(BuiltinTypeId id,GateRef gate)504 GateRef CircuitBuilder::BuiltinConstructor(BuiltinTypeId id, GateRef gate)
505 {
506     auto currentLabel = env_->GetCurrentLabel();
507     auto currentControl = currentLabel->GetControl();
508     auto currentDepend = currentLabel->GetDepend();
509     GateRef newGate = Circuit::NullGate();
510     switch (id) {
511         case BuiltinTypeId::ARRAY: {
512             if (acc_.GetNumValueIn(gate) == 1) {
513                 newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(1), MachineType::I64,
514                                                 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
515                                                 GateType::TaggedValue());
516             } else {
517                 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
518                 newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(2), MachineType::I64,
519                     { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
520                     GateType::TaggedValue());
521             }
522             break;
523         }
524         case BuiltinTypeId::OBJECT: {
525             if (acc_.GetNumValueIn(gate) == 1) {
526                 newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(1), MachineType::I64,
527                                                 { currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
528                                                 GateType::TaggedValue());
529             } else {
530                 ASSERT(acc_.GetNumValueIn(gate) >= 2); // 2: num value in
531                 newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(2), MachineType::I64,
532                     { currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
533                     GateType::TaggedValue());
534             }
535             break;
536         }
537         default:
538             LOG_ECMA(FATAL) << "this branch is unreachable";
539             UNREACHABLE();
540             break;
541     }
542     currentLabel->SetControl(newGate);
543     currentLabel->SetDepend(newGate);
544     return newGate;
545 }
546 
SetExtensibleToBitfield(GateRef glue,GateRef obj,bool isExtensible)547 void CircuitBuilder::SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible)
548 {
549     GateRef jsHclass = LoadHClass(obj);
550     GateRef bitfield = Load(VariableType::INT32(), jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
551     GateRef boolVal = Boolean(isExtensible);
552     GateRef boolToInt32 = ZExtInt1ToInt32(boolVal);
553     GateRef encodeValue = Int32LSL(boolToInt32, Int32(JSHClass::ExtensibleBit::START_BIT));
554     GateRef mask = Int32(((1LU << JSHClass::ExtensibleBit::SIZE) - 1) << JSHClass::ExtensibleBit::START_BIT);
555     bitfield = Int32Or(Int32And(bitfield, Int32Not(mask)), encodeValue);
556     Store(VariableType::INT32(), glue, jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET), bitfield);
557 }
558 
OrdinaryHasInstance(GateRef obj,GateRef target)559 GateRef CircuitBuilder::OrdinaryHasInstance(GateRef obj, GateRef target)
560 {
561     auto currentLabel = env_->GetCurrentLabel();
562     auto currentControl = currentLabel->GetControl();
563     auto currentDepend = currentLabel->GetDepend();
564     GateRef frameState = acc_.FindNearestFrameState(currentDepend);
565     auto ret = GetCircuit()->NewGate(circuit_->OrdinaryHasInstance(),
566                                      MachineType::I64,
567                                      {currentControl, currentDepend, obj, target, frameState},
568                                      GateType::TaggedNPointer());
569     acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret);
570     currentLabel->SetControl(ret);
571     currentLabel->SetDepend(ret);
572     return ret;
573 }
574 
IsLiteralString(GateRef string)575 GateRef CircuitBuilder::IsLiteralString(GateRef string)
576 {
577     return BoolOr(IsLineString(string), IsConstantString(string));
578 }
579 
580 // left and right both utf-8 or utf-16 and both linestring or constantstring can be concat.
CanBeConcat(GateRef leftString,GateRef rightString,GateRef isValidOpt)581 GateRef CircuitBuilder::CanBeConcat(GateRef leftString, GateRef rightString, GateRef isValidOpt)
582 {
583     GateRef isSameType = BoolAnd(IsLiteralString(leftString), IsLiteralString(rightString));
584     return BoolAnd(isSameType, isValidOpt);
585 }
586 
587 // left and right both utf-8 or utf-16 and right is linestring or constantstring can back store.
CanBackStore(GateRef rightString,GateRef isValidOpt)588 GateRef CircuitBuilder::CanBackStore(GateRef rightString, GateRef isValidOpt)
589 {
590     return BoolAnd(isValidOpt, IsLiteralString(rightString));
591 }
592 }
593