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