• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/type_inference/type_infer.h"
17 
18 #include "ecmascript/jspandafile/js_pandafile_manager.h"
19 #include "ecmascript/jspandafile/program_object.h"
20 #include "ecmascript/ts_types/ts_type_parser.h"
21 
22 namespace panda::ecmascript::kungfu {
TraverseCircuit()23 void TypeInfer::TraverseCircuit()
24 {
25     std::vector<GateRef> gateList;
26     circuit_->GetAllGates(gateList);
27     for (auto gate : gateList) {
28         pendingQueue_.push(gate);
29     }
30     // init jsgateToBytecode
31     BytecodeIterator iterator(builder_, 0, builder_->GetLastBcIndex());
32     for (iterator.GotoStart(); !iterator.Done(); ++iterator) {
33         auto index = iterator.Index();
34         GateRef gate = builder_->GetGateByBcIndex(index);
35         if (gate != Circuit::NullGate()) {
36             jsgateToBytecode_[gate] = index;
37         }
38     }
39     TraverseInfer();
40 
41     if (IsLogEnabled()) {
42         PrintAllByteCodesTypes();
43     }
44 
45     if (tsManager_->AssertTypes()) {
46         Verify();
47     }
48 
49     if (tsManager_->PrintAnyTypes()) {
50         FilterAnyTypeGates();
51     }
52     if (IsLogEnabled()) {
53         LOG_COMPILER(INFO) << "";
54         LOG_COMPILER(INFO) << "\033[34m"
55                            << "===================="
56                            << " After ts type infer "
57                            << "[" << GetMethodName() << "]"
58                            << "===================="
59                            << "\033[0m";
60         circuit_->PrintAllGatesWithBytecode();
61         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
62     }
63 }
64 
TraverseInfer()65 void TypeInfer::TraverseInfer()
66 {
67     bool needUpdateForLoopPhi = true;
68     // main type infer for all gates
69     while (!pendingQueue_.empty()) {
70         auto curGate = pendingQueue_.front();
71         inQueue_[gateAccessor_.GetId(curGate)] = false;
72         pendingQueue_.pop();
73         auto uses = gateAccessor_.ConstUses(curGate);
74         for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
75             auto gateId = gateAccessor_.GetId(*useIt);
76             if (Infer(*useIt) && !inQueue_[gateId]) {
77                 inQueue_[gateId] = true;
78                 pendingQueue_.push(*useIt);
79             }
80         }
81         if (pendingQueue_.empty() && needUpdateForLoopPhi) {
82             // only for loop begin phi
83             UpdateQueueForLoopPhi();
84             needUpdateForLoopPhi = false;
85         }
86     }
87 }
88 
UpdateQueueForLoopPhi()89 void TypeInfer::UpdateQueueForLoopPhi()
90 {
91     for (auto it = loopPhiState_.begin(); it != loopPhiState_.end(); it++) {
92         auto curGate = it->first;
93         auto loopType = gateAccessor_.GetGateType(curGate);
94         auto loopBackGate = gateAccessor_.GetValueIn(curGate, 1);
95         auto loopBackType = gateAccessor_.GetGateType(loopBackGate);
96         // if loopBack Gate is finally AnyType, loop-begin phi gate should be changed to any
97         if (!loopType.IsAnyType() && loopBackType.IsAnyType()) {
98             gateAccessor_.SetGateType(curGate, GateType::AnyType());
99             loopPhiState_[curGate] = InferState::ANY_INFERED;
100             pendingQueue_.push(curGate);
101             inQueue_[gateAccessor_.GetId(curGate)] = true;
102         }
103         // if loopBack Gate is finally not same number Type, loop-begin phi gate should be promoted
104         if (loopType.IsNumberType() && loopBackType.IsNumberType() && loopType != loopBackType) {
105             gateAccessor_.SetGateType(curGate, GateType::NumberType());
106             loopPhiState_[curGate] = InferState::NUMBER_INFERED;
107             pendingQueue_.push(curGate);
108             inQueue_[gateAccessor_.GetId(curGate)] = true;
109         }
110     }
111 }
112 
UpdateType(GateRef gate,const GateType type)113 bool TypeInfer::UpdateType(GateRef gate, const GateType type)
114 {
115     auto preType = gateAccessor_.GetGateType(gate);
116     if (type != preType) {
117         gateAccessor_.SetGateType(gate, type);
118         return true;
119     }
120     return false;
121 }
122 
UpdateType(GateRef gate,const GlobalTSTypeRef & typeRef)123 bool TypeInfer::UpdateType(GateRef gate, const GlobalTSTypeRef &typeRef)
124 {
125     auto type = GateType(typeRef);
126     return UpdateType(gate, type);
127 }
128 
IsNewLexEnv(EcmaOpcode opcode) const129 bool TypeInfer::IsNewLexEnv(EcmaOpcode opcode) const
130 {
131     switch (opcode) {
132         case EcmaOpcode::NEWLEXENV_IMM8:
133         case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16:
134         case EcmaOpcode::WIDE_NEWLEXENV_PREF_IMM16:
135         case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
136             return true;
137         default:
138             return false;
139     }
140 }
141 
ShouldInfer(const GateRef gate) const142 bool TypeInfer::ShouldInfer(const GateRef gate) const
143 {
144     auto opcode = gateAccessor_.GetOpCode(gate);
145     // handle phi gates
146     if (opcode == OpCode::VALUE_SELECTOR) {
147         return true;
148     }
149     /* Handle constant gates (like ldnull and ldtrue), return gates and gates generated by ecma.* bytecodes (not
150      * including jump and newlexenv). Jump instructions are skipped because they have no intrinsic type information.
151      * And newlexenv instructions are used to create runtime lexical env objects which have no TS types associated. As
152      * for the type inference on lexical variables, their type information is recorded in objects of class
153      * panda::ecmascript::kungfu::LexEnv which are created during the building of IR. So in the type inference,
154      * newlexenv is ignored.
155      */
156     if (opcode != OpCode::CONSTANT && opcode != OpCode::RETURN && opcode != OpCode::JS_BYTECODE) {
157         return false;
158     }
159     if (jsgateToBytecode_.find(gate) == jsgateToBytecode_.end()) {
160         return false;
161     }
162     auto &bytecodeInfo = GetByteCodeInfo(gate);
163     return !bytecodeInfo.IsJump() && !IsNewLexEnv(bytecodeInfo.GetOpcode());
164 }
165 
Infer(GateRef gate)166 bool TypeInfer::Infer(GateRef gate)
167 {
168     if (!ShouldInfer(gate)) {
169         return false;
170     }
171     if (gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR) {
172         return InferPhiGate(gate);
173     }
174     // infer ecma.* bytecode gates
175     auto &bytecodeInfo = GetByteCodeInfo(gate);
176     switch (bytecodeInfo.GetOpcode()) {
177         case EcmaOpcode::LDNAN:
178         case EcmaOpcode::LDINFINITY:
179         case EcmaOpcode::MOD2_IMM8_V8:
180         case EcmaOpcode::AND2_IMM8_V8:
181         case EcmaOpcode::OR2_IMM8_V8:
182         case EcmaOpcode::XOR2_IMM8_V8:
183         case EcmaOpcode::TONUMBER_IMM8:
184         case EcmaOpcode::TONUMERIC_IMM8:
185         case EcmaOpcode::NEG_IMM8:
186         case EcmaOpcode::EXP_IMM8_V8:
187         case EcmaOpcode::STARRAYSPREAD_V8_V8:
188             return SetNumberType(gate);
189         case EcmaOpcode::SHL2_IMM8_V8:
190         case EcmaOpcode::ASHR2_IMM8_V8:
191         case EcmaOpcode::SHR2_IMM8_V8:
192         case EcmaOpcode::NOT_IMM8:
193             return SetIntType(gate);
194         case EcmaOpcode::LDBIGINT_ID16:
195             return SetBigIntType(gate);
196         case EcmaOpcode::LDTRUE:
197         case EcmaOpcode::LDFALSE:
198         case EcmaOpcode::EQ_IMM8_V8:
199         case EcmaOpcode::NOTEQ_IMM8_V8:
200         case EcmaOpcode::LESS_IMM8_V8:
201         case EcmaOpcode::LESSEQ_IMM8_V8:
202         case EcmaOpcode::GREATER_IMM8_V8:
203         case EcmaOpcode::GREATEREQ_IMM8_V8:
204         case EcmaOpcode::ISIN_IMM8_V8:
205         case EcmaOpcode::INSTANCEOF_IMM8_V8:
206         case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
207         case EcmaOpcode::STRICTEQ_IMM8_V8:
208         case EcmaOpcode::ISTRUE:
209         case EcmaOpcode::ISFALSE:
210         case EcmaOpcode::SETOBJECTWITHPROTO_IMM8_V8:
211         case EcmaOpcode::SETOBJECTWITHPROTO_IMM16_V8:
212         case EcmaOpcode::DELOBJPROP_V8:
213             return SetBooleanType(gate);
214         case EcmaOpcode::LDUNDEFINED:
215             return InferLdUndefined(gate);
216         case EcmaOpcode::LDNULL:
217             return InferLdNull(gate);
218         case EcmaOpcode::LDAI_IMM32:
219             return InferLdai(gate);
220         case EcmaOpcode::FLDAI_IMM64:
221             return InferFLdai(gate);
222         case EcmaOpcode::LDSYMBOL:
223             return InferLdSymbol(gate);
224         case EcmaOpcode::THROW_PREF_NONE:
225             return InferThrow(gate);
226         case EcmaOpcode::TYPEOF_IMM8:
227         case EcmaOpcode::TYPEOF_IMM16:
228             return InferTypeOf(gate);
229         case EcmaOpcode::ADD2_IMM8_V8:
230             return InferAdd2(gate);
231         case EcmaOpcode::SUB2_IMM8_V8:
232             return InferSub2(gate);
233         case EcmaOpcode::MUL2_IMM8_V8:
234             return InferMul2(gate);
235         case EcmaOpcode::DIV2_IMM8_V8:
236             return InferDiv2(gate);
237         case EcmaOpcode::INC_IMM8:
238         case EcmaOpcode::DEC_IMM8:
239             return InferIncDec(gate);
240         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
241         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
242         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
243             return InferLdObjByIndex(gate);
244         case EcmaOpcode::STGLOBALVAR_IMM16_ID16:
245         case EcmaOpcode::TRYSTGLOBALBYNAME_IMM8_ID16:
246         case EcmaOpcode::TRYSTGLOBALBYNAME_IMM16_ID16:
247             return SetStGlobalBcType(gate, true);
248         case EcmaOpcode::STTOGLOBALRECORD_IMM16_ID16:
249         case EcmaOpcode::STCONSTTOGLOBALRECORD_IMM16_ID16:
250             return SetStGlobalBcType(gate, false);
251         case EcmaOpcode::LDGLOBALVAR_IMM16_ID16:
252             return InferLdGlobalVar(gate);
253         case EcmaOpcode::RETURNUNDEFINED:
254             return InferReturnUndefined(gate);
255         case EcmaOpcode::RETURN:
256             return InferReturn(gate);
257         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
258         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
259             return InferLdObjByName(gate);
260         case EcmaOpcode::LDA_STR_ID16:
261             return InferLdStr(gate);
262         case EcmaOpcode::CALLARG0_IMM8:
263         case EcmaOpcode::CALLARG1_IMM8_V8:
264         case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
265         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
266         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
267         case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
268         case EcmaOpcode::CALLTHIS0_IMM8_V8:
269         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
270         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
271         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
272         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
273         case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
274         case EcmaOpcode::APPLY_IMM8_V8_V8:
275             return InferCallFunction(gate);
276         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
277         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
278             return InferLdObjByValue(gate);
279         case EcmaOpcode::GETNEXTPROPNAME_V8:
280             return InferGetNextPropName(gate);
281         case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
282             return InferDefineGetterSetterByValue(gate);
283         case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
284         case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
285         case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
286         case EcmaOpcode::NEWOBJAPPLY_IMM8_V8:
287         case EcmaOpcode::NEWOBJAPPLY_IMM16_V8:
288             return InferNewObject(gate);
289         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
290         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
291         case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
292         case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
293         case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8:
294             return InferSuperCall(gate);
295         case EcmaOpcode::LDSUPERBYNAME_IMM8_ID16:
296         case EcmaOpcode::LDSUPERBYNAME_IMM16_ID16:
297             return InferSuperPropertyByName(gate);
298         case EcmaOpcode::LDSUPERBYVALUE_IMM8_V8:
299         case EcmaOpcode::LDSUPERBYVALUE_IMM16_V8:
300             return InferSuperPropertyByValue(gate);
301         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
302         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
303             return InferTryLdGlobalByName(gate);
304         case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
305         case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
306         case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
307             return InferLdLexVarDyn(gate);
308         case EcmaOpcode::STLEXVAR_IMM4_IMM4:
309         case EcmaOpcode::STLEXVAR_IMM8_IMM8:
310         case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
311             return InferStLexVarDyn(gate);
312         case EcmaOpcode::GETITERATOR_IMM8:
313         case EcmaOpcode::GETITERATOR_IMM16:
314             return InferGetIterator(gate);
315         case EcmaOpcode::STMODULEVAR_IMM8:
316         case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
317             return InferStModuleVar(gate);
318         case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
319         case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
320             return InferLdLocalModuleVar(gate);
321         default:
322             break;
323     }
324     return false;
325 }
326 
InferPhiGate(GateRef gate)327 bool TypeInfer::InferPhiGate(GateRef gate)
328 {
329     ASSERT(gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR);
330     CVector<GlobalTSTypeRef> typeList;
331     std::set<GlobalTSTypeRef> numberTypeSet;
332     auto ins = gateAccessor_.ConstIns(gate);
333     for (auto it =  ins.begin(); it != ins.end(); it++) {
334         // assuming that VALUE_SELECTOR is NO_DEPEND and NO_ROOT
335         if (gateAccessor_.GetOpCode(*it) == OpCode::MERGE) {
336             continue;
337         }
338         if (gateAccessor_.GetOpCode(*it) == OpCode::LOOP_BEGIN) {
339             return InferLoopBeginPhiGate(gate);
340         }
341         auto valueInType = gateAccessor_.GetGateType(*it);
342         if (valueInType.IsAnyType()) {
343             return UpdateType(gate, valueInType);
344         }
345         if (valueInType.IsNumberType()) {
346             numberTypeSet.insert(valueInType.GetGTRef());
347         } else {
348             typeList.emplace_back(valueInType.GetGTRef());
349         }
350     }
351     // deduplicate
352     std::sort(typeList.begin(), typeList.end());
353     auto deduplicateIndex = std::unique(typeList.begin(), typeList.end());
354     typeList.erase(deduplicateIndex, typeList.end());
355     if (numberTypeSet.size() == 1) {
356         typeList.emplace_back(*(numberTypeSet.begin()));
357     } else if (numberTypeSet.size() > 1) {
358         typeList.emplace_back(GateType::NumberType().GetGTRef());
359     }
360     if (typeList.size() > 1) {
361         auto unionType = tsManager_->GetOrCreateUnionType(typeList);
362         return UpdateType(gate, unionType);
363     }
364     auto type = typeList.at(0);
365     return UpdateType(gate, type);
366 }
367 
SetIntType(GateRef gate)368 bool TypeInfer::SetIntType(GateRef gate)
369 {
370     auto intType = GateType::IntType();
371     return UpdateType(gate, intType);
372 }
373 
SetNumberType(GateRef gate)374 bool TypeInfer::SetNumberType(GateRef gate)
375 {
376     auto numberType = GateType::NumberType();
377     return UpdateType(gate, numberType);
378 }
379 
SetBigIntType(GateRef gate)380 bool TypeInfer::SetBigIntType(GateRef gate)
381 {
382     auto bigIntType = GateType::BigIntType();
383     return UpdateType(gate, bigIntType);
384 }
385 
SetBooleanType(GateRef gate)386 bool TypeInfer::SetBooleanType(GateRef gate)
387 {
388     auto booleanType = GateType::BooleanType();
389     return UpdateType(gate, booleanType);
390 }
391 
InferLdUndefined(GateRef gate)392 bool TypeInfer::InferLdUndefined(GateRef gate)
393 {
394     auto undefinedType = GateType::UndefinedType();
395     return UpdateType(gate, undefinedType);
396 }
397 
InferLdNull(GateRef gate)398 bool TypeInfer::InferLdNull(GateRef gate)
399 {
400     auto nullType = GateType::NullType();
401     return UpdateType(gate, nullType);
402 }
403 
InferLdai(GateRef gate)404 bool TypeInfer::InferLdai(GateRef gate)
405 {
406     auto intType = GateType::IntType();
407     return UpdateType(gate, intType);
408 }
409 
InferFLdai(GateRef gate)410 bool TypeInfer::InferFLdai(GateRef gate)
411 {
412     auto doubleType = GateType::DoubleType();
413     return UpdateType(gate, doubleType);
414 }
415 
InferLdSymbol(GateRef gate)416 bool TypeInfer::InferLdSymbol(GateRef gate)
417 {
418     auto symbolType = GateType::SymbolType();
419     return UpdateType(gate, symbolType);
420 }
421 
InferThrow(GateRef gate)422 bool TypeInfer::InferThrow(GateRef gate)
423 {
424     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
425     auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
426     return UpdateType(gate, gateType);
427 }
428 
InferTypeOf(GateRef gate)429 bool TypeInfer::InferTypeOf(GateRef gate)
430 {
431     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
432     auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
433     return UpdateType(gate, gateType);
434 }
435 
436 /*
437  * Type Infer rule(satisfy commutative law):
438  * number + number = number
439  * int    + number = number
440  * double + number = double
441  * int    + int    = int
442  * int    + double = double
443  * double + double = double
444  * string + string = string
445  */
InferAdd2(GateRef gate)446 bool TypeInfer::InferAdd2(GateRef gate)
447 {
448     // 2: number of value inputs
449     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
450     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
451     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
452     if (firInType.IsStringType() || secInType.IsStringType()) {
453         return UpdateType(gate, GateType::StringType());
454     }
455     if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
456         (firInType.IsDoubleType() && secInType.IsNumberType())) {
457         return UpdateType(gate, GateType::DoubleType());
458     }
459     if ((firInType.IsIntType() && secInType.IsIntType())) {
460         return UpdateType(gate, GateType::IntType());
461     }
462     if (firInType.IsNumberType() && secInType.IsNumberType()) {
463         return UpdateType(gate, GateType::NumberType());
464     }
465     return UpdateType(gate, GateType::AnyType());
466 }
467 
468 /*
469  * Type Infer rule(satisfy commutative law):
470  * number - number = number
471  * int    - number = number
472  * double - number = double
473  * int    - int    = int
474  * int    - double = double
475  * double - double = double
476  */
InferSub2(GateRef gate)477 bool TypeInfer::InferSub2(GateRef gate)
478 {
479     // 2: number of value inputs
480     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
481     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
482     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
483     if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
484         (firInType.IsDoubleType() && secInType.IsNumberType())) {
485         return UpdateType(gate, GateType::DoubleType());
486     }
487     if ((firInType.IsIntType() && secInType.IsIntType())) {
488         return UpdateType(gate, GateType::IntType());
489     }
490     return UpdateType(gate, GateType::NumberType());
491 }
492 
493 /*
494  * Type Infer rule(satisfy commutative law):
495  * number * number = number
496  * int    * number = number
497  * double * number = double
498  * int    * int    = int
499  * int    * double = double
500  * double * double = double
501  */
InferMul2(GateRef gate)502 bool TypeInfer::InferMul2(GateRef gate)
503 {
504     // 2: number of value inputs
505     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
506     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
507     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
508     if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
509         (firInType.IsDoubleType() && secInType.IsNumberType())) {
510         return UpdateType(gate, GateType::DoubleType());
511     }
512     if ((firInType.IsIntType() && secInType.IsIntType())) {
513         return UpdateType(gate, GateType::IntType());
514     }
515     return UpdateType(gate, GateType::NumberType());
516 }
517 
518 /*
519  * Type Infer rule(satisfy commutative law):
520  * in type lowering, both elements will be changed to float64 firstly.
521  * number / number = double
522  * int    / number = double
523  * double / number = double
524  * int    / int    = double
525  * int    / double = double
526  * double / double = double
527  * any    / any    = number
528  * any    / number = number
529  * number / any    = number
530  */
InferDiv2(GateRef gate)531 bool TypeInfer::InferDiv2(GateRef gate)
532 {
533     // 2: number of value inputs
534     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
535     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
536     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
537     if (firInType.IsNumberType() && secInType.IsNumberType()) {
538         return UpdateType(gate, GateType::DoubleType());
539     }
540     return UpdateType(gate, GateType::NumberType());
541 }
542 
543 /*
544  * Type Infer rule:
545  * number++ = number
546  * number-- = number
547  * int++    = int
548  * int--    = int
549  * double++ = double
550  * double-- = double
551  */
InferIncDec(GateRef gate)552 bool TypeInfer::InferIncDec(GateRef gate)
553 {
554     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
555     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
556     if (firInType.IsDoubleType()) {
557         return UpdateType(gate, GateType::DoubleType());
558     }
559     if (firInType.IsIntType()) {
560         return UpdateType(gate, GateType::IntType());
561     }
562     return UpdateType(gate, GateType::NumberType());
563 }
564 
InferLdObjByIndex(GateRef gate)565 bool TypeInfer::InferLdObjByIndex(GateRef gate)
566 {
567     // 2: number of value inputs
568     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
569     auto inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
570     if (tsManager_->IsArrayTypeKind(inValueType)) {
571         auto type = tsManager_->GetArrayParameterTypeGT(inValueType);
572         return UpdateType(gate, type);
573     }
574 
575     if (tsManager_->IsTypedArrayType(inValueType)) {
576         return UpdateType(gate, GateType::NumberType());
577     }
578 
579     if (ShouldInferWithLdObjByValue(inValueType)) {
580         auto key = gateAccessor_.GetConstantValue((gateAccessor_.GetValueIn(gate, 0)));
581         auto type = GetPropType(inValueType, key);
582         return UpdateType(gate, type);
583     }
584     return false;
585 }
586 
SetStGlobalBcType(GateRef gate,bool hasIC)587 bool TypeInfer::SetStGlobalBcType(GateRef gate, bool hasIC)
588 {
589     auto &byteCodeInfo = GetByteCodeInfo(gate);
590     uint16_t stringId = 0;
591     GateType inValueType;
592     if (hasIC) {
593         // 2: number of value inputs
594         ASSERT(byteCodeInfo.inputs.size() == 2);
595         stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
596         // 3: number of value inputs
597         ASSERT(gateAccessor_.GetNumValueIn(gate) == 3);
598         // 2: value input
599         inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2));
600     } else {
601         ASSERT(byteCodeInfo.inputs.size() == 1);
602         stringId = std::get<ConstDataId>(byteCodeInfo.inputs[0]).GetId();
603         // 2: number of value inputs
604         ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
605         inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
606     }
607     if (stringIdToGateType_.find(stringId) != stringIdToGateType_.end()) {
608         stringIdToGateType_[stringId] = inValueType;
609     } else {
610         stringIdToGateType_.emplace(stringId, inValueType);
611     }
612     return UpdateType(gate, inValueType);
613 }
614 
InferLdGlobalVar(GateRef gate)615 bool TypeInfer::InferLdGlobalVar(GateRef gate)
616 {
617     auto &byteCodeInfo = GetByteCodeInfo(gate);
618     ASSERT(byteCodeInfo.inputs.size() == 2);  // 2: number of value inputs
619     auto stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
620     auto iter = stringIdToGateType_.find(stringId);
621     if (iter != stringIdToGateType_.end()) {
622         return UpdateType(gate, iter->second);
623     }
624     return false;
625 }
626 
InferReturnUndefined(GateRef gate)627 bool TypeInfer::InferReturnUndefined(GateRef gate)
628 {
629     auto undefinedType = GateType::UndefinedType();
630     return UpdateType(gate, undefinedType);
631 }
632 
InferReturn(GateRef gate)633 bool TypeInfer::InferReturn(GateRef gate)
634 {
635     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
636     auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
637     return UpdateType(gate, gateType);
638 }
639 
InferLdObjByName(GateRef gate)640 bool TypeInfer::InferLdObjByName(GateRef gate)
641 {
642     // 3: number of value inputs
643     ASSERT(gateAccessor_.GetNumValueIn(gate) == 3);
644     auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2));  // 2: the third parameter is receiver
645     if (objType.IsAnyType()) {
646         return false;
647     }
648 
649     if (ShouldConvertToBuiltinArray(objType)) {
650         GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType);
651         auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt);
652         objType = GateType(builtinInstanceType);
653     }
654     if (tsManager_->IsPrimitiveTypeKind(objType)) {
655         GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType);
656         if (builtinGt.GetModuleId() == TSModuleTable::BUILTINS_TABLE_ID) {
657             auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt);
658             objType = GateType(builtinInstanceType);
659         }
660     }
661     // If this object has no gt type, we cannot get its internal property type
662     if (ShouldInferWithLdObjByName(objType)) {
663         uint16_t index = gateAccessor_.GetConstDataId(gateAccessor_.GetValueIn(gate, 1)).GetId();
664         return GetObjPropWithName(gate, objType, index);
665     }
666     return false;
667 }
668 
InferNewObject(GateRef gate)669 bool TypeInfer::InferNewObject(GateRef gate)
670 {
671     auto objType = gateAccessor_.GetGateType(gate);
672     if (!tsManager_->IsClassInstanceTypeKind(objType) && !tsManager_->IsArrayTypeKind(objType)) {
673         ASSERT(gateAccessor_.GetNumValueIn(gate) > 0);
674         auto classType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
675         if (tsManager_->IsClassTypeKind(classType)) {
676             auto classInstanceType = tsManager_->CreateClassInstanceType(classType);
677             return UpdateType(gate, classInstanceType);
678         }
679     }
680     return false;
681 }
682 
InferLdStr(GateRef gate)683 bool TypeInfer::InferLdStr(GateRef gate)
684 {
685     auto stringType = GateType::StringType();
686     return UpdateType(gate, stringType);
687 }
688 
GetObjPropWithName(GateRef gate,GateType objType,uint64_t index)689 bool TypeInfer::GetObjPropWithName(GateRef gate, GateType objType, uint64_t index)
690 {
691     auto thread = tsManager_->GetEcmaVM()->GetJSThread();
692     JSHandle<ConstantPool> constantPool(tsManager_->GetConstantPool());
693     JSTaggedValue name = ConstantPool::GetStringFromCache(thread, constantPool.GetTaggedValue(), index);
694     if (tsManager_->IsBuiltinArrayType(objType) || tsManager_->IsTypedArrayType(objType)) {
695         JSTaggedValue lengthKey = thread->GlobalConstants()->GetLengthString();
696         if (JSTaggedValue::SameValue(name, lengthKey)) {
697             return SetIntType(gate);
698         }
699     }
700     auto type = GetPropType(objType, name);
701     if (tsManager_->IsGetterSetterFunc(type)) {
702         auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type);
703         return UpdateType(gate, returnGt);
704     }
705     return UpdateType(gate, type);
706 }
707 
InferCallFunction(GateRef gate)708 bool TypeInfer::InferCallFunction(GateRef gate)
709 {
710     // 1: last one elem is function
711     size_t funcIndex = gateAccessor_.GetNumValueIn(gate) - 1;
712     auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex));
713     if (tsManager_->IsFunctionTypeKind(funcType)) {
714         auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType);
715         return UpdateType(gate, returnType);
716     }
717 
718     if (tsManager_->IsIteratorInstanceTypeKind(funcType)) {
719         GlobalTSTypeRef elementGT = tsManager_->GetIteratorInstanceElementGt(funcType);
720         GlobalTSTypeRef iteratorResultInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType(
721             TSRuntimeType::ITERATOR_RESULT, elementGT);
722         return UpdateType(gate, iteratorResultInstanceType);
723     }
724     /* According to the ECMAScript specification, user-defined classes can only be instantiated by constructing (with
725      * new keyword). However, a few builtin types can be called like a function. Upon the results of calling and
726      * constructing, there are 4 categories of builtin types:
727      *
728      * Category 1: non-callable, objects of such a type can only be created by constructing.
729      * Category 2: non-constructable, such types can only be called.
730      * Category 3: simple, calling and constructing are equivalent.
731      * Category 4: complex, a type can be called and constructed, but the results differ.
732      *
733      * Constructing a builtin type always create objects of the type if supported. So in this function, we focus on the
734      * builtin types which are callable. While the majority of the callable builtin types have the same calling behavior
735      * as constructing, here are some special cases:
736      *
737      * | Type    | Call              | Category |
738      * | ------- | ----------------- | -------- |
739      * | BigInt  | primitive bigint  | 2        |
740      * | Boolean | primitive boolean | 4        |
741      * | Date    | primitive string  | 4        |
742      * | Number  | primitive number  | 4        |
743      * | String  | primitive string  | 4        |
744      *
745      * See the list of builtin types' constructors at:
746      *     https://tc39.es/ecma262/2021/#sec-constructor-properties-of-the-global-object
747      */
748     if (tsManager_->IsClassTypeKind(funcType) && tsManager_->IsBuiltin(funcType)) {
749         // For simplicity, calling and constructing are considered equivalent.
750         return UpdateType(gate, tsManager_->CreateClassInstanceType(funcType));
751     }
752     return false;
753 }
754 
InferLdObjByValue(GateRef gate)755 bool TypeInfer::InferLdObjByValue(GateRef gate)
756 {
757     auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
758     // handle array
759     if (tsManager_->IsArrayTypeKind(objType)) {
760         auto elementType = tsManager_->GetArrayParameterTypeGT(objType);
761         return UpdateType(gate, elementType);
762     }
763     // handle object
764     if (ShouldInferWithLdObjByValue(objType)) {
765         auto valueGate = gateAccessor_.GetValueIn(gate, 2);  // 2: value input slot
766         if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
767             auto value = gateAccessor_.GetConstantValue(valueGate);
768             auto type = GetPropType(objType, value);
769             return UpdateType(gate, type);
770         }
771         if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) {
772             ConstDataId dataId = gateAccessor_.GetConstDataId(valueGate);
773             auto index = dataId.GetId();
774             return GetObjPropWithName(gate, objType, index);
775         }
776     }
777     return false;
778 }
779 
InferGetNextPropName(GateRef gate)780 bool TypeInfer::InferGetNextPropName(GateRef gate)
781 {
782     auto stringType = GateType::StringType();
783     return UpdateType(gate, stringType);
784 }
785 
InferDefineGetterSetterByValue(GateRef gate)786 bool TypeInfer::InferDefineGetterSetterByValue(GateRef gate)
787 {
788     // 0 : the index of obj
789     auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
790     return UpdateType(gate, objType);
791 }
792 
InferSuperCall(GateRef gate)793 bool TypeInfer::InferSuperCall(GateRef gate)
794 {
795     ArgumentAccessor argAcc(circuit_);
796     auto newTarget = argAcc.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
797     auto classType = gateAccessor_.GetGateType(newTarget);
798     if (tsManager_->IsClassTypeKind(classType)) {
799         auto classInstanceType = tsManager_->CreateClassInstanceType(classType);
800         return UpdateType(gate, classInstanceType);
801     }
802     return false;
803 }
804 
InferSuperPropertyByName(GateRef gate)805 bool TypeInfer::InferSuperPropertyByName(GateRef gate)
806 {
807     uint16_t index = gateAccessor_.GetConstDataId(gateAccessor_.GetValueIn(gate, 0)).GetId();
808     return GetSuperProp(gate, index);
809 }
810 
InferSuperPropertyByValue(GateRef gate)811 bool TypeInfer::InferSuperPropertyByValue(GateRef gate)
812 {
813     auto valueGate = gateAccessor_.GetValueIn(gate, 1);
814     if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) {
815         ConstDataId dataId = gateAccessor_.GetConstDataId(valueGate);
816         auto index = dataId.GetId();
817         return GetSuperProp(gate, index);
818     }
819     if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
820         auto index = gateAccessor_.GetConstantValue(valueGate);
821 
822         return GetSuperProp(gate, index, false);
823     }
824     return false;
825 }
826 
GetSuperProp(GateRef gate,uint64_t index,bool isString)827 bool TypeInfer::GetSuperProp(GateRef gate, uint64_t index, bool isString)
828 {
829     ArgumentAccessor argAcc(circuit_);
830     auto func = argAcc.GetCommonArgGate(CommonArgIdx::FUNC);
831     auto newTarget = argAcc.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
832     auto funcType = gateAccessor_.GetGateType(func);
833     auto classType = gateAccessor_.GetGateType(newTarget);
834     if (!funcType.IsAnyType() && !classType.IsAnyType()) {
835         auto thread = tsManager_->GetEcmaVM()->GetJSThread();
836         GlobalTSTypeRef type = GlobalTSTypeRef::Default();
837         bool isStatic = tsManager_->IsStaticFunc(funcType.GetGTRef());
838         auto propType = isStatic ? PropertyType::STATIC : PropertyType::NORMAL;
839         JSHandle<ConstantPool> constantPool(tsManager_->GetConstantPool());
840         type = isString ? tsManager_->GetSuperPropType(classType.GetGTRef(),
841             ConstantPool::GetStringFromCache(thread, constantPool.GetTaggedValue(), index), propType) :
842             tsManager_->GetSuperPropType(classType.GetGTRef(), index, propType);
843         if (tsManager_->IsGetterSetterFunc(type)) {
844             auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type);
845             return UpdateType(gate, returnGt);
846         }
847         return UpdateType(gate, type);
848     }
849     return false;
850 }
851 
InferGetIterator(GateRef gate)852 bool TypeInfer::InferGetIterator(GateRef gate)
853 {
854     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
855     GateType inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
856 
857     GlobalTSTypeRef elementGt = GlobalTSTypeRef::Default();
858     if (tsManager_->IsArrayTypeKind(inValueType)) {
859         elementGt = tsManager_->GetArrayParameterTypeGT(inValueType);
860     } else if (inValueType.IsStringType()) {
861         elementGt.SetType(GateType::StringType().Value());
862     } else {
863         return false;
864     }
865     GlobalTSTypeRef iteratorInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType(
866         TSRuntimeType::ITERATOR, elementGt);
867     return UpdateType(gate, iteratorInstanceType);
868 }
869 
InferTryLdGlobalByName(GateRef gate)870 bool TypeInfer::InferTryLdGlobalByName(GateRef gate)
871 {
872     // todo by hongtao, should consider function of .d.ts
873     auto &byteCodeInfo = GetByteCodeInfo(gate);
874     ASSERT(byteCodeInfo.inputs.size() == 2);  // 2: number of parameter
875     auto stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
876     auto iter = stringIdToGateType_.find(stringId);
877     if (iter != stringIdToGateType_.end()) {
878         return UpdateType(gate, iter->second);
879     }
880     return false;
881 }
882 
InferLdLexVarDyn(GateRef gate)883 bool TypeInfer::InferLdLexVarDyn(GateRef gate)
884 {
885     auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
886     auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
887     auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot);
888     return UpdateType(gate, type);
889 }
890 
InferStLexVarDyn(GateRef gate)891 bool TypeInfer::InferStLexVarDyn(GateRef gate)
892 {
893     auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
894     auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
895     auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot);
896     if (type.IsAnyType() || type.IsUndefinedType()) {
897         auto valueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 3));
898         if (!valueType.IsAnyType()) {
899             lexEnvManager_->SetLexEnvElementType(methodId_, level, slot, valueType);
900             return true;
901         }
902     }
903     return false;
904 }
905 
InferStModuleVar(GateRef gate)906 bool TypeInfer::InferStModuleVar(GateRef gate)
907 {
908     auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
909     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
910     auto defineGate = gateAccessor_.GetValueIn(gate, 1);
911     auto defineType = gateAccessor_.GetGateType(defineGate);
912     if (!defineType.IsAnyType()) {
913         tsManager_->AddTypeToLocalModuleVarGtMap(jsPandaFile, recordName_, index, defineType.GetGTRef());
914         return true;
915     }
916     return false;
917 }
918 
InferLdLocalModuleVar(GateRef gate)919 bool TypeInfer::InferLdLocalModuleVar(GateRef gate)
920 {
921     auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
922     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
923     if (!tsManager_->HasExportGT(jsPandaFile, recordName_, index)) {
924         return UpdateType(gate, GateType::AnyType());
925     }
926     auto type = tsManager_->GetGTFromModuleMap(jsPandaFile, recordName_, index);
927     return UpdateType(gate, type);
928 }
929 
InferLoopBeginPhiGate(GateRef gate)930 bool TypeInfer::InferLoopBeginPhiGate(GateRef gate)
931 {
932     // loop-begin phi gate has 3 ins: loop_begin(stateWire), loopInGate(valueWire), loopBackGate(valueWire)
933     auto loopInGate = gateAccessor_.GetValueIn(gate);
934     auto loopInType = gateAccessor_.GetGateType(loopInGate);
935     // loop-begin phi will be initialized as loopInTytpe
936     // type of loop-back phi should be infered correctly only after loop-begin has actual type
937     // if loop-in phi is actual any type, loop-begin phi must be any
938     if (loopPhiState_.find(gate) == loopPhiState_.end()) {
939         if (!loopInType.IsAnyType()) {
940             loopPhiState_[gate] = InferState::NORMAL_INFERED;
941         }
942         return UpdateType(gate, loopInType);
943     }
944     // if loop phi has been marked as ANY_INFERED, it's in the second round infer for loop
945     if (loopPhiState_[gate] == InferState::ANY_INFERED) {
946         return UpdateType(gate, GateType::AnyType());
947     }
948     // if loopInType and loopBackType both have non-any type, we need special treatment for the situation
949     // in which loopInType and loopBackType both are numberType(int/double/number).
950     // However, we should avoid excessive type promotion which may cause endless loop in few IR situations.
951     if (loopPhiState_[gate] == InferState::NUMBER_INFERED) {
952         return UpdateType(gate, GateType::NumberType());
953     }
954     return UpdateType(gate, loopInType);
955 }
956 
ConvertPrimitiveToBuiltin(const GateType & gateType)957 GlobalTSTypeRef TypeInfer::ConvertPrimitiveToBuiltin(const GateType &gateType)
958 {
959     GlobalTSTypeRef builtinGt = GlobalTSTypeRef::Default();
960     if (!tsManager_->IsBuiltinsDTSEnabled()) {
961         return builtinGt;
962     }
963 
964     const JSPandaFile *builtinjsPandaFile = tsManager_->GetBuiltinPandaFile();
965     if (builtinjsPandaFile == nullptr) {
966         LOG_COMPILER(FATAL) << "load lib_ark_builtins.d.ts failed";
967     }
968     const CString &builtinsRecordName = tsManager_->GetBuiltinRecordName();
969     TSTypeParser typeParser(tsManager_);
970 
971     if (tsManager_->IsArrayTypeKind(gateType)) {
972         return typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
973                                    static_cast<uint32_t>(BuiltinTypeId::ARRAY));
974     }
975 
976     const GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.Value());
977     uint32_t l = gt.GetLocalId();
978     switch (l) {
979         case static_cast<uint32_t>(TSPrimitiveType::SYMBOL):
980             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
981                                             static_cast<uint32_t>(BuiltinTypeId::SYMBOL));
982             break;
983         case static_cast<uint32_t>(TSPrimitiveType::INT):
984         case static_cast<uint32_t>(TSPrimitiveType::DOUBLE):
985         case static_cast<uint32_t>(TSPrimitiveType::NUMBER):
986             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
987                                             static_cast<uint32_t>(BuiltinTypeId::NUMBER));
988             break;
989         case static_cast<uint32_t>(TSPrimitiveType::BOOLEAN):
990             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
991                                             static_cast<uint32_t>(BuiltinTypeId::BOOLEAN));
992             break;
993         case static_cast<uint32_t>(TSPrimitiveType::STRING):
994             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
995                                             static_cast<uint32_t>(BuiltinTypeId::STRING));
996             break;
997         default:
998             builtinGt = GlobalTSTypeRef::Default();
999     }
1000     return builtinGt;
1001 }
1002 
PrintAllByteCodesTypes() const1003 void TypeInfer::PrintAllByteCodesTypes() const
1004 {
1005     std::vector<GateRef> gateList;
1006     circuit_->GetAllGates(gateList);
1007 
1008     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1009     const MethodLiteral *methodLiteral = builder_->GetMethod();
1010     const std::string functionName = methodLiteral->ParseFunctionName(jsPandaFile, methodLiteral->GetMethodId());
1011 
1012     LOG_COMPILER(INFO) << "print bytecode types:";
1013     LOG_COMPILER(INFO) << ".recordName " + recordName_;
1014     LOG_COMPILER(INFO) << ".function " + functionName + "() {";
1015     uint32_t lastBcIndex = builder_->GetLastBcIndex();
1016     for (uint32_t bcIndex = 0; bcIndex < lastBcIndex; bcIndex++) {  // ignore last element
1017         const uint8_t *pc = builder_->GetPCByIndex(bcIndex);
1018         BytecodeInstruction inst(pc);
1019         GateRef gate = builder_->GetGateByBcIndex(bcIndex);
1020         if (gate != Circuit::NullGate()) {
1021             GateType type = gateAccessor_.GetGateType(gate);
1022             if (!tsManager_->IsPrimitiveTypeKind(type)) {
1023                 GlobalTSTypeRef gt = type.GetGTRef();
1024                 LOG_COMPILER(INFO) << "    " << inst << ", type: " + tsManager_->GetTypeStr(type)
1025                                    << ", [moduleId: " + std::to_string(gt.GetModuleId())
1026                                    << ", localId: " + std::to_string(gt.GetLocalId()) + "]";
1027             } else {
1028                 LOG_COMPILER(INFO) << "    " << inst << ", type: " + tsManager_->GetTypeStr(type);
1029             }
1030         }
1031     }
1032     LOG_COMPILER(INFO) << "}";
1033 }
1034 
Verify() const1035 void TypeInfer::Verify() const
1036 {
1037     std::vector<GateRef> gateList;
1038     circuit_->GetAllGates(gateList);
1039     for (const auto &gate : gateList) {
1040         auto op = gateAccessor_.GetOpCode(gate);
1041         if (op == OpCode::JS_BYTECODE) {
1042             TypeCheck(gate);
1043         }
1044     }
1045 }
1046 
1047 /*
1048  * Let v be a variable in one ts-file and t be a type. To check whether the type of v is t after
1049  * type inferenece, one should declare a function named "AssertType(value:any, type:string):void"
1050  * in ts-file and call it with arguments v and t, where t is the expected type string.
1051  * The following interface performs such a check at compile time.
1052  */
TypeCheck(GateRef gate) const1053 void TypeInfer::TypeCheck(GateRef gate) const
1054 {
1055     auto &info = GetByteCodeInfo(gate);
1056     if (!info.IsBc(EcmaOpcode::CALLARGS2_IMM8_V8_V8)) {
1057         return;
1058     }
1059     auto func = gateAccessor_.GetValueIn(gate, 2); // 2: acc
1060     auto &funcInfo = GetByteCodeInfo(func);
1061     if (!funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16) &&
1062         !funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16)) {
1063         return;
1064     }
1065     auto funcName = gateAccessor_.GetValueIn(func, 1);
1066     auto thread = tsManager_->GetEcmaVM()->GetJSThread();
1067     JSHandle<ConstantPool> constantPool(tsManager_->GetConstantPool());
1068     uint16_t funcNameStrId = gateAccessor_.GetConstDataId(funcName).GetId();
1069     ConstantPool::GetStringFromCache(thread, constantPool.GetTaggedValue(), funcNameStrId);
1070     auto funcNameString = constantPool->GetStdStringByIdx(funcNameStrId);
1071     if (funcNameString == "AssertType") {
1072         GateRef expectedGate = gateAccessor_.GetValueIn(gate, 1);
1073         uint16_t strId = gateAccessor_.GetConstDataId(expectedGate).GetId();
1074         ConstantPool::GetStringFromCache(thread, constantPool.GetTaggedValue(), strId);
1075         auto expectedTypeStr = constantPool->GetStdStringByIdx(strId);
1076         GateRef valueGate = gateAccessor_.GetValueIn(gate, 0);
1077         auto type = gateAccessor_.GetGateType(valueGate);
1078         if (expectedTypeStr != tsManager_->GetTypeStr(type)) {
1079             const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1080             const MethodLiteral *methodLiteral = builder_->GetMethod();
1081             EntityId methodId = builder_->GetMethod()->GetMethodId();
1082             DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
1083             const std::string &sourceFileName = debugExtractor->GetSourceFile(methodId);
1084             const std::string functionName = methodLiteral->ParseFunctionName(jsPandaFile, methodId);
1085 
1086             std::string log = CollectGateTypeLogInfo(valueGate, debugExtractor, "[TypeAssertion] ");
1087             log += "[TypeAssertion] but expected type: " + expectedTypeStr + "\n";
1088 
1089             LOG_COMPILER(ERROR) << "[TypeAssertion] [" << sourceFileName << ":" << functionName << "] begin:";
1090             LOG_COMPILER(FATAL) << log << "[compiler] [TypeAssertion] end";
1091         }
1092     }
1093 }
1094 
FilterAnyTypeGates() const1095 void TypeInfer::FilterAnyTypeGates() const
1096 {
1097     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1098     const MethodLiteral *methodLiteral = builder_->GetMethod();
1099     EntityId methodId = methodLiteral->GetMethodId();
1100 
1101     DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
1102     const std::string &sourceFileName = debugExtractor->GetSourceFile(methodId);
1103     const std::string functionName = methodLiteral->ParseFunctionName(jsPandaFile, methodId);
1104 
1105     std::vector<GateRef> gateList;
1106     circuit_->GetAllGates(gateList);
1107     std::string log;
1108     for (const auto &gate : gateList) {
1109         GateType type = gateAccessor_.GetGateType(gate);
1110         if (ShouldInfer(gate) && type.IsAnyType()) {
1111             log += CollectGateTypeLogInfo(gate, debugExtractor, "[TypeFilter] ");
1112         }
1113     }
1114 
1115     LOG_COMPILER(INFO) << "[TypeFilter] [" << sourceFileName << ":" << functionName << "] begin:";
1116     LOG_COMPILER(INFO) << log << "[TypeFilter] end";
1117 }
1118 
CollectGateTypeLogInfo(GateRef gate,DebugInfoExtractor * debugExtractor,const std::string & logPreFix) const1119 std::string TypeInfer::CollectGateTypeLogInfo(GateRef gate, DebugInfoExtractor *debugExtractor,
1120                                               const std::string &logPreFix) const
1121 {
1122     std::string log(logPreFix);
1123     log += "gate id: "+ std::to_string(gateAccessor_.GetId(gate)) + ", ";
1124     OpCode op = gateAccessor_.GetOpCode(gate);
1125     log += "op: " + GateMetaData::Str(op) + ", ";
1126     if (op == OpCode::ARG) {
1127         log += "arg gate, ";
1128     } else if (op != OpCode::VALUE_SELECTOR) {
1129         auto &bytecodeInfo = GetByteCodeInfo(gate);
1130         // handle ByteCode gate: print gate id, bytecode and line number in source code.
1131         log += "bytecode: " + GetEcmaOpcodeStr(bytecodeInfo.GetOpcode()) + ", ";
1132 
1133         int32_t lineNumber = 0;
1134         auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
1135             lineNumber = line + 1;
1136             return true;
1137         };
1138 
1139         const auto bcIndex = jsgateToBytecode_.at(gate);
1140         auto offset = builder_->GetPcOffset(bcIndex);
1141         const MethodLiteral *methodLiteral = builder_->GetMethod();
1142         debugExtractor->MatchLineWithOffset(callbackLineFunc, methodLiteral->GetMethodId(), offset);
1143 
1144         log += "at line: " + std::to_string(lineNumber) + ", ";
1145     } else {
1146     // handle phi gate: print gate id and input gates id list.
1147         log += "phi gate, ins: ";
1148         auto ins = gateAccessor_.ConstIns(gate);
1149         for (auto it =  ins.begin(); it != ins.end(); it++) {
1150             log += std::to_string(gateAccessor_.GetId(*it)) + " ";
1151         }
1152     }
1153 
1154     GateType type = gateAccessor_.GetGateType(gate);
1155     log += "type: " + tsManager_->GetTypeStr(type) + ", ";
1156     if (!tsManager_->IsPrimitiveTypeKind(type)) {
1157         GlobalTSTypeRef gt = type.GetGTRef();
1158         log += "[moduleId: " + std::to_string(gt.GetModuleId()) + ", ";
1159         log += "localId: " + std::to_string(gt.GetLocalId()) + "], ";
1160     }
1161 
1162     log += "\n[compiler] ";
1163     return log;
1164 }
1165 }  // namespace panda::ecmascript
1166