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