• 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 #include "ecmascript/compiler/native_inline_lowering.h"
16 #include "ecmascript/compiler/circuit_builder-inl.h"
17 #include "ecmascript/compiler/circuit_builder_helper.h"
18 #include "ecmascript/compiler/circuit.h"
19 #include "ecmascript/js_thread.h"
20 #include "ecmascript/message_string.h"
21 
22 namespace panda::ecmascript::kungfu {
RunNativeInlineLowering()23 void NativeInlineLowering::RunNativeInlineLowering()
24 {
25     std::vector<GateRef> gateList;
26     circuit_->GetAllGates(gateList);
27     for (const auto &gate : gateList) {
28         auto op = acc_.GetOpCode(gate);
29         if (op == OpCode::JS_BYTECODE) {
30             EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
31             switch (ecmaOpcode) {
32                 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
33                     TryInlineNativeCallThis1(gate);
34                     break;
35                 default:
36                     break;
37             }
38         }
39     }
40 
41     if (EnableLog()) {
42         LOG_COMPILER(INFO) << " ";
43         LOG_COMPILER(INFO) << "\033[34m" << "================="
44                            << " After Native Inline Lowering "
45                            << "[" << GetMethodName() << "] "
46                            << "=================" << "\033[0m";
47         circuit_->PrintAllGatesWithBytecode();
48         LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
49     }
50 }
51 
TryInlineNativeCallThis1(GateRef gate)52 void NativeInlineLowering::TryInlineNativeCallThis1(GateRef gate)
53 {
54     CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate);
55     BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinId();
56     switch (id) {
57         case BuiltinsStubCSigns::ID::StringFromCharCode: {
58             TryInlineStringFromCharCode(gate, tacc);
59             break;
60         }
61         default:
62             break;
63     }
64 }
65 
TryInlineStringFromCharCode(GateRef gate,CallThis1TypeInfoAccessor & tacc)66 void NativeInlineLowering::TryInlineStringFromCharCode(GateRef gate, CallThis1TypeInfoAccessor &tacc)
67 {
68     if (acc_.GetByteCodeOpcode(gate) != EcmaOpcode::CALLTHIS1_IMM8_V8_V8) {
69         return;
70     }
71     Environment env(gate, circuit_, &builder_);
72     if (!Uncheck()) {
73         builder_.CallTargetCheck(gate, tacc.GetFunc(),
74                                  builder_.IntPtr(static_cast<int64_t>(BuiltinsStubCSigns::ID::StringFromCharCode)),
75                                  tacc.GetArg0());
76     }
77     GateRef ret = builder_.StringFromSingleCharCode(tacc.GetArg0());
78     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
79 }
80 
TryInlineBuiltinsArrayFunc(GateRef gate)81 void NativeInlineLowering::TryInlineBuiltinsArrayFunc(GateRef gate)
82 {
83     GateRef func = acc_.GetValueIn(gate, acc_.GetNumValueIn(gate) - 1); // 1: last value in
84     GateType funcType = acc_.GetGateType(func);
85     if (tsManager_->IsBuiltinObjectMethod(BuiltinTypeId::ARRAY, funcType)) {
86         std::string name = tsManager_->GetFuncName(funcType);
87         if (name == "forEach") {
88             RunArrayForeachInline(gate);
89         }
90     }
91 }
92 
RunArrayForeachInline(GateRef gate)93 void NativeInlineLowering::RunArrayForeachInline(GateRef gate)
94 {
95     Environment env(gate, circuit_, &builder_);
96 
97     GateRef thisObj = acc_.GetValueIn(gate, 0);
98     GateRef callBack = acc_.GetValueIn(gate, 1);
99     GateRef thisArg = builder_.Undefined();
100     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
101     if (ecmaOpcode == EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8) {
102         thisArg = acc_.GetValueIn(gate, 2); // 2: this arg parameter
103     }
104     builder_.BuiltinPrototypeHClassCheck(thisObj, BuiltinTypeId::ARRAY);
105     ElementsKind kind = acc_.TryGetArrayElementsKind(thisObj);
106     if (!IsCreateArray(thisObj)) {
107         builder_.StableArrayCheck(thisObj, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
108     }
109     Label callBackIsCallable(&builder_);
110     Label callBackNotCallable(&builder_);
111     builder_.Branch(builder_.IsCallable(callBack), &callBackIsCallable, &callBackNotCallable);
112     builder_.Bind(&callBackNotCallable);
113     {
114         GateRef taggedId = builder_.Int64(GET_MESSAGE_STRING_ID(NonCallable));
115         LowerCallRuntime(glue_, gate, RTSTUB_ID(ThrowTypeError), { builder_.ToTaggedIntPtr(taggedId) }, true);
116         GateRef exception = builder_.ExceptionConstant();
117         builder_.Return(exception);
118     }
119     builder_.Bind(&callBackIsCallable);
120     Label exit(&builder_);
121     ArrayForeachCall(gate, thisObj, callBack, thisArg, &exit);
122     builder_.Bind(&exit);
123     ReplaceHirDirectly(gate, builder_.Undefined());
124 }
125 
ArrayForeachCall(GateRef gate,GateRef thisObj,GateRef callBack,GateRef thisArg,Label * exit)126 void NativeInlineLowering::ArrayForeachCall(GateRef gate, GateRef thisObj, GateRef callBack, GateRef thisArg,
127                                             Label *exit)
128 {
129     GateRef length = builder_.LoadArrayLength(thisObj);
130     Label loopHead(&builder_);
131     Label loopEnd(&builder_);
132     Label exitloop(&builder_);
133     Label slowForeach(&builder_);
134     DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
135     DEFVALUE(propKey, (&builder_), VariableType::JS_ANY(), builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(*i)));
136     DEFVALUE(value, (&builder_), VariableType::JS_ANY(), builder_.Hole());
137     builder_.Branch(builder_.Int32LessThan(*i, length), &loopHead, &exitloop);
138     builder_.LoopBegin(&loopHead);
139     ElementsKind kind = acc_.TryGetArrayElementsKind(thisObj);
140     value = LoadArrayElement(kind, thisObj, *i);
141     Label NotHole(&builder_);
142     Label merge(&builder_);
143     builder_.Branch(builder_.NotEqual(*value, builder_.Hole()), &NotHole, &exitloop);
144     builder_.Bind(&NotHole);
145     {
146         auto depend = builder_.GetDepend();
147         GateRef nativeCall = NativeCallTS(gate, depend,
148             {glue_, builder_.Int64(6), callBack, builder_.Undefined(), thisArg, *value, *propKey, thisObj}); // 6: args
149         builder_.SetDepend(nativeCall);
150         i = builder_.Int32Add(*i, builder_.Int32(1));
151         propKey = builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(*i));
152         builder_.Branch(builder_.IsStabelArray(glue_, thisObj), &merge, &exitloop);
153     }
154     builder_.Bind(&merge);
155     builder_.Branch(builder_.Int32LessThan(*i, length), &loopEnd, &exitloop);
156     builder_.Bind(&loopEnd);
157     builder_.LoopEnd(&loopHead);
158     builder_.Bind(&exitloop);
159     builder_.Branch(builder_.Int32LessThan(*i, length), &slowForeach, exit);
160     builder_.Bind(&slowForeach);
161     {
162         GateRef taggedLength = builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(length));
163         GateRef slowPathCall = LowerCallRuntime(glue_, gate, RTSTUB_ID(ArrayForEachContinue),
164             {thisArg, *propKey, thisObj, callBack, taggedLength}, true);
165         builder_.SetDepend(slowPathCall);
166         builder_.Jump(exit);
167     }
168 }
169 
IsCreateArray(GateRef gate)170 bool NativeInlineLowering::IsCreateArray(GateRef gate)
171 {
172     if (acc_.GetOpCode(gate) != OpCode::JS_BYTECODE) {
173         return false;
174     }
175     EcmaOpcode ecmaop = acc_.GetByteCodeOpcode(gate);
176     switch (ecmaop) {
177         case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
178         case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
179         case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
180         case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
181             return true;
182         default:
183             return false;
184     }
185     UNREACHABLE();
186     return false;
187 }
188 
LoadArrayElement(ElementsKind kind,GateRef gate,GateRef index)189 GateRef NativeInlineLowering::LoadArrayElement(ElementsKind kind, GateRef gate, GateRef index)
190 {
191     switch (kind) {
192         case ElementsKind::INT:
193             return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(gate, index);
194         case ElementsKind::NUMBER:
195             return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(gate, index);
196         case ElementsKind::OBJECT:
197             return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(gate, index);
198         default:
199             if (!Elements::IsHole(kind)) {
200                 return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(gate, index);
201             }
202     }
203     return builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(gate, index);
204 }
205 
ReplaceHirDirectly(GateRef gate,GateRef value)206 void NativeInlineLowering::ReplaceHirDirectly(GateRef gate, GateRef value)
207 {
208     GateRef state = builder_.GetState();
209     GateRef depend = builder_.GetDepend();
210     auto uses = acc_.Uses(gate);
211     for (auto it = uses.begin(); it != uses.end();) {
212         if (acc_.IsStateIn(it)) {
213             ASSERT(acc_.GetOpCode(*it) != OpCode::IF_SUCCESS &&
214                 acc_.GetOpCode(*it) != OpCode::IF_EXCEPTION);
215             it = acc_.ReplaceIn(it, state);
216         } else if (acc_.IsDependIn(it)) {
217             it = acc_.ReplaceIn(it, depend);
218         } else {
219             ASSERT(acc_.IsValueIn(it));
220             it = acc_.ReplaceIn(it, value);
221         }
222     }
223     acc_.DeleteGate(gate);
224 }
225 
LowerCallRuntime(GateRef glue,GateRef hirGate,int index,const std::vector<GateRef> & args,bool useLabel)226 GateRef NativeInlineLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int index,
227     const std::vector<GateRef> &args, bool useLabel)
228 {
229     if (useLabel) {
230         GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, hirGate);
231         return result;
232     } else {
233         const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
234         GateRef target = builder_.IntPtr(index);
235         GateRef result = builder_.Call(cs, glue, target, acc_.GetDependRoot(), args, hirGate);
236         return result;
237     }
238 }
239 
NativeCallTS(GateRef gate,GateRef depend,const std::vector<GateRef> & args)240 GateRef NativeInlineLowering::NativeCallTS(GateRef gate, GateRef depend, const std::vector<GateRef> &args)
241 {
242     const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
243     GateRef target = builder_.IntPtr(RTSTUB_ID(JSCall));
244     GateRef call = builder_.Call(cs, glue_, target, depend, args, gate);
245     return call;
246 }
247 }  // namespace panda::ecmascript
248