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