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/ntype_hcr_lowering.h"
17 #include "ecmascript/jit/jit.h"
18
19 namespace panda::ecmascript::kungfu {
VisitGate(GateRef gate)20 GateRef NTypeHCRLowering::VisitGate(GateRef gate)
21 {
22 GateRef glue = acc_.GetGlueFromArgList();
23 auto op = acc_.GetOpCode(gate);
24 switch (op) {
25 case OpCode::CREATE_ARRAY: {
26 Jit::JitLockHolder lock(compilationEnv_, "LowerCreateArray");
27 LowerCreateArray(gate, glue);
28 }
29 break;
30 case OpCode::CREATE_ARRAY_WITH_BUFFER: {
31 Jit::JitLockHolder lock(compilationEnv_, "LowerCreateArrayWithBuffer");
32 LowerCreateArrayWithBuffer(gate, glue);
33 }
34 break;
35 case OpCode::CREATE_ARGUMENTS:
36 LowerCreateArguments(gate, glue);
37 break;
38 case OpCode::STORE_MODULE_VAR:
39 LowerStoreModuleVar(gate, glue);
40 break;
41 case OpCode::LD_LOCAL_MODULE_VAR:
42 LowerLdLocalModuleVar(gate);
43 break;
44 default:
45 break;
46 }
47 return Circuit::NullGate();
48 }
49
LowerCreateArray(GateRef gate,GateRef glue)50 void NTypeHCRLowering::LowerCreateArray(GateRef gate, GateRef glue)
51 {
52 Environment env(gate, circuit_, &builder_);
53 if (acc_.GetArraySize(gate) == 0) {
54 LowerCreateEmptyArray(gate, glue);
55 } else {
56 LowerCreateArrayWithOwn(gate, glue);
57 }
58 }
59
LowerCreateEmptyArray(GateRef gate,GateRef glue)60 void NTypeHCRLowering::LowerCreateEmptyArray(GateRef gate, GateRef glue)
61 {
62 GateRef length = builder_.Int32(0);
63 GateRef elements = Circuit::NullGate();
64 GateRef value = acc_.GetValueIn(gate, 0);
65 auto hintLength = static_cast<uint32_t>(acc_.GetConstantValue(value));
66 elements = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
67 auto array = NewJSArrayLiteral(glue, gate, elements, length, hintLength);
68 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
69 }
70
LowerCreateArrayWithOwn(GateRef gate,GateRef glue)71 void NTypeHCRLowering::LowerCreateArrayWithOwn(GateRef gate, GateRef glue)
72 {
73 uint32_t elementsLength = acc_.GetArraySize(gate);
74 GateRef length = builder_.IntPtr(elementsLength);
75 GateRef elements = CreateElementsWithLength(gate, glue, elementsLength);
76
77 auto array = NewJSArrayLiteral(glue, gate, elements, length);
78 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
79 }
80
LowerCreateArrayWithBuffer(GateRef gate,GateRef glue)81 void NTypeHCRLowering::LowerCreateArrayWithBuffer(GateRef gate, GateRef glue)
82 {
83 Environment env(gate, circuit_, &builder_);
84 // 2: number of value inputs
85 ASSERT(acc_.GetNumValueIn(gate) == 2);
86 GateRef cpId = acc_.GetValueIn(gate, 0);
87 GateRef index = acc_.GetValueIn(gate, 1);
88 uint32_t constPoolIndex = static_cast<uint32_t>(acc_.GetConstantValue(index));
89 ArgumentAccessor argAcc(circuit_);
90 GateRef frameState = GetFrameState(gate);
91 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
92 GateRef module = builder_.GetModuleFromFunction(jsFunc);
93 GateRef unsharedConstpool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::UNSHARED_CONST_POOL);
94 GateRef sharedConstpool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::SHARED_CONST_POOL);
95 GateRef cachedArray = builder_.GetObjectFromConstPool(glue, gate, sharedConstpool, unsharedConstpool,
96 module, builder_.TruncInt64ToInt32(index),
97 ConstPoolType::ARRAY_LITERAL);
98 GateRef literialElements = builder_.GetElementsArray(cachedArray);
99 uint32_t cpIdVal = static_cast<uint32_t>(acc_.GetConstantValue(cpId));
100 JSTaggedValue arr = GetArrayLiteralValue(cpIdVal, constPoolIndex);
101 ASSERT(!arr.IsUndefined());
102 DISALLOW_GARBAGE_COLLECTION;
103 JSArray *arrayHandle = JSArray::Cast(arr.GetTaggedObject());
104 TaggedArray *arrayLiteral = TaggedArray::Cast(arrayHandle->GetElements());
105 uint32_t literialLength = arrayLiteral->GetLength();
106 uint32_t arrayLength = acc_.GetArraySize(gate);
107 GateRef elements = Circuit::NullGate();
108 GateRef length = Circuit::NullGate();
109 if (arrayLength > literialLength) {
110 elements = CreateElementsWithLength(gate, glue, arrayLength);
111 for (uint32_t i = 0; i < literialLength; i++) {
112 GateRef value = builder_.LoadFromTaggedArray(literialElements, i);
113 builder_.StoreToTaggedArray(elements, i, value);
114 }
115 length = builder_.IntPtr(arrayLength);
116 } else {
117 elements = literialElements;
118 length = builder_.IntPtr(literialLength);
119 }
120
121 auto array = NewJSArrayLiteral(glue, gate, elements, length);
122 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
123 }
124
NewActualArgv(GateRef gate,GateRef glue)125 GateRef NTypeHCRLowering::NewActualArgv(GateRef gate, GateRef glue)
126 {
127 ArgumentAccessor argAcc(circuit_);
128 auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
129 size_t length = argAcc.ArgsCount() - funcIdx;
130 GateRef array = CreateElementsWithLength(gate, glue, length);
131 for (size_t i = funcIdx; i < argAcc.ArgsCount(); i++) {
132 GateRef value = argAcc.ArgsAt(i);
133 builder_.StoreToTaggedArray(array, i - funcIdx, value);
134 }
135 return array;
136 }
137
LowerCreateArguments(GateRef gate,GateRef glue)138 void NTypeHCRLowering::LowerCreateArguments(GateRef gate, GateRef glue)
139 {
140 CreateArgumentsAccessor accessor = acc_.GetCreateArgumentsAccessor(gate);
141 CreateArgumentsAccessor::Mode mode = accessor.GetMode();
142 Environment env(gate, circuit_, &builder_);
143 ArgumentAccessor argAcc(circuit_);
144 GateRef frameState = GetFrameState(gate);
145 GateRef actualArgc = builder_.TruncInt64ToInt32(argAcc.GetFrameArgsIn(frameState, FrameArgIdx::ACTUAL_ARGC));
146 GateRef expectedArgc = builder_.Int32(methodLiteral_->GetNumArgs());
147 GateRef argv = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::ACTUAL_ARGV);
148 DEFVALUE(actualArgv, (&builder_), VariableType::NATIVE_POINTER(), argv);
149 DEFVALUE(actualArgvArray, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
150 GateRef startIdx = acc_.GetValueIn(gate, 0);
151 GateRef check = builder_.BitAnd(builder_.Equal(actualArgc, expectedArgc),
152 builder_.Equal(builder_.IntPtr(0), *actualArgv));
153 Label calcActualArgv(&builder_);
154 Label exit(&builder_);
155 BRANCH_CIR(check, &calcActualArgv, &exit);
156 builder_.Bind(&calcActualArgv);
157 {
158 actualArgvArray = NewActualArgv(gate, glue);
159 builder_.Jump(&exit);
160 }
161 builder_.Bind(&exit);
162 switch (mode) {
163 case CreateArgumentsAccessor::Mode::REST_ARGUMENTS: {
164 GateRef newGate = builder_.CallStub(glue, gate, CommonStubCSigns::CopyRestArgs,
165 { glue, *actualArgv, startIdx, actualArgc, *actualArgvArray });
166 ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), newGate);
167 break;
168 }
169 case CreateArgumentsAccessor::Mode::UNMAPPED_ARGUMENTS: {
170 GateRef newGate = builder_.CallStub(glue, gate, CommonStubCSigns::GetUnmappedArgs,
171 { glue, *actualArgv, actualArgc, *actualArgvArray });
172 ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), newGate);
173 break;
174 }
175 default: {
176 LOG_ECMA(FATAL) << "this branch is unreachable";
177 UNREACHABLE();
178 }
179 }
180 }
181
LoadFromConstPool(GateRef unsharedConstpool,size_t index,size_t valVecType)182 GateRef NTypeHCRLowering::LoadFromConstPool(GateRef unsharedConstpool, size_t index, size_t valVecType)
183 {
184 GateRef constPoolSize = builder_.GetLengthOfTaggedArray(unsharedConstpool);
185 GateRef valVecIndex = builder_.Int32Sub(constPoolSize, builder_.Int32(valVecType));
186 GateRef valVec = builder_.GetValueFromTaggedArray(unsharedConstpool, valVecIndex);
187 return builder_.LoadFromTaggedArray(valVec, index);
188 }
189
CreateElementsWithLength(GateRef gate,GateRef glue,size_t arrayLength)190 GateRef NTypeHCRLowering::CreateElementsWithLength(GateRef gate, GateRef glue, size_t arrayLength)
191 {
192 GateRef elements = Circuit::NullGate();
193 GateRef length = builder_.IntPtr(arrayLength);
194 if (arrayLength < MAX_TAGGED_ARRAY_LENGTH) {
195 elements = NewTaggedArray(arrayLength, glue);
196 } else {
197 elements = LowerCallRuntime(glue, gate, RTSTUB_ID(NewTaggedArray), { builder_.Int32ToTaggedInt(length) }, true);
198 }
199 return elements;
200 }
201
NewJSArrayLiteral(GateRef glue,GateRef gate,GateRef elements,GateRef length,uint32_t hintLength)202 GateRef NTypeHCRLowering::NewJSArrayLiteral(GateRef glue, GateRef gate, GateRef elements, GateRef length,
203 uint32_t hintLength)
204 {
205 ElementsKind kind = acc_.GetArrayMetaDataAccessor(gate).GetElementsKind();
206 GateRef hclass = Circuit::NullGate();
207 if (!Elements::IsGeneric(kind)) {
208 // At define point, we use initial array class without IsPrototype set.
209 auto hclassIndex = compilationEnv_->GetArrayHClassIndexMap().at(kind).first;
210 hclass = builder_.GetGlobalConstantValue(hclassIndex);
211 } else {
212 GateRef globalEnv = builder_.GetGlobalEnv();
213 hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
214 }
215
216 JSHandle<JSFunction> arrayFunc(compilationEnv_->GetGlobalEnv()->GetArrayFunction());
217 JSTaggedValue protoOrHClass = arrayFunc->GetProtoOrHClass();
218 JSHClass *arrayHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
219 size_t arraySize = arrayHC->GetObjectSize();
220 size_t lengthAccessorOffset = arrayHC->GetInlinedPropertiesOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX);
221
222 GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
223 GateRef accessor = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_LENGTH_ACCESSOR);
224 GateRef size = builder_.IntPtr(arrayHC->GetObjectSize());
225
226 builder_.StartAllocate();
227 GateRef array = builder_.HeapAlloc(glue, size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
228 // initialization
229 for (size_t offset = JSArray::SIZE; offset < arraySize; offset += JSTaggedValue::TaggedTypeSize()) {
230 builder_.StoreConstOffset(VariableType::INT64(), array, offset, builder_.Undefined());
231 }
232 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, 0, hclass, MemoryAttribute::NeedBarrierAndAtomic());
233 builder_.StoreConstOffset(VariableType::INT64(), array, ECMAObject::HASH_OFFSET,
234 builder_.Int64(JSTaggedValue(0).GetRawData()));
235 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::PROPERTIES_OFFSET, emptyArray,
236 MemoryAttribute::NoBarrier());
237 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::ELEMENTS_OFFSET, elements,
238 MemoryAttribute::NeedBarrier());
239 builder_.StoreConstOffset(VariableType::INT32(), array, JSArray::LENGTH_OFFSET, length);
240 if (hintLength > 0) {
241 builder_.StoreConstOffset(VariableType::INT64(), array, JSArray::TRACK_INFO_OFFSET,
242 builder_.Int64(JSTaggedValue(hintLength).GetRawData()));
243 } else {
244 builder_.StoreConstOffset(VariableType::INT64(), array, JSArray::TRACK_INFO_OFFSET, builder_.Undefined());
245 }
246 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, lengthAccessorOffset, accessor,
247 MemoryAttribute::NeedBarrier());
248 return builder_.FinishAllocate(array);
249 }
250
NewTaggedArray(size_t length,GateRef glue)251 GateRef NTypeHCRLowering::NewTaggedArray(size_t length, GateRef glue)
252 {
253 GateRef elementsHclass = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_CLASS_INDEX);
254 GateRef elementsSize = builder_.ComputeTaggedArraySize(builder_.IntPtr(length));
255
256 builder_.StartAllocate();
257 GateRef elements = builder_.HeapAlloc(glue, elementsSize, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
258 builder_.StoreConstOffset(VariableType::JS_POINTER(), elements, 0, elementsHclass,
259 MemoryAttribute::NeedBarrierAndAtomic());
260 builder_.StoreConstOffset(VariableType::JS_ANY(), elements, TaggedArray::LENGTH_OFFSET,
261 builder_.Int32ToTaggedInt(builder_.IntPtr(length)), MemoryAttribute::NoBarrier());
262 size_t endOffset = TaggedArray::DATA_OFFSET + length * JSTaggedValue::TaggedTypeSize();
263 // initialization
264 for (size_t offset = TaggedArray::DATA_OFFSET; offset < endOffset; offset += JSTaggedValue::TaggedTypeSize()) {
265 builder_.StoreConstOffset(VariableType::INT64(), elements, offset, builder_.Hole());
266 }
267 return builder_.FinishAllocate(elements);
268 }
269
LowerCallRuntime(GateRef glue,GateRef hirGate,int index,const std::vector<GateRef> & args,bool useLabel)270 GateRef NTypeHCRLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
271 bool useLabel)
272 {
273 const std::string name = RuntimeStubCSigns::GetRTName(index);
274 if (useLabel) {
275 GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, hirGate, name.c_str());
276 return result;
277 } else {
278 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
279 GateRef target = builder_.IntPtr(index);
280 GateRef result = builder_.Call(cs, glue, target, dependEntry_, args, hirGate, name.c_str());
281 return result;
282 }
283 }
284
LowerStoreModuleVar(GateRef gate,GateRef glue)285 void NTypeHCRLowering::LowerStoreModuleVar(GateRef gate, GateRef glue)
286 {
287 Environment env(gate, circuit_, &builder_);
288 GateRef jsFunc = acc_.GetValueIn(gate, 0);
289 GateRef index = acc_.GetValueIn(gate, 1);
290 GateRef value = acc_.GetValueIn(gate, 2);
291 GateRef moduleOffset = builder_.IntPtr(JSFunction::ECMA_MODULE_OFFSET);
292 GateRef module = builder_.Load(VariableType::JS_ANY(), jsFunc, moduleOffset);
293 GateRef localExportEntriesOffset = builder_.IntPtr(SourceTextModule::LOCAL_EXPORT_ENTTRIES_OFFSET);
294 GateRef localExportEntries = builder_.Load(VariableType::JS_ANY(), module, localExportEntriesOffset);
295 GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET);
296 GateRef data = builder_.Load(VariableType::JS_ANY(), module, nameDictionaryOffset);
297 DEFVALUE(array, (&builder_), VariableType::JS_ANY(), data);
298
299 Label dataIsUndefined(&builder_);
300 Label exit(&builder_);
301 BRANCH_CIR(builder_.TaggedIsUndefined(data), &dataIsUndefined, &exit);
302 builder_.Bind(&dataIsUndefined);
303 {
304 GateRef size = builder_.GetLengthOfTaggedArray(localExportEntries);
305 array = LowerCallRuntime(glue, gate, RTSTUB_ID(NewTaggedArray), { builder_.Int32ToTaggedInt(size) }, true);
306 builder_.StoreConstOffset(VariableType::JS_ANY(), module, SourceTextModule::NAME_DICTIONARY_OFFSET, *array);
307 builder_.Jump(&exit);
308 }
309 builder_.Bind(&exit);
310 GateRef dataOffset = builder_.Int32(TaggedArray::DATA_OFFSET);
311 GateRef indexOffset = builder_.Int32Mul(index, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
312 GateRef offset = builder_.Int32Add(indexOffset, dataOffset);
313 builder_.Store(VariableType::JS_ANY(), glue_, *array, offset, value);
314 ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
315 }
316
LowerLdLocalModuleVar(GateRef gate)317 void NTypeHCRLowering::LowerLdLocalModuleVar(GateRef gate)
318 {
319 Environment env(gate, circuit_, &builder_);
320 GateRef jsFunc = acc_.GetValueIn(gate, 0);
321 GateRef index = acc_.GetValueIn(gate, 1);
322 GateRef moduleOffset = builder_.IntPtr(JSFunction::ECMA_MODULE_OFFSET);
323 GateRef module = builder_.Load(VariableType::JS_ANY(), jsFunc, moduleOffset);
324 GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET);
325 GateRef dictionary = builder_.Load(VariableType::JS_ANY(), module, nameDictionaryOffset);
326 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
327 Label dataIsNotUndefined(&builder_);
328 Label exit(&builder_);
329 BRANCH_CIR(builder_.TaggedIsUndefined(dictionary), &exit, &dataIsNotUndefined);
330 builder_.Bind(&dataIsNotUndefined);
331 {
332 GateRef dataOffset = builder_.Int32(TaggedArray::DATA_OFFSET);
333 GateRef indexOffset = builder_.Int32Mul(index, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
334 GateRef offset = builder_.Int32Add(indexOffset, dataOffset);
335 result = builder_.Load(VariableType::JS_ANY(), dictionary, offset);
336 builder_.Jump(&exit);
337 }
338 builder_.Bind(&exit);
339 ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
340 }
341
ReplaceGateWithPendingException(GateRef gate,GateRef state,GateRef depend,GateRef value)342 void NTypeHCRLowering::ReplaceGateWithPendingException(GateRef gate, GateRef state, GateRef depend, GateRef value)
343 {
344 auto condition = builder_.HasPendingException(glue_);
345 GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
346 GateRef ifTrue = builder_.IfTrue(ifBranch);
347 GateRef ifFalse = builder_.IfFalse(ifBranch);
348 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
349 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
350
351 StateDepend success(ifFalse, sDepend);
352 StateDepend exception(ifTrue, eDepend);
353 acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
354 }
355 }
356