• 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/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             acc_.ReplaceGate(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             acc_.ReplaceGate(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     RegionSpaceFlag flag = RegionSpaceFlag::IN_YOUNG_SPACE;
207     if (enablePgoSpace_) {
208         flag = acc_.GetArrayMetaDataAccessor(gate).GetRegionSpaceFlag();
209     }
210     GateRef hclass = Circuit::NullGate();
211     // At define point, we use initial array class without IsPrototype set.
212     auto hclassIndex = compilationEnv_->GetArrayHClassIndex(kind, false);
213     hclass = builder_.GetGlobalConstantValue(hclassIndex);
214 
215     JSHandle<JSFunction> arrayFunc(compilationEnv_->GetGlobalEnv()->GetArrayFunction());
216     JSTaggedValue protoOrHClass = arrayFunc->GetProtoOrHClass();
217     JSHClass *arrayHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
218     size_t arraySize = arrayHC->GetObjectSize();
219     size_t lengthAccessorOffset = arrayHC->GetInlinedPropertiesOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX);
220 
221     GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
222     GateRef accessor = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_LENGTH_ACCESSOR);
223     GateRef size = builder_.IntPtr(arrayHC->GetObjectSize());
224 
225     builder_.StartAllocate();
226     GateRef array = builder_.HeapAlloc(glue, size, GateType::TaggedValue(), flag);
227     // initialization
228     for (size_t offset = JSArray::SIZE; offset < arraySize; offset += JSTaggedValue::TaggedTypeSize()) {
229         builder_.StoreConstOffset(VariableType::INT64(), array, offset, builder_.Undefined(),
230                                   MemoryAttribute::NoBarrier());
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()), MemoryAttribute::NoBarrier());
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()), MemoryAttribute::NoBarrier());
243     } else {
244         builder_.StoreConstOffset(VariableType::INT64(), array, JSArray::TRACK_INFO_OFFSET, builder_.Undefined(),
245             MemoryAttribute::NoBarrier());
246     }
247     builder_.StoreConstOffset(VariableType::JS_POINTER(), array, lengthAccessorOffset, accessor,
248                               MemoryAttribute::NoBarrier());
249     return builder_.FinishAllocate(array);
250 }
251 
NewTaggedArray(size_t length,GateRef glue)252 GateRef NTypeHCRLowering::NewTaggedArray(size_t length, GateRef glue)
253 {
254     GateRef elementsHclass = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_CLASS_INDEX);
255     GateRef elementsSize = builder_.ComputeTaggedArraySize(builder_.IntPtr(length));
256 
257     builder_.StartAllocate();
258     GateRef elements = builder_.HeapAlloc(glue, elementsSize, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
259     builder_.StoreConstOffset(VariableType::JS_POINTER(), elements, 0, elementsHclass,
260                               MemoryAttribute::NeedBarrierAndAtomic());
261     builder_.StoreConstOffset(VariableType::JS_ANY(), elements, TaggedArray::LENGTH_OFFSET,
262         builder_.Int32ToTaggedInt(builder_.IntPtr(length)), MemoryAttribute::NoBarrier());
263     size_t endOffset = TaggedArray::DATA_OFFSET + length * JSTaggedValue::TaggedTypeSize();
264     // initialization
265     for (size_t offset = TaggedArray::DATA_OFFSET; offset < endOffset; offset += JSTaggedValue::TaggedTypeSize()) {
266         builder_.StoreConstOffset(VariableType::INT64(), elements, offset, builder_.Hole());
267     }
268     return builder_.FinishAllocate(elements);
269 }
270 
LowerCallRuntime(GateRef glue,GateRef hirGate,int index,const std::vector<GateRef> & args,bool useLabel)271 GateRef NTypeHCRLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
272     bool useLabel)
273 {
274     const std::string name = RuntimeStubCSigns::GetRTName(index);
275     if (useLabel) {
276         GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, hirGate, name.c_str());
277         return result;
278     } else {
279         const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
280         GateRef target = builder_.IntPtr(index);
281         GateRef result = builder_.Call(cs, glue, target, dependEntry_, args, hirGate, name.c_str());
282         return result;
283     }
284 }
285 
LowerStoreModuleVar(GateRef gate,GateRef glue)286 void NTypeHCRLowering::LowerStoreModuleVar(GateRef gate, GateRef glue)
287 {
288     Environment env(gate, circuit_, &builder_);
289     GateRef jsFunc = acc_.GetValueIn(gate, 0);
290     GateRef index = acc_.GetValueIn(gate, 1);
291     GateRef value = acc_.GetValueIn(gate, 2);
292     GateRef moduleOffset = builder_.IntPtr(JSFunction::ECMA_MODULE_OFFSET);
293     GateRef module = builder_.Load(VariableType::JS_ANY(), jsFunc, moduleOffset);
294     GateRef localExportEntriesOffset = builder_.IntPtr(SourceTextModule::LOCAL_EXPORT_ENTTRIES_OFFSET);
295     GateRef localExportEntries = builder_.Load(VariableType::JS_ANY(), module, localExportEntriesOffset);
296     GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET);
297     GateRef data = builder_.Load(VariableType::JS_ANY(), module, nameDictionaryOffset);
298     DEFVALUE(array, (&builder_), VariableType::JS_ANY(), data);
299 
300     Label dataIsUndefined(&builder_);
301     Label exit(&builder_);
302     BRANCH_CIR(builder_.TaggedIsUndefined(data), &dataIsUndefined, &exit);
303     builder_.Bind(&dataIsUndefined);
304     {
305         GateRef size = builder_.GetLengthOfTaggedArray(localExportEntries);
306         array = LowerCallRuntime(glue, gate, RTSTUB_ID(NewTaggedArray), { builder_.Int32ToTaggedInt(size) }, true);
307         builder_.StoreConstOffset(VariableType::JS_ANY(), module, SourceTextModule::NAME_DICTIONARY_OFFSET, *array);
308         builder_.Jump(&exit);
309     }
310     builder_.Bind(&exit);
311     GateRef dataOffset = builder_.Int32(TaggedArray::DATA_OFFSET);
312     GateRef indexOffset = builder_.Int32Mul(index, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
313     GateRef offset = builder_.ZExtInt32ToPtr(builder_.Int32Add(indexOffset, dataOffset));
314     builder_.Store(VariableType::JS_ANY(), glue_, *array, offset, value);
315     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
316 }
317 
LowerLdLocalModuleVar(GateRef gate)318 void NTypeHCRLowering::LowerLdLocalModuleVar(GateRef gate)
319 {
320     Environment env(gate, circuit_, &builder_);
321     GateRef jsFunc = acc_.GetValueIn(gate, 0);
322     GateRef index = acc_.GetValueIn(gate, 1);
323     GateRef moduleOffset = builder_.IntPtr(JSFunction::ECMA_MODULE_OFFSET);
324     GateRef module = builder_.Load(VariableType::JS_ANY(), jsFunc, moduleOffset);
325     GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET);
326     GateRef dictionary = builder_.Load(VariableType::JS_ANY(), module, nameDictionaryOffset);
327     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
328     Label dataIsNotUndefined(&builder_);
329     Label exit(&builder_);
330     BRANCH_CIR(builder_.TaggedIsUndefined(dictionary), &exit, &dataIsNotUndefined);
331     builder_.Bind(&dataIsNotUndefined);
332     {
333         GateRef dataOffset = builder_.Int32(TaggedArray::DATA_OFFSET);
334         GateRef indexOffset = builder_.Int32Mul(index, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
335         GateRef offset = builder_.Int32Add(indexOffset, dataOffset);
336         result = builder_.Load(VariableType::JS_ANY(), dictionary, offset);
337         builder_.Jump(&exit);
338     }
339     builder_.Bind(&exit);
340     ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
341 }
342 
ReplaceGateWithPendingException(GateRef gate,GateRef state,GateRef depend,GateRef value)343 void NTypeHCRLowering::ReplaceGateWithPendingException(GateRef gate, GateRef state, GateRef depend, GateRef value)
344 {
345     auto condition = builder_.HasPendingException(glue_);
346     GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
347     GateRef ifTrue = builder_.IfTrue(ifBranch);
348     GateRef ifFalse = builder_.IfFalse(ifBranch);
349     GateRef eDepend = builder_.DependRelay(ifTrue, depend);
350     GateRef sDepend = builder_.DependRelay(ifFalse, depend);
351 
352     StateDepend success(ifFalse, sDepend);
353     StateDepend exception(ifTrue, eDepend);
354     acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
355 }
356 }
357