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_mcr_lowering.h"
17 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
18 #include "ecmascript/compiler/new_object_stub_builder.h"
19
20 namespace panda::ecmascript::kungfu {
RunNTypeMCRLowering()21 void NTypeMCRLowering::RunNTypeMCRLowering()
22 {
23 std::vector<GateRef> gateList;
24 circuit_->GetAllGates(gateList);
25
26 for (const auto &gate : gateList) {
27 Lower(gate);
28 }
29
30 if (IsLogEnabled()) {
31 LOG_COMPILER(INFO) << "";
32 LOG_COMPILER(INFO) << "\033[34m" << "=================="
33 << " after NTypeMCRlowering "
34 << "[" << GetMethodName() << "] "
35 << "==================" << "\033[0m";
36 circuit_->PrintAllGatesWithBytecode();
37 LOG_COMPILER(INFO) << "\033[34m" << "=========================== End =========================" << "\033[0m";
38 }
39 }
40
Lower(GateRef gate)41 void NTypeMCRLowering::Lower(GateRef gate)
42 {
43 GateRef glue = acc_.GetGlueFromArgList();
44 auto op = acc_.GetOpCode(gate);
45 switch (op) {
46 case OpCode::CREATE_ARRAY:
47 LowerCreateArray(gate, glue);
48 break;
49 case OpCode::CREATE_ARRAY_WITH_BUFFER:
50 LowerCreateArrayWithBuffer(gate);
51 break;
52 default:
53 break;
54 }
55 }
56
LowerCreateArray(GateRef gate,GateRef glue)57 void NTypeMCRLowering::LowerCreateArray(GateRef gate, GateRef glue)
58 {
59 Environment env(gate, circuit_, &builder_);
60 if (acc_.GetArraySize(gate) == 0) {
61 LowerCreateEmptyArray(gate);
62 } else {
63 LowerCreateArrayWithOwn(gate, glue);
64 }
65 }
66
LowerCreateEmptyArray(GateRef gate)67 void NTypeMCRLowering::LowerCreateEmptyArray(GateRef gate)
68 {
69 GateRef length = builder_.Int32(0);
70 GateRef elements = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
71
72 auto array = NewJSArrayLiteral(elements, length);
73 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
74 }
75
LowerCreateArrayWithOwn(GateRef gate,GateRef glue)76 void NTypeMCRLowering::LowerCreateArrayWithOwn(GateRef gate, GateRef glue)
77 {
78 size_t elementsLength = acc_.GetArraySize(gate);
79 GateRef length = builder_.IntPtr(elementsLength);
80 GateRef elements = Circuit::NullGate();
81 if (elementsLength < MAX_TAGGED_ARRAY_LENGTH) {
82 elements = NewTaggedArray(elementsLength);
83 } else {
84 elements = LowerCallRuntime(glue, gate, RTSTUB_ID(NewTaggedArray), { builder_.Int32ToTaggedInt(length) }, true);
85 }
86
87 auto array = NewJSArrayLiteral(elements, length);
88 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
89 }
90
LowerCreateArrayWithBuffer(GateRef gate)91 void NTypeMCRLowering::LowerCreateArrayWithBuffer(GateRef gate)
92 {
93 Environment env(gate, circuit_, &builder_);
94 // 2: number of value inputs
95 ASSERT(acc_.GetNumValueIn(gate) == 2);
96 GateRef index = acc_.GetValueIn(gate, 0);
97 GateRef aotElmIndex = acc_.GetValueIn(gate, 1);
98 auto elementIndex = acc_.GetConstantValue(aotElmIndex);
99 uint32_t elementLength = static_cast<uint32_t>(acc_.GetArraySize(gate));
100 uint32_t constPoolIndex = static_cast<uint32_t>(acc_.GetConstantValue(index));
101 ArgumentAccessor argAcc(circuit_);
102 GateRef frameState = GetFrameState(gate);
103 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
104 GateRef elements = LoadFromConstPool(jsFunc, elementIndex);
105 auto thread = tsManager_->GetEcmaVM()->GetJSThread();
106 JSHandle<ConstantPool> constpoolHandle(tsManager_->GetConstantPool());
107 JSTaggedValue arr = ConstantPool::GetLiteralFromCache<ConstPoolType::ARRAY_LITERAL>(
108 thread, constpoolHandle.GetTaggedValue(), constPoolIndex, recordName_);
109 JSHandle<JSArray> arrayHandle(thread, arr);
110 TaggedArray *arrayLiteral = TaggedArray::Cast(arrayHandle->GetElements());
111 uint32_t literialLength = arrayLiteral->GetLength();
112 uint32_t arrayLength = std::max(literialLength, elementLength);
113 GateRef length = builder_.IntPtr(arrayLength);
114
115 auto array = NewJSArrayLiteral(elements, length);
116 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
117 }
118
LoadFromConstPool(GateRef jsFunc,size_t index)119 GateRef NTypeMCRLowering::LoadFromConstPool(GateRef jsFunc, size_t index)
120 {
121 GateRef constPool = builder_.GetConstPool(jsFunc);
122 return builder_.LoadFromTaggedArray(constPool, index);
123 }
124
NewJSArrayLiteral(GateRef elements,GateRef length)125 GateRef NTypeMCRLowering::NewJSArrayLiteral(GateRef elements, GateRef length)
126 {
127 JSHandle<JSFunction> arrayFunc(tsManager_->GetEcmaVM()->GetGlobalEnv()->GetArrayFunction());
128 JSTaggedValue protoOrHClass = arrayFunc->GetProtoOrHClass();
129 JSHClass *arrayHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
130 size_t arraySize = arrayHC->GetObjectSize();
131 size_t lengthAccessorOffset = arrayHC->GetInlinedPropertiesOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX);
132
133 GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
134 GateRef globalEnv = builder_.GetGlobalEnv();
135 GateRef accessor = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_LENGTH_ACCESSOR);
136 GateRef hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
137 GateRef size = builder_.IntPtr(arrayHC->GetObjectSize());
138
139 builder_.StartAllocate();
140 GateRef array = builder_.HeapAlloc(size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
141 // initialization
142 for (size_t offset = JSArray::SIZE; offset < arraySize; offset += JSTaggedValue::TaggedTypeSize()) {
143 builder_.StoreConstOffset(VariableType::INT64(), array, offset, builder_.Undefined());
144 }
145 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, 0, hclass);
146 builder_.StoreConstOffset(VariableType::INT64(), array, ECMAObject::HASH_OFFSET,
147 builder_.Int64(JSTaggedValue(0).GetRawData()));
148 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::PROPERTIES_OFFSET, emptyArray);
149 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::ELEMENTS_OFFSET, elements);
150 builder_.StoreConstOffset(VariableType::INT32(), array, JSArray::LENGTH_OFFSET, length);
151 builder_.StoreConstOffset(VariableType::JS_POINTER(), array, lengthAccessorOffset, accessor);
152 builder_.FinishAllocate();
153 return array;
154 }
155
NewTaggedArray(size_t length)156 GateRef NTypeMCRLowering::NewTaggedArray(size_t length)
157 {
158 GateRef elementsHclass = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_CLASS_INDEX);
159 GateRef elementsSize = builder_.ComputeTaggedArraySize(builder_.IntPtr(length));
160
161 builder_.StartAllocate();
162 GateRef elements = builder_.HeapAlloc(elementsSize, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
163 builder_.StoreConstOffset(VariableType::JS_POINTER(), elements, 0, elementsHclass);
164 builder_.StoreConstOffset(VariableType::JS_ANY(), elements, TaggedArray::LENGTH_OFFSET,
165 builder_.Int32ToTaggedInt(builder_.IntPtr(length)));
166 size_t endOffset = TaggedArray::DATA_OFFSET + length * JSTaggedValue::TaggedTypeSize();
167 // initialization
168 for (size_t offset = TaggedArray::DATA_OFFSET; offset < endOffset; offset += JSTaggedValue::TaggedTypeSize()) {
169 builder_.StoreConstOffset(VariableType::INT64(), elements, offset, builder_.Hole());
170 }
171 builder_.FinishAllocate();
172
173 return elements;
174 }
175
LowerCallRuntime(GateRef glue,GateRef hirGate,int index,const std::vector<GateRef> & args,bool useLabel)176 GateRef NTypeMCRLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
177 bool useLabel)
178 {
179 if (useLabel) {
180 GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, hirGate);
181 return result;
182 } else {
183 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
184 GateRef target = builder_.IntPtr(index);
185 GateRef result = builder_.Call(cs, glue, target, dependEntry_, args, hirGate);
186 return result;
187 }
188 }
189 }
190