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/method_type_infer.h"
17
18 #include "ecmascript/jspandafile/js_pandafile_manager.h"
19 #include "ecmascript/ts_types/ts_type_accessor.h"
20 #include "ecmascript/ts_types/ts_type_parser.h"
21
22 namespace panda::ecmascript::kungfu {
MethodTypeInfer(BytecodeCircuitBuilder * builder,Circuit * circuit,PassContext * ctx,size_t methodId,bool enableLog,const std::string & name,const CString & recordName,MethodInfo * methodInfo,const MethodLiteral * methodLiteral,bool enableGlobalTypeInfer)23 MethodTypeInfer::MethodTypeInfer(BytecodeCircuitBuilder *builder, Circuit *circuit, PassContext *ctx, size_t methodId,
24 bool enableLog, const std::string &name, const CString &recordName,
25 MethodInfo *methodInfo, const MethodLiteral *methodLiteral,
26 bool enableGlobalTypeInfer)
27 : builder_(builder), circuit_(circuit), gateAccessor_(circuit), tsManager_(ctx->GetTSManager()), ctx_(ctx),
28 lexEnvManager_(ctx->GetLexEnvManager()), methodId_(methodId), enableLog_(enableLog), methodName_(name),
29 recordName_(recordName), methodInfo_(methodInfo), methodLiteral_(methodLiteral),
30 inQueue_(circuit_->GetGateCount(), true), enableGlobalTypeInfer_(enableGlobalTypeInfer)
31 {
32 if (enableGlobalTypeInfer_ && methodInfo->IsNamespace()) {
33 uint32_t methodOffset = methodLiteral_->GetMethodId().GetOffset();
34 if (tsManager_->HasInferredNamespaceType(methodOffset)) {
35 SetNamespaceArgType(tsManager_->GetNamespaceObjType(methodOffset));
36 }
37 }
38
39 std::vector<GateRef> gateList;
40 circuit_->GetAllGates(gateList);
41 for (auto gate : gateList) {
42 if (gateAccessor_.GetOpCode(gate) == OpCode::FRAME_ARGS) {
43 continue;
44 }
45 pendingQueue_.push(gate);
46 }
47 // init jsgateToBytecode
48 BytecodeIterator iterator(builder_, 0, builder_->GetLastBcIndex());
49 for (iterator.GotoStart(); !iterator.Done(); ++iterator) {
50 auto index = iterator.Index();
51 auto gates = builder_->GetGatesByBcIndex(index);
52 for (auto gate : gates) {
53 jsgateToBytecode_[gate] = index;
54 }
55 }
56 }
57
CheckAndPrint()58 void MethodTypeInfer::CheckAndPrint()
59 {
60 VerifyTypePercent();
61
62 if (tsManager_->AssertTypes()) {
63 Verify();
64 }
65
66 if (IsLogEnabled()) {
67 PrintTypeAnnotation();
68 PrintByteCodesWithTypes();
69 PrintCircuitWithTypes();
70 }
71 }
72
TraverseInfer()73 std::pair<GateType, uint32_t> MethodTypeInfer::TraverseInfer()
74 {
75 // main type infer for all gates
76 while (!pendingQueue_.empty()) {
77 auto curGate = pendingQueue_.front();
78 inQueue_[gateAccessor_.GetId(curGate)] = false;
79 pendingQueue_.pop();
80 auto uses = gateAccessor_.ConstUses(curGate);
81 for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
82 auto gateId = gateAccessor_.GetId(*useIt);
83 if (Infer(*useIt) && !inQueue_[gateId]) {
84 inQueue_[gateId] = true;
85 pendingQueue_.push(*useIt);
86 }
87 if (enableGlobalTypeInfer_ && IsNamespace(*useIt)) {
88 return SetAndReturnNamespaceObjType(*useIt);
89 }
90 }
91 if (pendingQueue_.empty() && needUpdateForLoopPhi_) {
92 // only for loop begin phi
93 UpdateQueueForLoopPhi();
94 needUpdateForLoopPhi_ = false;
95 }
96 }
97 return std::make_pair(GateType::AnyType(), 0); // 0: defaule value
98 }
99
UpdateQueueForLoopPhi()100 void MethodTypeInfer::UpdateQueueForLoopPhi()
101 {
102 for (auto it = loopPhiState_.begin(); it != loopPhiState_.end(); it++) {
103 auto curGate = it->first;
104 auto loopType = gateAccessor_.GetGateType(curGate);
105 auto loopBackGate = gateAccessor_.GetValueIn(curGate, 1);
106 auto loopBackType = gateAccessor_.GetGateType(loopBackGate);
107 // if loopBack Gate is finally AnyType, loop-begin phi gate should be changed to any
108 if (!loopType.IsAnyType() && loopBackType.IsAnyType()) {
109 gateAccessor_.SetGateType(curGate, GateType::AnyType());
110 loopPhiState_[curGate] = InferState::ANY_INFERED;
111 pendingQueue_.push(curGate);
112 inQueue_[gateAccessor_.GetId(curGate)] = true;
113 }
114 // if loopBack Gate is finally not same number Type, loop-begin phi gate should be promoted
115 if (loopType.IsNumberType() && loopBackType.IsNumberType() && loopType != loopBackType) {
116 gateAccessor_.SetGateType(curGate, GateType::NumberType());
117 loopPhiState_[curGate] = InferState::NUMBER_INFERED;
118 pendingQueue_.push(curGate);
119 inQueue_[gateAccessor_.GetId(curGate)] = true;
120 }
121 }
122 }
123
UpdateType(GateRef gate,const GateType type,bool savePreType)124 bool MethodTypeInfer::UpdateType(GateRef gate, const GateType type, bool savePreType)
125 {
126 GateType preType = gateAccessor_.GetGateType(gate);
127 needInferGates_.insert(gate);
128 // When the type after type inference is any and you want to save previous type, it wolud not update.
129 if (savePreType && type.IsAnyType()) {
130 return false;
131 }
132
133 if (type != preType) {
134 gateAccessor_.SetGateType(gate, HandleTypeCompatibility(preType, type));
135 return true;
136 }
137 return false;
138 }
139
UpdateType(GateRef gate,const GlobalTSTypeRef & typeRef,bool savePreType)140 bool MethodTypeInfer::UpdateType(GateRef gate, const GlobalTSTypeRef &typeRef, bool savePreType)
141 {
142 auto type = GateType(typeRef);
143 return UpdateType(gate, type, savePreType);
144 }
145
HandleTypeCompatibility(const GateType preType,const GateType type) const146 GateType MethodTypeInfer::HandleTypeCompatibility(const GateType preType, const GateType type) const
147 {
148 if (tsManager_->IsArrayTypeKind(preType) && tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, type)) {
149 return preType;
150 }
151 return type;
152 }
153
IsNewLexEnv(EcmaOpcode opcode) const154 bool MethodTypeInfer::IsNewLexEnv(EcmaOpcode opcode) const
155 {
156 switch (opcode) {
157 case EcmaOpcode::NEWLEXENV_IMM8:
158 case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16:
159 case EcmaOpcode::WIDE_NEWLEXENV_PREF_IMM16:
160 case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
161 return true;
162 default:
163 return false;
164 }
165 }
166
ShouldInfer(const GateRef gate) const167 bool MethodTypeInfer::ShouldInfer(const GateRef gate) const
168 {
169 auto opcode = gateAccessor_.GetOpCode(gate);
170 // handle phi gates
171 if ((opcode == OpCode::VALUE_SELECTOR) ||
172 (opcode == OpCode::LOOP_EXIT_VALUE)) {
173 return true;
174 }
175 /* Handle constant gates (like ldnull and ldtrue), return gates and gates generated by ecma.* bytecodes (not
176 * including jump and newlexenv). Jump instructions are skipped because they have no intrinsic type information.
177 * And newlexenv instructions are used to create runtime lexical env objects which have no TS types associated. As
178 * for the type inference on lexical variables, their type information is recorded in objects of class
179 * panda::ecmascript::kungfu::LexEnv which are created during the building of IR. So in the type inference,
180 * newlexenv is ignored.
181 */
182 if (opcode != OpCode::CONSTANT &&
183 opcode != OpCode::RETURN && opcode != OpCode::JS_BYTECODE) {
184 return false;
185 }
186 if (jsgateToBytecode_.find(gate) == jsgateToBytecode_.end()) {
187 return false;
188 }
189 auto &bytecodeInfo = GetByteCodeInfo(gate);
190 return !bytecodeInfo.IsJump() && !IsNewLexEnv(bytecodeInfo.GetOpcode());
191 }
192
Infer(GateRef gate)193 bool MethodTypeInfer::Infer(GateRef gate)
194 {
195 if (!ShouldInfer(gate)) {
196 return false;
197 }
198 if (gateAccessor_.GetOpCode(gate) == OpCode::LOOP_EXIT_VALUE) {
199 return UpdateType(gate, gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate)));
200 }
201 if (gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR) {
202 return InferPhiGate(gate);
203 }
204 // infer ecma.* bytecode gates
205 auto &bytecodeInfo = GetByteCodeInfo(gate);
206 switch (bytecodeInfo.GetOpcode()) {
207 case EcmaOpcode::LDNAN:
208 case EcmaOpcode::LDINFINITY:
209 case EcmaOpcode::MOD2_IMM8_V8:
210 case EcmaOpcode::AND2_IMM8_V8:
211 case EcmaOpcode::OR2_IMM8_V8:
212 case EcmaOpcode::XOR2_IMM8_V8:
213 case EcmaOpcode::TONUMBER_IMM8:
214 case EcmaOpcode::NEG_IMM8:
215 case EcmaOpcode::EXP_IMM8_V8:
216 case EcmaOpcode::STARRAYSPREAD_V8_V8:
217 return SetNumberType(gate);
218 case EcmaOpcode::SHL2_IMM8_V8:
219 case EcmaOpcode::ASHR2_IMM8_V8:
220 case EcmaOpcode::SHR2_IMM8_V8:
221 case EcmaOpcode::NOT_IMM8:
222 return SetIntType(gate);
223 case EcmaOpcode::LDBIGINT_ID16:
224 return SetBigIntType(gate);
225 case EcmaOpcode::LDTRUE:
226 case EcmaOpcode::LDFALSE:
227 case EcmaOpcode::EQ_IMM8_V8:
228 case EcmaOpcode::NOTEQ_IMM8_V8:
229 case EcmaOpcode::LESS_IMM8_V8:
230 case EcmaOpcode::LESSEQ_IMM8_V8:
231 case EcmaOpcode::GREATER_IMM8_V8:
232 case EcmaOpcode::GREATEREQ_IMM8_V8:
233 case EcmaOpcode::ISIN_IMM8_V8:
234 case EcmaOpcode::INSTANCEOF_IMM8_V8:
235 case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
236 case EcmaOpcode::STRICTEQ_IMM8_V8:
237 case EcmaOpcode::ISTRUE:
238 case EcmaOpcode::ISFALSE:
239 case EcmaOpcode::SETOBJECTWITHPROTO_IMM8_V8:
240 case EcmaOpcode::SETOBJECTWITHPROTO_IMM16_V8:
241 case EcmaOpcode::DELOBJPROP_V8:
242 return SetBooleanType(gate);
243 case EcmaOpcode::LDUNDEFINED:
244 return InferLdUndefined(gate);
245 case EcmaOpcode::LDNULL:
246 return InferLdNull(gate);
247 case EcmaOpcode::LDAI_IMM32:
248 return InferLdai(gate);
249 case EcmaOpcode::FLDAI_IMM64:
250 return InferFLdai(gate);
251 case EcmaOpcode::LDSYMBOL:
252 return InferLdSymbol(gate);
253 case EcmaOpcode::THROW_PREF_NONE:
254 return InferThrow(gate);
255 case EcmaOpcode::TYPEOF_IMM8:
256 case EcmaOpcode::TYPEOF_IMM16:
257 return InferTypeOf(gate);
258 case EcmaOpcode::ADD2_IMM8_V8:
259 return InferAdd2(gate);
260 case EcmaOpcode::SUB2_IMM8_V8:
261 return InferSub2(gate);
262 case EcmaOpcode::MUL2_IMM8_V8:
263 return InferMul2(gate);
264 case EcmaOpcode::DIV2_IMM8_V8:
265 return InferDiv2(gate);
266 case EcmaOpcode::INC_IMM8:
267 case EcmaOpcode::DEC_IMM8:
268 return InferIncDec(gate);
269 case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
270 case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
271 case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
272 return InferLdObjByIndex(gate);
273 case EcmaOpcode::STGLOBALVAR_IMM16_ID16:
274 case EcmaOpcode::TRYSTGLOBALBYNAME_IMM8_ID16:
275 case EcmaOpcode::TRYSTGLOBALBYNAME_IMM16_ID16:
276 return SetStGlobalBcType(gate, true);
277 case EcmaOpcode::STTOGLOBALRECORD_IMM16_ID16:
278 case EcmaOpcode::STCONSTTOGLOBALRECORD_IMM16_ID16:
279 return SetStGlobalBcType(gate, false);
280 case EcmaOpcode::LDGLOBALVAR_IMM16_ID16:
281 return InferLdGlobalVar(gate);
282 case EcmaOpcode::RETURNUNDEFINED:
283 return InferReturnUndefined(gate);
284 case EcmaOpcode::RETURN:
285 return InferReturn(gate);
286 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
287 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
288 return InferLdObjByName(gate);
289 case EcmaOpcode::LDA_STR_ID16:
290 return InferLdStr(gate);
291 case EcmaOpcode::TONUMERIC_IMM8:
292 return InferToNumberic(gate);
293 case EcmaOpcode::CALLARG0_IMM8:
294 case EcmaOpcode::CALLARG1_IMM8_V8:
295 case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
296 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
297 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
298 case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
299 case EcmaOpcode::APPLY_IMM8_V8_V8:
300 return InferCallFunction(gate);
301 case EcmaOpcode::CALLTHIS0_IMM8_V8:
302 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
303 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
304 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
305 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
306 case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
307 return InferCallMethod(gate);
308 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
309 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
310 return InferLdObjByValue(gate);
311 case EcmaOpcode::GETNEXTPROPNAME_V8:
312 return InferGetNextPropName(gate);
313 case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
314 return InferDefineGetterSetterByValue(gate);
315 case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
316 case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
317 case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
318 case EcmaOpcode::NEWOBJAPPLY_IMM8_V8:
319 case EcmaOpcode::NEWOBJAPPLY_IMM16_V8:
320 return InferNewObject(gate);
321 case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
322 case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
323 case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
324 case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
325 case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8:
326 return InferSuperCall(gate);
327 case EcmaOpcode::LDSUPERBYNAME_IMM8_ID16:
328 case EcmaOpcode::LDSUPERBYNAME_IMM16_ID16:
329 return InferSuperPropertyByName(gate);
330 case EcmaOpcode::LDSUPERBYVALUE_IMM8_V8:
331 case EcmaOpcode::LDSUPERBYVALUE_IMM16_V8:
332 return InferSuperPropertyByValue(gate);
333 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
334 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
335 return InferTryLdGlobalByName(gate);
336 case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
337 case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
338 case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
339 return InferLdLexVarDyn(gate);
340 case EcmaOpcode::STLEXVAR_IMM4_IMM4:
341 case EcmaOpcode::STLEXVAR_IMM8_IMM8:
342 case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
343 return InferStLexVarDyn(gate);
344 case EcmaOpcode::GETITERATOR_IMM8:
345 case EcmaOpcode::GETITERATOR_IMM16:
346 return InferGetIterator(gate);
347 case EcmaOpcode::STMODULEVAR_IMM8:
348 case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
349 return InferStModuleVar(gate);
350 case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
351 case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
352 return InferLdLocalModuleVar(gate);
353 case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8:
354 case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
355 return InferLdExternalModuleVar(gate);
356 case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
357 case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
358 return InferStObjByName(gate);
359 default:
360 break;
361 }
362 return false;
363 }
364
InferPhiGate(GateRef gate)365 bool MethodTypeInfer::InferPhiGate(GateRef gate)
366 {
367 ASSERT(gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR);
368 CVector<GlobalTSTypeRef> typeList;
369 std::set<GlobalTSTypeRef> numberTypeSet;
370 auto ins = gateAccessor_.ConstIns(gate);
371 for (auto it = ins.begin(); it != ins.end(); it++) {
372 // assuming that VALUE_SELECTOR is NO_DEPEND and NO_ROOT
373 if (gateAccessor_.GetOpCode(*it) == OpCode::MERGE) {
374 continue;
375 }
376 if (gateAccessor_.GetOpCode(*it) == OpCode::LOOP_BEGIN) {
377 return InferLoopBeginPhiGate(gate);
378 }
379 auto valueInType = gateAccessor_.GetGateType(*it);
380 if (valueInType.IsAnyType()) {
381 return UpdateType(gate, valueInType, false);
382 }
383 if (valueInType.IsNumberType()) {
384 numberTypeSet.insert(valueInType.GetGTRef());
385 } else {
386 typeList.emplace_back(valueInType.GetGTRef());
387 }
388 }
389 // deduplicate
390 std::sort(typeList.begin(), typeList.end());
391 auto deduplicateIndex = std::unique(typeList.begin(), typeList.end());
392 typeList.erase(deduplicateIndex, typeList.end());
393 if (numberTypeSet.size() == 1) {
394 typeList.emplace_back(*(numberTypeSet.begin()));
395 } else if (numberTypeSet.size() > 1) {
396 typeList.emplace_back(GateType::NumberType().GetGTRef());
397 }
398 if (typeList.size() > 1) {
399 auto unionType = tsManager_->GetOrCreateUnionType(typeList);
400 return UpdateType(gate, unionType, false);
401 }
402 auto type = typeList.at(0);
403 return UpdateType(gate, type, false);
404 }
405
SetIntType(GateRef gate)406 bool MethodTypeInfer::SetIntType(GateRef gate)
407 {
408 auto intType = GateType::IntType();
409 return UpdateType(gate, intType);
410 }
411
SetNumberType(GateRef gate)412 bool MethodTypeInfer::SetNumberType(GateRef gate)
413 {
414 auto numberType = GateType::NumberType();
415 return UpdateType(gate, numberType);
416 }
417
SetBigIntType(GateRef gate)418 bool MethodTypeInfer::SetBigIntType(GateRef gate)
419 {
420 auto bigIntType = GateType::BigIntType();
421 return UpdateType(gate, bigIntType);
422 }
423
SetBooleanType(GateRef gate)424 bool MethodTypeInfer::SetBooleanType(GateRef gate)
425 {
426 auto booleanType = GateType::BooleanType();
427 return UpdateType(gate, booleanType);
428 }
429
InferLdUndefined(GateRef gate)430 bool MethodTypeInfer::InferLdUndefined(GateRef gate)
431 {
432 auto undefinedType = GateType::UndefinedType();
433 return UpdateType(gate, undefinedType);
434 }
435
InferLdNull(GateRef gate)436 bool MethodTypeInfer::InferLdNull(GateRef gate)
437 {
438 auto nullType = GateType::NullType();
439 return UpdateType(gate, nullType);
440 }
441
InferLdai(GateRef gate)442 bool MethodTypeInfer::InferLdai(GateRef gate)
443 {
444 auto intType = GateType::IntType();
445 return UpdateType(gate, intType);
446 }
447
InferFLdai(GateRef gate)448 bool MethodTypeInfer::InferFLdai(GateRef gate)
449 {
450 auto doubleType = GateType::DoubleType();
451 return UpdateType(gate, doubleType);
452 }
453
InferLdSymbol(GateRef gate)454 bool MethodTypeInfer::InferLdSymbol(GateRef gate)
455 {
456 auto symbolType = GateType::SymbolType();
457 return UpdateType(gate, symbolType);
458 }
459
InferThrow(GateRef gate)460 bool MethodTypeInfer::InferThrow(GateRef gate)
461 {
462 ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
463 auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
464 return UpdateType(gate, gateType);
465 }
466
InferTypeOf(GateRef gate)467 bool MethodTypeInfer::InferTypeOf(GateRef gate)
468 {
469 ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
470 auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
471 return UpdateType(gate, gateType);
472 }
473
474 /*
475 * Type Infer rule(satisfy commutative law):
476 * number + number = number
477 * int + number = number
478 * double + number = double
479 * int + int = int
480 * int + double = double
481 * double + double = double
482 * string + string = string
483 */
InferAdd2(GateRef gate)484 bool MethodTypeInfer::InferAdd2(GateRef gate)
485 {
486 // 2: number of value inputs
487 ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
488 auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
489 auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
490 if (firInType.IsStringType() || secInType.IsStringType()) {
491 return UpdateType(gate, GateType::StringType());
492 }
493 if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
494 (firInType.IsDoubleType() && secInType.IsNumberType())) {
495 return UpdateType(gate, GateType::DoubleType());
496 }
497 if ((firInType.IsIntType() && secInType.IsIntType())) {
498 return UpdateType(gate, GateType::IntType());
499 }
500 if (firInType.IsNumberType() && secInType.IsNumberType()) {
501 return UpdateType(gate, GateType::NumberType());
502 }
503 return UpdateType(gate, GateType::AnyType());
504 }
505
506 /*
507 * Type Infer rule(satisfy commutative law):
508 * number - number = number
509 * int - number = number
510 * double - number = double
511 * int - int = int
512 * int - double = double
513 * double - double = double
514 */
InferSub2(GateRef gate)515 bool MethodTypeInfer::InferSub2(GateRef gate)
516 {
517 // 2: number of value inputs
518 ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
519 auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
520 auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
521 if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
522 (firInType.IsDoubleType() && secInType.IsNumberType())) {
523 return UpdateType(gate, GateType::DoubleType());
524 }
525 if ((firInType.IsIntType() && secInType.IsIntType())) {
526 return UpdateType(gate, GateType::IntType());
527 }
528 return UpdateType(gate, GateType::NumberType());
529 }
530
531 /*
532 * Type Infer rule(satisfy commutative law):
533 * number * number = number
534 * int * number = number
535 * double * number = double
536 * int * int = int
537 * int * double = double
538 * double * double = double
539 */
InferMul2(GateRef gate)540 bool MethodTypeInfer::InferMul2(GateRef gate)
541 {
542 // 2: number of value inputs
543 ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
544 auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
545 auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
546 if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
547 (firInType.IsDoubleType() && secInType.IsNumberType())) {
548 return UpdateType(gate, GateType::DoubleType());
549 }
550 if ((firInType.IsIntType() && secInType.IsIntType())) {
551 return UpdateType(gate, GateType::IntType());
552 }
553 return UpdateType(gate, GateType::NumberType());
554 }
555
556 /*
557 * Type Infer rule(satisfy commutative law):
558 * in type lowering, both elements will be changed to float64 firstly.
559 * number / number = double
560 * int / number = double
561 * double / number = double
562 * int / int = double
563 * int / double = double
564 * double / double = double
565 * any / any = number
566 * any / number = number
567 * number / any = number
568 */
InferDiv2(GateRef gate)569 bool MethodTypeInfer::InferDiv2(GateRef gate)
570 {
571 // 2: number of value inputs
572 ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
573 auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
574 auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
575 if (firInType.IsNumberType() && secInType.IsNumberType()) {
576 return UpdateType(gate, GateType::DoubleType());
577 }
578 return UpdateType(gate, GateType::NumberType());
579 }
580
581 /*
582 * Type Infer rule:
583 * number++ = number
584 * number-- = number
585 * int++ = int
586 * int-- = int
587 * double++ = double
588 * double-- = double
589 */
InferIncDec(GateRef gate)590 bool MethodTypeInfer::InferIncDec(GateRef gate)
591 {
592 ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
593 auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
594 if (firInType.IsDoubleType()) {
595 return UpdateType(gate, GateType::DoubleType());
596 }
597 if (firInType.IsIntType()) {
598 return UpdateType(gate, GateType::IntType());
599 }
600 return UpdateType(gate, GateType::NumberType());
601 }
602
InferToNumberic(GateRef gate)603 bool MethodTypeInfer::InferToNumberic(GateRef gate)
604 {
605 GateRef src = gateAccessor_.GetValueIn(gate, 0);
606 GateType srcType = gateAccessor_.GetGateType(src);
607 if (srcType.IsNumberType()) {
608 return UpdateType(gate, srcType);
609 }
610 return UpdateType(gate, GateType::NumberType());
611 }
612
InferLdObjByIndex(GateRef gate)613 bool MethodTypeInfer::InferLdObjByIndex(GateRef gate)
614 {
615 // 2: number of value inputs
616 ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
617 auto inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
618 inValueType = tsManager_->TryNarrowUnionType(inValueType);
619 if (tsManager_->IsArrayTypeKind(inValueType)) {
620 auto type = tsManager_->GetArrayParameterTypeGT(inValueType);
621 return UpdateType(gate, type);
622 }
623
624 if (tsManager_->IsIntTypedArrayType(inValueType)) {
625 return UpdateType(gate, GateType::IntType());
626 }
627
628 if (tsManager_->IsDoubleTypedArrayType(inValueType)) {
629 return UpdateType(gate, GateType::DoubleType());
630 }
631
632 if (tsManager_->IsTypedArrayType(inValueType)) {
633 return UpdateType(gate, GateType::NumberType());
634 }
635
636 if (ShouldInferWithLdObjByValue(inValueType)) {
637 uint64_t key = gateAccessor_.GetConstantValue((gateAccessor_.GetValueIn(gate, 0))); // 0: index of key
638 auto type = GetPropType(inValueType, key);
639 return UpdateType(gate, type);
640 }
641 return UpdateType(gate, GateType::AnyType());
642 }
643
SetStGlobalBcType(GateRef gate,bool hasIC)644 bool MethodTypeInfer::SetStGlobalBcType(GateRef gate, bool hasIC)
645 {
646 auto &byteCodeInfo = GetByteCodeInfo(gate);
647 uint16_t stringId = 0;
648 GateType inValueType;
649 if (hasIC) {
650 // 2: number of value inputs
651 ASSERT(byteCodeInfo.inputs.size() == 2);
652 stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
653 // 3: number of value inputs
654 ASSERT(gateAccessor_.GetNumValueIn(gate) == 3);
655 // 2: value input
656 inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2));
657 } else {
658 ASSERT(byteCodeInfo.inputs.size() == 1);
659 stringId = std::get<ConstDataId>(byteCodeInfo.inputs[0]).GetId();
660 // 2: number of value inputs
661 ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
662 inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
663 }
664 if (stringIdToGateType_.find(stringId) != stringIdToGateType_.end()) {
665 stringIdToGateType_[stringId] = inValueType;
666 } else {
667 stringIdToGateType_.emplace(stringId, inValueType);
668 }
669 return UpdateType(gate, inValueType);
670 }
671
InferLdGlobalVar(GateRef gate)672 bool MethodTypeInfer::InferLdGlobalVar(GateRef gate)
673 {
674 auto &byteCodeInfo = GetByteCodeInfo(gate);
675 ASSERT(byteCodeInfo.inputs.size() == 2); // 2: number of value inputs
676 auto stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
677 auto iter = stringIdToGateType_.find(stringId);
678 if (iter != stringIdToGateType_.end()) {
679 return UpdateType(gate, iter->second);
680 }
681 return UpdateType(gate, GateType::AnyType());
682 }
683
InferReturnUndefined(GateRef gate)684 bool MethodTypeInfer::InferReturnUndefined(GateRef gate)
685 {
686 auto undefinedType = GateType::UndefinedType();
687 return UpdateType(gate, undefinedType);
688 }
689
InferReturn(GateRef gate)690 bool MethodTypeInfer::InferReturn(GateRef gate)
691 {
692 ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
693 auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
694 return UpdateType(gate, gateType);
695 }
696
InferLdObjByName(GateRef gate)697 bool MethodTypeInfer::InferLdObjByName(GateRef gate)
698 {
699 // 3: number of value inputs
700 ASSERT(gateAccessor_.GetNumValueIn(gate) == 3);
701 auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2)); // 2: the third parameter is receiver
702 if (objType.IsAnyType()) {
703 return UpdateType(gate, GateType::AnyType());
704 }
705 objType = tsManager_->TryNarrowUnionType(objType);
706 if (ShouldConvertToBuiltinArray(objType)) {
707 GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType);
708 auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt);
709 objType = GateType(builtinInstanceType);
710 }
711 if (tsManager_->IsPrimitiveTypeKind(objType)) {
712 GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType);
713 if (builtinGt.IsBuiltinModule()) {
714 auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt);
715 objType = GateType(builtinInstanceType);
716 }
717 }
718 // If this object has no gt type, we cannot get its internal property type
719 if (ShouldInferWithLdObjByName(objType)) {
720 uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
721 return GetObjPropWithName(gate, objType, index);
722 }
723 return UpdateType(gate, GateType::AnyType());
724 }
725
InferStObjByName(GateRef gate)726 bool MethodTypeInfer::InferStObjByName(GateRef gate)
727 {
728 GateRef value = gateAccessor_.GetValueIn(gate, 3); // 3: index of value
729 GateType valueType = gateAccessor_.GetGateType(value);
730 if (valueType.IsAnyType()) {
731 return false;
732 }
733
734 GateRef receiver = gateAccessor_.GetValueIn(gate, 2); // 2: index of receiver
735 GateType receiverType = gateAccessor_.GetGateType(receiver);
736
737 uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1)); // 1: index of key
738 JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(index);
739 if (tsManager_->IsNamespaceTypeKind(receiverType)) {
740 tsManager_->AddNamespacePropType(receiverType, propKey, valueType);
741 return true;
742 }
743
744 if (valueType.IsNumberType()) {
745 valueType = GateType::NumberType();
746 }
747
748 if (tsManager_->IsClassTypeKind(receiverType)) {
749 TSTypeAccessor typeAccessor(tsManager_, receiverType);
750 typeAccessor.UpdateStaticProp(propKey, valueType.GetGTRef());
751 return true;
752 }
753 return false;
754 }
755
InferNewObject(GateRef gate)756 bool MethodTypeInfer::InferNewObject(GateRef gate)
757 {
758 auto objType = gateAccessor_.GetGateType(gate);
759 if (!tsManager_->IsClassInstanceTypeKind(objType) && !tsManager_->IsArrayTypeKind(objType)) {
760 ASSERT(gateAccessor_.GetNumValueIn(gate) > 0);
761 auto classType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
762 if (tsManager_->IsClassTypeKind(classType)) {
763 auto classInstanceType = tsManager_->CreateClassInstanceType(classType);
764 return UpdateType(gate, classInstanceType);
765 }
766 }
767 return UpdateType(gate, GateType::AnyType());
768 }
769
InferLdStr(GateRef gate)770 bool MethodTypeInfer::InferLdStr(GateRef gate)
771 {
772 auto stringType = GateType::StringType();
773 return UpdateType(gate, stringType);
774 }
775
GetObjPropWithName(GateRef gate,GateType objType,uint64_t index)776 bool MethodTypeInfer::GetObjPropWithName(GateRef gate, GateType objType, uint64_t index)
777 {
778 JSTaggedValue name = tsManager_->GetStringFromConstantPool(index);
779 if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, objType) || tsManager_->IsTypedArrayType(objType)) {
780 auto thread = tsManager_->GetThread();
781 JSTaggedValue lengthKey = thread->GlobalConstants()->GetLengthString();
782 if (JSTaggedValue::SameValue(name, lengthKey)) {
783 return SetIntType(gate);
784 }
785 if (tsManager_->IsTypedArrayType(objType)) {
786 uint32_t eleIdx = 0;
787 if (EcmaStringAccessor(name).ToElementIndex(&eleIdx)) {
788 return UpdateType(gate, GateType::NumberType());
789 }
790 }
791 }
792 auto type = GetPropType(objType, name);
793 if (tsManager_->IsGetterSetterFunc(type)) {
794 auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type);
795 return UpdateType(gate, returnGt);
796 }
797 return UpdateType(gate, type);
798 }
799
InferCallMethod(GateRef gate)800 bool MethodTypeInfer::InferCallMethod(GateRef gate)
801 {
802 // 1: last one elem is function
803 size_t funcIndex = gateAccessor_.GetNumValueIn(gate) - 1;
804 auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex));
805 if (tsManager_->IsFunctionTypeKind(funcType)) {
806 // forEach CallBack
807 TSTypeAccessor typeAccessor(tsManager_, funcType);
808 if (typeAccessor.GetFunctionName() == "forEach") {
809 auto funcGate = gateAccessor_.GetValueIn(gate, funcIndex);
810 auto &bytecodeInfo = GetByteCodeInfo(funcGate);
811 if (bytecodeInfo.GetOpcode() == EcmaOpcode::LDOBJBYNAME_IMM8_ID16 ||
812 bytecodeInfo.GetOpcode() == EcmaOpcode::LDOBJBYNAME_IMM16_ID16) {
813 // 2: the third parameter is receiver
814 auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(funcGate, 2));
815 // get callBack function type
816 auto callBackType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
817 TSTypeAccessor newTypeAccessor(tsManager_, callBackType);
818 newTypeAccessor.UpdateForEachCBPara(objType);
819 }
820 }
821
822 // normal Call
823 auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType);
824 GateRef thisObj = gateAccessor_.GetValueIn(gate, 0); // 0: index of thisObject
825 auto thisObjType = gateAccessor_.GetGateType(thisObj);
826 return UpdateType(gate, HandleTypeCompatibility(thisObjType, GateType(returnType)));
827 } else if (tsManager_->IsIteratorInstanceTypeKind(funcType)) {
828 GlobalTSTypeRef elementGT = tsManager_->GetIteratorInstanceElementGt(funcType);
829 GlobalTSTypeRef iteratorResultInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType(
830 TSRuntimeType::ITERATOR_RESULT, elementGT);
831 return UpdateType(gate, iteratorResultInstanceType);
832 }
833 return UpdateType(gate, GateType::AnyType());
834 }
835
InferCallFunction(GateRef gate)836 bool MethodTypeInfer::InferCallFunction(GateRef gate)
837 {
838 // 1: last one elem is function
839 size_t funcIndex = gateAccessor_.GetNumValueIn(gate) - 1;
840 auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex));
841 if (tsManager_->IsFunctionTypeKind(funcType)) {
842 auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType);
843 return UpdateType(gate, returnType);
844 }
845 /* According to the ECMAScript specification, user-defined classes can only be instantiated by constructing (with
846 * new keyword). However, a few builtin types can be called like a function. Upon the results of calling and
847 * constructing, there are 4 categories of builtin types:
848 *
849 * Category 1: non-callable, objects of such a type can only be created by constructing.
850 * Category 2: non-constructable, such types can only be called.
851 * Category 3: simple, calling and constructing are equivalent.
852 * Category 4: complex, a type can be called and constructed, but the results differ.
853 *
854 * Constructing a builtin type always create objects of the type if supported. So in this function, we focus on the
855 * builtin types which are callable. While the majority of the callable builtin types have the same calling behavior
856 * as constructing, here are some special cases:
857 *
858 * | Type | Call | Category |
859 * | ------- | ----------------- | -------- |
860 * | BigInt | primitive bigint | 2 |
861 * | Boolean | primitive boolean | 4 |
862 * | Date | primitive string | 4 |
863 * | Number | primitive number | 4 |
864 * | String | primitive string | 4 |
865 *
866 * See the list of builtin types' constructors at:
867 * https://tc39.es/ecma262/2021/#sec-constructor-properties-of-the-global-object
868 */
869 if (tsManager_->IsBuiltinObjectType(funcType)) {
870 // For simplicity, calling and constructing are considered equivalent.
871 return UpdateType(gate, tsManager_->CreateClassInstanceType(funcType));
872 }
873 return UpdateType(gate, GateType::AnyType());
874 }
875
InferLdObjByValue(GateRef gate)876 bool MethodTypeInfer::InferLdObjByValue(GateRef gate)
877 {
878 auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
879 objType = tsManager_->TryNarrowUnionType(objType);
880 // handle array
881 if (tsManager_->IsArrayTypeKind(objType)) {
882 auto elementType = tsManager_->GetArrayParameterTypeGT(objType);
883 return UpdateType(gate, elementType);
884 }
885 if (tsManager_->IsIntTypedArrayType(objType)) {
886 return UpdateType(gate, GateType::IntType());
887 }
888 if (tsManager_->IsDoubleTypedArrayType(objType)) {
889 return UpdateType(gate, GateType::DoubleType());
890 }
891 // handle object
892 if (ShouldInferWithLdObjByValue(objType)) {
893 auto valueGate = gateAccessor_.GetValueIn(gate, 2); // 2: value input slot
894 if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
895 if (tsManager_->IsTypedArrayType(objType)) {
896 return UpdateType(gate, GateType::NumberType());
897 }
898 uint64_t value = gateAccessor_.GetConstantValue(valueGate);
899 auto type = GetPropType(objType, value);
900 return UpdateType(gate, type);
901 }
902 if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) {
903 auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(valueGate, 0));
904 return GetObjPropWithName(gate, objType, index);
905 }
906 }
907 return UpdateType(gate, GateType::AnyType());
908 }
909
InferGetNextPropName(GateRef gate)910 bool MethodTypeInfer::InferGetNextPropName(GateRef gate)
911 {
912 auto stringType = GateType::StringType();
913 return UpdateType(gate, stringType);
914 }
915
InferDefineGetterSetterByValue(GateRef gate)916 bool MethodTypeInfer::InferDefineGetterSetterByValue(GateRef gate)
917 {
918 // 0 : the index of obj
919 auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
920 return UpdateType(gate, objType);
921 }
922
InferSuperCall(GateRef gate)923 bool MethodTypeInfer::InferSuperCall(GateRef gate)
924 {
925 ArgumentAccessor argAcc(circuit_);
926 auto newTarget = argAcc.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
927 auto classType = gateAccessor_.GetGateType(newTarget);
928 if (tsManager_->IsClassTypeKind(classType)) {
929 auto classInstanceType = tsManager_->CreateClassInstanceType(classType);
930 return UpdateType(gate, classInstanceType);
931 }
932 return UpdateType(gate, GateType::AnyType());
933 }
934
InferSuperPropertyByName(GateRef gate)935 bool MethodTypeInfer::InferSuperPropertyByName(GateRef gate)
936 {
937 uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
938 return GetSuperProp(gate, index);
939 }
940
InferSuperPropertyByValue(GateRef gate)941 bool MethodTypeInfer::InferSuperPropertyByValue(GateRef gate)
942 {
943 auto valueGate = gateAccessor_.GetValueIn(gate, 1);
944 if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) {
945 auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(valueGate, 0));
946 return GetSuperProp(gate, index);
947 }
948 if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
949 auto index = gateAccessor_.GetConstantValue(valueGate);
950
951 return GetSuperProp(gate, index, false);
952 }
953 return UpdateType(gate, GateType::AnyType());
954 }
955
GetSuperProp(GateRef gate,uint64_t index,bool isString)956 bool MethodTypeInfer::GetSuperProp(GateRef gate, uint64_t index, bool isString)
957 {
958 ArgumentAccessor argAcc(circuit_);
959 auto func = argAcc.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
960 auto newTarget = argAcc.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
961 auto funcType = gateAccessor_.GetGateType(func);
962 auto classType = gateAccessor_.GetGateType(newTarget);
963 if (funcType.IsAnyType() || classType.IsAnyType() || classType.IsUndefinedType()) {
964 return UpdateType(gate, GateType::AnyType());
965 }
966
967 bool isStatic = tsManager_->IsStaticFunc(funcType.GetGTRef());
968 auto propType = isStatic ? PropertyType::STATIC : PropertyType::NORMAL;
969 GlobalTSTypeRef type = isString ?
970 tsManager_->GetSuperPropType(classType.GetGTRef(), tsManager_->GetStringFromConstantPool(index), propType) :
971 tsManager_->GetSuperPropType(classType.GetGTRef(), index, propType);
972 if (tsManager_->IsGetterSetterFunc(type)) {
973 auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type);
974 return UpdateType(gate, returnGt);
975 }
976 return UpdateType(gate, type);
977 }
978
InferGetIterator(GateRef gate)979 bool MethodTypeInfer::InferGetIterator(GateRef gate)
980 {
981 ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
982 GateType inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
983
984 GlobalTSTypeRef elementGt = GlobalTSTypeRef::Default();
985 if (tsManager_->IsArrayTypeKind(inValueType)) {
986 elementGt = tsManager_->GetArrayParameterTypeGT(inValueType);
987 } else if (inValueType.IsStringType()) {
988 elementGt.SetType(GateType::StringType().Value());
989 } else {
990 return UpdateType(gate, GateType::AnyType());
991 }
992 GlobalTSTypeRef iteratorInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType(
993 TSRuntimeType::ITERATOR, elementGt);
994 return UpdateType(gate, iteratorInstanceType);
995 }
996
InferTryLdGlobalByName(GateRef gate)997 bool MethodTypeInfer::InferTryLdGlobalByName(GateRef gate)
998 {
999 // todo by hongtao, should consider function of .d.ts
1000 auto &byteCodeInfo = GetByteCodeInfo(gate);
1001 ASSERT(byteCodeInfo.inputs.size() == 2); // 2: number of parameter
1002 auto stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
1003 auto iter = stringIdToGateType_.find(stringId);
1004 if (iter != stringIdToGateType_.end()) {
1005 return UpdateType(gate, iter->second);
1006 }
1007 return UpdateType(gate, GateType::AnyType());
1008 }
1009
InferLdLexVarDyn(GateRef gate)1010 bool MethodTypeInfer::InferLdLexVarDyn(GateRef gate)
1011 {
1012 auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1013 auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
1014 auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot);
1015 return UpdateType(gate, type);
1016 }
1017
InferStLexVarDyn(GateRef gate)1018 bool MethodTypeInfer::InferStLexVarDyn(GateRef gate)
1019 {
1020 auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1021 auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
1022 auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot);
1023 if (type.IsAnyType() || type.IsUndefinedType()) {
1024 auto valueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 3));
1025 if (!valueType.IsAnyType()) {
1026 lexEnvManager_->SetLexEnvElementType(methodId_, level, slot, valueType);
1027 return true;
1028 }
1029 }
1030 return false;
1031 }
1032
InferStModuleVar(GateRef gate)1033 bool MethodTypeInfer::InferStModuleVar(GateRef gate)
1034 {
1035 auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1036 const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1037 auto defineGate = gateAccessor_.GetValueIn(gate, 1);
1038 auto defineType = gateAccessor_.GetGateType(defineGate);
1039 if (!defineType.IsAnyType()) {
1040 tsManager_->AddTypeToModuleVarGtMap(jsPandaFile, recordName_, index, defineType.GetGTRef());
1041 return true;
1042 }
1043 return false;
1044 }
1045
InferLdLocalModuleVar(GateRef gate)1046 bool MethodTypeInfer::InferLdLocalModuleVar(GateRef gate)
1047 {
1048 auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1049 const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1050 if (!tsManager_->HasExportGT(jsPandaFile, recordName_, index)) {
1051 return UpdateType(gate, GateType::AnyType());
1052 }
1053 auto type = tsManager_->GetGTFromModuleMap(jsPandaFile, recordName_, index);
1054 return UpdateType(gate, type);
1055 }
1056
InferLdExternalModuleVar(GateRef gate)1057 bool MethodTypeInfer::InferLdExternalModuleVar(GateRef gate)
1058 {
1059 auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1060 auto loadType = gateAccessor_.GetGateType(gate);
1061 auto bcInfoCollector = tsManager_->GetBytecodeInfoCollector();
1062 ASSERT(bcInfoCollector != nullptr);
1063 const auto &bcInfo = bcInfoCollector->GetBytecodeInfo();
1064 const auto &importRecordsInfos = bcInfo.GetImportRecordsInfos();
1065 auto iter = importRecordsInfos.find(recordName_);
1066 const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1067 CString resolvedRecord = "";
1068 uint32_t resolvedIndex = 0;
1069 if (loadType.IsAnyType() && iter != importRecordsInfos.end()) {
1070 const auto &importIdToExportRecord = iter->second.GetImportIdToExportRecord();
1071 if (importIdToExportRecord.find(index) != importIdToExportRecord.end()) {
1072 std::tie(resolvedRecord, resolvedIndex) = importIdToExportRecord.at(index);
1073 if (tsManager_->HasExportGT(jsPandaFile, resolvedRecord, resolvedIndex)) {
1074 return UpdateType(gate, tsManager_->GetGTFromModuleMap(jsPandaFile, resolvedRecord, resolvedIndex));
1075 }
1076 }
1077 }
1078 // if we can't find type in exportRecords, we will try to find type using resolved index binding directly.
1079 // However, this compilation order is not guaranteed, so the export type may not have been infered.
1080 if (UNLIKELY(loadType.IsAnyType())) {
1081 auto thread = tsManager_->GetEcmaVM()->GetJSThread();
1082 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
1083 [[maybe_unused]] EcmaHandleScope scope(thread);
1084 JSHandle<SourceTextModule> currentModule = moduleManager->HostGetImportedModule(recordName_);
1085 JSTaggedValue moduleEnvironment = currentModule->GetEnvironment();
1086 if (moduleEnvironment.IsUndefined()) {
1087 return UpdateType(gate, GateType::AnyType());
1088 }
1089 ASSERT(moduleEnvironment.IsTaggedArray());
1090 JSHandle<TaggedArray> moduleArray(thread, moduleEnvironment);
1091 JSTaggedValue resolvedBinding = moduleArray->Get(index);
1092 // if resolvedBinding.IsHole(), means that importname is * or it belongs to empty Aot module.
1093 if (resolvedBinding.IsHole()) {
1094 return UpdateType(gate, GateType::AnyType());
1095 }
1096 ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
1097 resolvedRecord = ModuleManager::GetRecordName(binding->GetModule());
1098 resolvedIndex = static_cast<uint32_t>(binding->GetIndex());
1099 if (tsManager_->HasExportGT(jsPandaFile, resolvedRecord, resolvedIndex)) {
1100 return UpdateType(gate, tsManager_->GetGTFromModuleMap(jsPandaFile, resolvedRecord, resolvedIndex));
1101 }
1102 }
1103 return UpdateType(gate, GateType::AnyType());
1104 }
1105
InferLoopBeginPhiGate(GateRef gate)1106 bool MethodTypeInfer::InferLoopBeginPhiGate(GateRef gate)
1107 {
1108 // loop-begin phi gate has 3 ins: loop_begin(stateWire), loopInGate(valueWire), loopBackGate(valueWire)
1109 auto loopInGate = gateAccessor_.GetValueIn(gate);
1110 auto loopInType = gateAccessor_.GetGateType(loopInGate);
1111 // loop-begin phi will be initialized as loopInTytpe
1112 // type of loop-back phi should be infered correctly only after loop-begin has actual type
1113 // if loop-in phi is actual any type, loop-begin phi must be any
1114 if (loopPhiState_.find(gate) == loopPhiState_.end()) {
1115 if (!loopInType.IsAnyType()) {
1116 loopPhiState_[gate] = InferState::NORMAL_INFERED;
1117 }
1118 return UpdateType(gate, loopInType, false);
1119 }
1120 // if loop phi has been marked as ANY_INFERED, it's in the second round infer for loop
1121 if (loopPhiState_[gate] == InferState::ANY_INFERED) {
1122 return UpdateType(gate, GateType::AnyType(), false);
1123 }
1124 // if loopInType and loopBackType both have non-any type, we need special treatment for the situation
1125 // in which loopInType and loopBackType both are numberType(int/double/number).
1126 // However, we should avoid excessive type promotion which may cause endless loop in few IR situations.
1127 if (loopPhiState_[gate] == InferState::NUMBER_INFERED) {
1128 return UpdateType(gate, GateType::NumberType(), false);
1129 }
1130 return UpdateType(gate, loopInType, false);
1131 }
1132
ConvertPrimitiveToBuiltin(const GateType & gateType)1133 GlobalTSTypeRef MethodTypeInfer::ConvertPrimitiveToBuiltin(const GateType &gateType)
1134 {
1135 GlobalTSTypeRef builtinGt = GlobalTSTypeRef::Default();
1136 if (!tsManager_->IsBuiltinsDTSEnabled()) {
1137 return builtinGt;
1138 }
1139
1140 const JSPandaFile *builtinjsPandaFile = tsManager_->GetBuiltinPandaFile();
1141 if (builtinjsPandaFile == nullptr) {
1142 LOG_COMPILER(FATAL) << "load lib_ark_builtins.d.ts failed";
1143 }
1144 const CString &builtinsRecordName = tsManager_->GetBuiltinRecordName();
1145 TSTypeParser typeParser(tsManager_);
1146
1147 if (tsManager_->IsArrayTypeKind(gateType)) {
1148 return typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1149 static_cast<uint32_t>(BuiltinTypeId::ARRAY));
1150 }
1151
1152 const GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.Value());
1153 uint32_t l = gt.GetLocalId();
1154 switch (l) {
1155 case static_cast<uint32_t>(TSPrimitiveType::SYMBOL):
1156 builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1157 static_cast<uint32_t>(BuiltinTypeId::SYMBOL));
1158 break;
1159 case static_cast<uint32_t>(TSPrimitiveType::INT):
1160 case static_cast<uint32_t>(TSPrimitiveType::DOUBLE):
1161 case static_cast<uint32_t>(TSPrimitiveType::NUMBER):
1162 builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1163 static_cast<uint32_t>(BuiltinTypeId::NUMBER));
1164 break;
1165 case static_cast<uint32_t>(TSPrimitiveType::BOOLEAN):
1166 builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1167 static_cast<uint32_t>(BuiltinTypeId::BOOLEAN));
1168 break;
1169 case static_cast<uint32_t>(TSPrimitiveType::STRING):
1170 builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1171 static_cast<uint32_t>(BuiltinTypeId::STRING));
1172 break;
1173 default:
1174 builtinGt = GlobalTSTypeRef::Default();
1175 }
1176 return builtinGt;
1177 }
1178
GetPropType(const GateType type,const JSTaggedValue propertyName) const1179 GlobalTSTypeRef MethodTypeInfer::GetPropType(const GateType type, const JSTaggedValue propertyName) const
1180 {
1181 GlobalTSTypeRef objGT(type.Value());
1182 GlobalTSTypeRef propGT = tsManager_->GetPropType(objGT, propertyName);
1183 if (!propGT.IsDefault()) {
1184 return propGT;
1185 }
1186 return tsManager_->GetIndexSignType(objGT, GateType::StringType());
1187 }
1188
GetPropType(const GateType type,const uint64_t key) const1189 GlobalTSTypeRef MethodTypeInfer::GetPropType(const GateType type, const uint64_t key) const
1190 {
1191 GlobalTSTypeRef objGT(type.Value());
1192 GlobalTSTypeRef propGT = tsManager_->GetPropType(objGT, key);
1193 if (!propGT.IsDefault()) {
1194 return propGT;
1195 }
1196 return tsManager_->GetIndexSignType(objGT, GateType::NumberType());
1197 }
1198
1199 // In TS, a namespace can be thought of as a formalization of the IIFE pattern.
1200 // The function has only one parameter, which corresponds to the namespace object.
SetNamespaceArgType(GateType type)1201 void MethodTypeInfer::SetNamespaceArgType(GateType type)
1202 {
1203 ArgumentAccessor argAcc(circuit_, methodLiteral_);
1204 // the last position is where the only parameter of the function are placed
1205 auto gate = argAcc.ArgsAt(argAcc.ArgsCount() - 1);
1206 gateAccessor_.SetGateType(gate, type);
1207 }
1208
1209 // When a IIFE which corresponds to namespaces declaration being called,
1210 // A namespace type will be set to the namespace object.
SetAndReturnNamespaceObjType(GateRef gate)1211 std::pair<GateType, uint32_t> MethodTypeInfer::SetAndReturnNamespaceObjType(GateRef gate)
1212 {
1213 GateRef func = gateAccessor_.GetValueIn(gate, 1); // 1: index of func
1214 uint16_t id = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(func, 0)); // 0: index of methodId
1215 GateRef obj = gateAccessor_.GetValueIn(gate, 0); // 0: index of obj
1216 // the obj must be phi gate due to the conversion of syntax sugar of namespace
1217 ASSERT(gateAccessor_.IsValueSelector(obj));
1218 GlobalTSTypeRef gt = TryGetNamespaceType(obj);
1219
1220 uint32_t methodId = ctx_->GetJSPandaFile()->ResolveMethodIndex(methodLiteral_->GetMethodId(), id).GetOffset();
1221 uint32_t length = gateAccessor_.GetNumValueIn(obj);
1222 for (uint32_t i = 0; i < length; i++) {
1223 GateRef namespaceObj = gateAccessor_.GetValueIn(obj, i);
1224 if (!IsByteCodeGate(namespaceObj)) {
1225 continue;
1226 }
1227 auto &bytecodeInfo = GetByteCodeInfo(namespaceObj);
1228 if (!bytecodeInfo.IsBc(EcmaOpcode::CREATEEMPTYOBJECT)) {
1229 continue;
1230 }
1231
1232 if (gt.IsDefault()) {
1233 gt = tsManager_->CreateNamespaceType();
1234 }
1235 gateAccessor_.SetGateType(namespaceObj, GateType(gt));
1236 return std::make_pair(GateType(gt), methodId);
1237 }
1238
1239 return std::make_pair((GateType(gt)), methodId);
1240 }
1241
TryGetNamespaceType(GateRef gate) const1242 GlobalTSTypeRef MethodTypeInfer::TryGetNamespaceType(GateRef gate) const
1243 {
1244 ASSERT(gateAccessor_.IsValueSelector(gate));
1245 uint32_t length = gateAccessor_.GetNumValueIn(gate);
1246 for (uint32_t i = 0; i < length; i++) {
1247 GateRef namespaceObj = gateAccessor_.GetValueIn(gate, i);
1248 GateType type = gateAccessor_.GetGateType(namespaceObj);
1249 GlobalTSTypeRef namespaceGT(type.Value());
1250 if (tsManager_->IsNamespaceTypeKind(namespaceGT)) {
1251 return namespaceGT;
1252 }
1253 }
1254 return GlobalTSTypeRef::Default();
1255 }
1256
IsNamespace(GateRef gate) const1257 bool MethodTypeInfer::IsNamespace(GateRef gate) const
1258 {
1259 if (IsByteCodeGate(gate)) {
1260 auto &bytecodeInfo = GetByteCodeInfo(gate);
1261 if (bytecodeInfo.IsBc(EcmaOpcode::CALLARG1_IMM8_V8)) {
1262 GateRef obj = gateAccessor_.GetValueIn(gate, 0); // 0: index of obj
1263 GateRef func = gateAccessor_.GetValueIn(gate, 1); // 1: index of func
1264 return CheckNamespaceFunc(func) && gateAccessor_.IsValueSelector(obj);
1265 }
1266 }
1267 return false;
1268 }
1269
CheckNamespaceFunc(GateRef func) const1270 bool MethodTypeInfer::CheckNamespaceFunc(GateRef func) const
1271 {
1272 if (IsByteCodeGate(func)) {
1273 auto &bytecodeInfo = GetByteCodeInfo(func);
1274 if (bytecodeInfo.IsBc(EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8) ||
1275 bytecodeInfo.IsBc(EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1276 uint16_t id = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(func, 0)); // 0: index of methodId
1277 uint32_t methodId =
1278 ctx_->GetJSPandaFile()->ResolveMethodIndex(methodLiteral_->GetMethodId(), id).GetOffset();
1279 auto &bcInfo = ctx_->GetBytecodeInfo();
1280 auto &methodLists = bcInfo.GetMethodList();
1281 auto &methodInfo = methodLists.at(methodId);
1282 return methodInfo.IsNamespace();
1283 }
1284 }
1285 return false;
1286 }
1287
PrintTypeAnnotation() const1288 void MethodTypeInfer::PrintTypeAnnotation() const
1289 {
1290 const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1291 panda_file::File::EntityId fieldId = methodLiteral_->GetMethodId();
1292 TypeAnnotationExtractor annoExtractor(jsPandaFile, fieldId.GetOffset());
1293 annoExtractor.Print();
1294 }
1295
PrintByteCodesWithTypes() const1296 void MethodTypeInfer::PrintByteCodesWithTypes() const
1297 {
1298 std::vector<GateRef> gateList;
1299 circuit_->GetAllGates(gateList);
1300
1301 const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1302 const MethodLiteral *methodLiteral = builder_->GetMethod();
1303 auto methodId = methodLiteral->GetMethodId();
1304 const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
1305
1306 const uint32_t adjustment = 6;
1307 LOG_COMPILER(INFO) << "====================================================================";
1308 LOG_COMPILER(INFO) << "print bytecode types:";
1309 LOG_COMPILER(INFO) << ".recordName " + recordName_;
1310 LOG_COMPILER(INFO) << ".function " + functionName + "() {";
1311 uint32_t lastBcIndex = builder_->GetLastBcIndex();
1312 DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
1313 for (uint32_t bcIndex = 0; bcIndex < lastBcIndex; bcIndex++) { // ignore last element
1314 const uint8_t *pc = builder_->GetPCByIndex(bcIndex);
1315 BytecodeInstruction inst(pc);
1316 int32_t lineNumber = 0;
1317 auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
1318 lineNumber = line + 1;
1319 return true;
1320 };
1321 int32_t columnNumber = 0;
1322 auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool {
1323 columnNumber += column + 1;
1324 return true;
1325 };
1326 auto offset = builder_->GetPcOffset(bcIndex);
1327 debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset);
1328 debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset);
1329
1330 auto gates = builder_->GetGatesByBcIndex(bcIndex);
1331 if (gates.empty()) {
1332 LOG_COMPILER(INFO) << std::setw(adjustment) << std::to_string(bcIndex) << " " << inst << ", "
1333 << "at line: " + std::to_string(lineNumber) + " column: " + std::to_string(columnNumber)
1334 << ", pcOffset: " + std::to_string(offset);
1335 }
1336
1337 for (const auto gate : gates) {
1338 if (gate == Circuit::NullGate()) {
1339 continue;
1340 }
1341
1342 GateType type = gateAccessor_.GetGateType(gate);
1343 GlobalTSTypeRef gt = type.GetGTRef();
1344 LOG_COMPILER(INFO) << std::setw(adjustment) << std::to_string(bcIndex) << " " << inst << ", "
1345 << "[type: " + tsManager_->GetTypeStr(type) + ", "
1346 << "moduleId: " + std::to_string(gt.GetModuleId()) + ", "
1347 << "localId: " + std::to_string(gt.GetLocalId()) + "], "
1348 << "at line: " + std::to_string(lineNumber) + " column: " + std::to_string(columnNumber)
1349 << ", pcOffset: " + std::to_string(offset);
1350 }
1351 }
1352 LOG_COMPILER(INFO) << "}";
1353 }
1354
PrintCircuitWithTypes() const1355 void MethodTypeInfer::PrintCircuitWithTypes() const
1356 {
1357 LOG_COMPILER(INFO) << "\033[34m"
1358 << "===================="
1359 << " After ts type infer "
1360 << "[" << GetMethodName() << "]"
1361 << "===================="
1362 << "\033[0m";
1363 circuit_->PrintAllGatesWithBytecode();
1364 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
1365 LOG_COMPILER(INFO) << "";
1366 }
1367
Verify() const1368 void MethodTypeInfer::Verify() const
1369 {
1370 std::vector<GateRef> gateList;
1371 circuit_->GetAllGates(gateList);
1372 for (const auto &gate : gateList) {
1373 if (IsByteCodeGate(gate)) {
1374 TypeCheck(gate);
1375 }
1376 }
1377 }
1378
1379 /*
1380 * Let v be a variable in one ts-file and t be a type. To check whether the type of v is t after
1381 * type inferenece, one should declare a function named "AssertType(value:any, type:string):void"
1382 * in ts-file and call it with arguments v and t, where t is the expected type string.
1383 * The following interface performs such a check at compile time.
1384 */
TypeCheck(GateRef gate) const1385 void MethodTypeInfer::TypeCheck(GateRef gate) const
1386 {
1387 auto &info = GetByteCodeInfo(gate);
1388 if (!info.IsBc(EcmaOpcode::CALLARGS2_IMM8_V8_V8)) {
1389 return;
1390 }
1391 auto func = gateAccessor_.GetValueIn(gate, 2); // 2: acc
1392 auto &funcInfo = GetByteCodeInfo(func);
1393 if (!funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16) &&
1394 !funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16)) {
1395 return;
1396 }
1397 auto funcName = gateAccessor_.GetValueIn(func, 1);
1398 uint16_t funcNameStrId = gateAccessor_.GetConstantValue(funcName);
1399 auto funcNameString = tsManager_->GetStdStringFromConstantPool(funcNameStrId);
1400 if (funcNameString == "AssertType") {
1401 GateRef expectedGate = gateAccessor_.GetValueIn(gate, 1);
1402 GateRef constId = gateAccessor_.GetValueIn(expectedGate, 0);
1403 uint16_t strId = gateAccessor_.GetConstantValue(constId);
1404 auto expectedTypeStr = tsManager_->GetStdStringFromConstantPool(strId);
1405 GateRef valueGate = gateAccessor_.GetValueIn(gate, 0);
1406 auto type = gateAccessor_.GetGateType(valueGate);
1407 if (expectedTypeStr != tsManager_->GetTypeStr(type)) {
1408 const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1409 EntityId methodId = builder_->GetMethod()->GetMethodId();
1410 DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
1411 const std::string &sourceFileName = debugExtractor->GetSourceFile(methodId);
1412 const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
1413
1414 std::string log = CollectGateTypeLogInfo(valueGate, debugExtractor, "[TypeAssertion] ");
1415 log += "[TypeAssertion] but expected type: " + expectedTypeStr + "\n";
1416
1417 LOG_COMPILER(ERROR) << "[TypeAssertion] [" << sourceFileName << ":" << functionName << "] begin:";
1418 LOG_COMPILER(FATAL) << log << "[compiler] [TypeAssertion] end";
1419 }
1420 }
1421 }
1422
CollectGateTypeLogInfo(GateRef gate,DebugInfoExtractor * debugExtractor,const std::string & logPreFix) const1423 std::string MethodTypeInfer::CollectGateTypeLogInfo(GateRef gate, DebugInfoExtractor *debugExtractor,
1424 const std::string &logPreFix) const
1425 {
1426 std::string log(logPreFix);
1427 log += "gate id: "+ std::to_string(gateAccessor_.GetId(gate)) + ", ";
1428 OpCode op = gateAccessor_.GetOpCode(gate);
1429 log += "op: " + GateMetaData::Str(op) + ", ";
1430 if (op == OpCode::ARG) {
1431 log += "arg gate, ";
1432 } else if (op != OpCode::VALUE_SELECTOR) {
1433 auto &bytecodeInfo = GetByteCodeInfo(gate);
1434 // handle ByteCode gate: print gate id, bytecode and line number in source code.
1435 log += "bytecode: " + GetEcmaOpcodeStr(bytecodeInfo.GetOpcode()) + ", ";
1436
1437 int32_t lineNumber = 0;
1438 auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
1439 lineNumber = line + 1;
1440 return true;
1441 };
1442
1443 const auto bcIndex = jsgateToBytecode_.at(gate);
1444 auto offset = builder_->GetPcOffset(bcIndex);
1445 const MethodLiteral *methodLiteral = builder_->GetMethod();
1446 debugExtractor->MatchLineWithOffset(callbackLineFunc, methodLiteral->GetMethodId(), offset);
1447
1448 log += "at line: " + std::to_string(lineNumber) + ", ";
1449 } else {
1450 // handle phi gate: print gate id and input gates id list.
1451 log += "phi gate, ins: ";
1452 auto ins = gateAccessor_.ConstIns(gate);
1453 for (auto it = ins.begin(); it != ins.end(); it++) {
1454 log += std::to_string(gateAccessor_.GetId(*it)) + " ";
1455 }
1456 }
1457
1458 GateType type = gateAccessor_.GetGateType(gate);
1459 log += "type: " + tsManager_->GetTypeStr(type) + ", ";
1460 if (!tsManager_->IsPrimitiveTypeKind(type)) {
1461 GlobalTSTypeRef gt = type.GetGTRef();
1462 log += "[moduleId: " + std::to_string(gt.GetModuleId()) + ", ";
1463 log += "localId: " + std::to_string(gt.GetLocalId()) + "], ";
1464 }
1465
1466 log += "\n[compiler] ";
1467 return log;
1468 }
1469
VerifyTypePercent()1470 void MethodTypeInfer::VerifyTypePercent()
1471 {
1472 shouldInferNum_ = needInferGates_.size();
1473 for (auto gate : needInferGates_) {
1474 if (!gateAccessor_.GetGateType(gate).IsAnyType()) {
1475 normalInferNum_++;
1476 }
1477 }
1478 double rate = needInferGates_.empty() ? 0.0 : (double)normalInferNum_ / (double)shouldInferNum_;
1479 auto typeThreshold = tsManager_->GetTypeThreshold();
1480 if (rate <= typeThreshold) {
1481 methodInfo_->SetTypeInferAbort(true);
1482 }
1483 if (IsLogEnabled()) {
1484 LOG_COMPILER(INFO) << "====================================================================";
1485 LOG_COMPILER(INFO) << "[TypeCoverage] print method type coverage: \n"
1486 << "[compiler] [TypeCoverage] [ShouldInferedGate]: " << shouldInferNum_
1487 << " || [NormalInferedGate]: " << normalInferNum_ << "\n"
1488 << "[compiler] [TypeCoverage] [TypeCoverage Percentage]: "
1489 << std::fixed << std::setprecision(PERCENT_LENS) << rate * HUNDRED_TIME << "%";
1490 if (rate <= typeThreshold) {
1491 LOG_COMPILER(INFO) << "[TypeCoverage] TypeCoverage Percentage is lower than threshold: ["
1492 << typeThreshold << "]";
1493 }
1494 }
1495 }
1496 } // namespace panda::ecmascript
1497