• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/type_info_accessors.h"
17 
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/compiler/circuit.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/global_env_fields.h"
22 #include "ecmascript/js_hclass-inl.h"
23 #include "ecmascript/jspandafile/js_pandafile.h"
24 #include "ecmascript/jspandafile/program_object.h"
25 #include "ecmascript/ts_types/ts_type_accessor.h"
26 
27 namespace panda::ecmascript::kungfu {
GetStringFromConstantPool(const JSThread * thread,uint32_t methodId,uint32_t index)28 JSTaggedValue TypeInfoAccessor::GetStringFromConstantPool(const JSThread *thread, uint32_t methodId, uint32_t index)
29 {
30     return thread->GetCurrentEcmaContext()->GetTSManager()->GetStringFromConstantPool(methodId, index);
31 }
32 
33 // TypeTrusted means the type of gate is already PrimitiveTypeCheck-passed,
34 // or the gate is constant and no need to check.
IsTrustedType(GateAccessor acc,GateRef gate)35 bool TypeInfoAccessor::IsTrustedType(GateAccessor acc, GateRef gate)
36 {
37     if (acc.IsConstant(gate)) {
38         return true;
39     }
40     auto op = acc.GetOpCode(gate);
41     if (acc.IsTypedOperator(gate)) {
42         if (op == OpCode::TYPED_BINARY_OP) {
43             return !acc.GetGateType(gate).IsIntType();
44         } else {
45             return true;
46         }
47     }
48     if (op == OpCode::JS_BYTECODE) {
49         EcmaOpcode ecmaOpcode = acc.GetByteCodeOpcode(gate);
50         switch (ecmaOpcode) {
51             case EcmaOpcode::ADD2_IMM8_V8:
52             case EcmaOpcode::SUB2_IMM8_V8:
53             case EcmaOpcode::MUL2_IMM8_V8:
54                 return !acc.GetGateType(gate).IsIntType();
55             case EcmaOpcode::INC_IMM8:
56             case EcmaOpcode::DEC_IMM8:
57             case EcmaOpcode::LESS_IMM8_V8:
58             case EcmaOpcode::LESSEQ_IMM8_V8:
59             case EcmaOpcode::GREATER_IMM8_V8:
60             case EcmaOpcode::GREATEREQ_IMM8_V8:
61             case EcmaOpcode::EQ_IMM8_V8:
62             case EcmaOpcode::NOTEQ_IMM8_V8:
63             case EcmaOpcode::STRICTEQ_IMM8_V8:
64             case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
65             case EcmaOpcode::ISTRUE:
66             case EcmaOpcode::ISFALSE:
67                 return true;
68             default:
69                 break;
70         }
71     }
72     return false;
73 }
74 
IsTrustedStringType(const JSThread * thread,Circuit * circuit,Chunk * chunk,GateAccessor acc,GateRef gate)75 bool TypeInfoAccessor::IsTrustedStringType(
76     const JSThread *thread, Circuit *circuit, Chunk *chunk, GateAccessor acc, GateRef gate)
77 {
78     auto op = acc.GetOpCode(gate);
79     if (op == OpCode::LOAD_ELEMENT) {
80         return acc.GetTypedLoadOp(gate) == TypedLoadOp::STRING_LOAD_ELEMENT;
81     }
82     if (op == OpCode::JS_BYTECODE) {
83         EcmaOpcode ecmaOpcode = acc.GetByteCodeOpcode(gate);
84         switch (ecmaOpcode) {
85             case EcmaOpcode::LDA_STR_ID16:
86                 return true;
87             case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
88             case EcmaOpcode::LDOBJBYVALUE_IMM16_V8: {
89                 LoadBulitinObjTypeInfoAccessor tacc(thread, circuit, gate, chunk);
90                 if (tacc.IsMono()) {
91                     return tacc.IsBuiltinsString();
92                 }
93                 break;
94             }
95             default:
96                 break;
97         }
98     }
99     return false;
100 }
101 
BinOpTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,bool convertNumberType)102 BinOpTypeInfoAccessor::BinOpTypeInfoAccessor(const JSThread *thread, Circuit *circuit,
103                                              GateRef gate, bool convertNumberType)
104     : TypeInfoAccessor(thread, circuit, gate), convertNumberType_(convertNumberType)
105 {
106     left_ = acc_.GetValueIn(gate, 0);  // 0: left
107     right_ = acc_.GetValueIn(gate, 1);  // 1: right
108 }
109 
HasNumberType() const110 bool BinOpTypeInfoAccessor::HasNumberType() const
111 {
112     GateType leftType = acc_.GetGateType(left_);
113     GateType rightType = acc_.GetGateType(right_);
114 
115     const PGOSampleType *sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType();
116     if (sampleType->IsNumber()) {
117         return true;
118     } else if (convertNumberType_ && sampleType->IsNone() && leftType.IsPrimitiveNumberType() &&
119                rightType.IsPrimitiveNumberType()) {
120         return true;
121     } else if (!convertNumberType_ && sampleType->IsNone() && leftType.IsNumberType() && rightType.IsNumberType()) {
122         return true;
123     } else {
124         return false;
125     }
126     return false;
127 }
128 
HasStringType() const129 bool BinOpTypeInfoAccessor::HasStringType() const
130 {
131     GateType leftType = acc_.GetGateType(left_);
132     GateType rightType = acc_.GetGateType(right_);
133     const PGOSampleType *sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType();
134     if (sampleType->IsString()) {
135         return true;
136     } else if (sampleType->IsNone() && leftType.IsStringType() && rightType.IsStringType()) {
137         return true;
138     }
139     return false;
140 }
141 
UnOpTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)142 UnOpTypeInfoAccessor::UnOpTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
143     : TypeInfoAccessor(thread, circuit, gate)
144 {
145     value_ = acc_.GetValueIn(gate, 0); // 0: value
146 }
147 
ValueIsNumberType() const148 bool UnOpTypeInfoAccessor::ValueIsNumberType() const
149 {
150     const PGOSampleType *sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType();
151     if (sampleType->IsNumber() ||
152         (sampleType->IsNone() && ValueIsPrimitiveNumberType())) {
153         return true;
154     }
155     return false;
156 }
157 
FindHClass()158 bool NewObjRangeTypeInfoAccessor::FindHClass()
159 {
160     auto sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType();
161     if (!sampleType->IsProfileType()) {
162         return false;
163     }
164     auto type = std::make_pair(sampleType->GetProfileType(), sampleType->GetProfileType());
165     hclassIndex_ = static_cast<int>(ptManager_->GetHClassIndexByProfileType(type));
166     if (hclassIndex_ == -1) {
167         return false;
168     }
169     return ptManager_->QueryHClass(type.first, type.second).IsJSHClass();
170 }
171 
IsIllegalType() const172 bool TypeOfTypeInfoAccessor::IsIllegalType() const
173 {
174     GateType valueType = GetValueGateType();
175     if (!valueType.IsDigitablePrimitiveType() && !valueType.IsStringType() && !valueType.IsSymbolType()) {
176         if (!tsManager_->IsFunctionTypeKind(valueType) && !tsManager_->IsObjectTypeKind(valueType) &&
177             !tsManager_->IsClassTypeKind(valueType) && !tsManager_->IsClassInstanceTypeKind(valueType) &&
178             !tsManager_->IsArrayTypeKind(valueType)) {
179             return true;
180         }
181     }
182     return false;
183 }
184 
SuperCallTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)185 SuperCallTypeInfoAccessor::SuperCallTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
186     : TypeInfoAccessor(thread, circuit, gate)
187 {
188     ctor_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
189 }
190 
TryGetPGOBuiltinId() const191 BuiltinsStubCSigns::ID CallTypeInfoAccessor::TryGetPGOBuiltinId() const
192 {
193     PGOTypeRef sampleType = acc_.TryGetPGOType(gate_);
194     if (sampleType.GetPGOSampleType()->IsNone()) {
195         return BuiltinsStubCSigns::ID::NONE;
196     }
197     if (sampleType.GetPGOSampleType()->GetProfileType().IsBuiltinFunctionId()) {
198         return static_cast<BuiltinsStubCSigns::ID>(sampleType.GetPGOSampleType()->GetProfileType().GetId());
199     }
200     return BuiltinsStubCSigns::ID::NONE;
201 }
202 
TryGetBuiltinId(BuiltinTypeId id) const203 BuiltinsStubCSigns::ID CallTypeInfoAccessor::TryGetBuiltinId(BuiltinTypeId id) const
204 {
205     GateType funcType = acc_.GetGateType(func_);
206     if (!tsManager_->IsBuiltinObjectMethod(id, funcType)) {
207         return BuiltinsStubCSigns::ID::NONE;
208     }
209     std::string name = tsManager_->GetFuncName(funcType);
210     BuiltinsStubCSigns::ID stubId = BuiltinsStubCSigns::GetBuiltinId(name);
211     return stubId;
212 }
213 
GetIteratorTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)214 GetIteratorTypeInfoAccessor::GetIteratorTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
215     : CallTypeInfoAccessor(thread, circuit, gate)
216 {
217     argc_ = 0; // 0: number of argc
218     func_ = acc_.GetValueIn(gate, 0); // 1: func
219 }
220 
CallArg0TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)221 CallArg0TypeInfoAccessor::CallArg0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
222     : CallTypeInfoAccessor(thread, circuit, gate)
223 {
224     argc_ = 0; // 0: number of argc
225     func_ = acc_.GetValueIn(gate, 0); // 0: func
226 }
227 
CallArg1TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)228 CallArg1TypeInfoAccessor::CallArg1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
229     : CallTypeInfoAccessor(thread, circuit, gate)
230 {
231     argc_ = 1; // 1: number of argc
232     value_ = acc_.GetValueIn(gate, 0); // 0: value
233     func_ = acc_.GetValueIn(gate, 1); // 1: func
234 }
235 
CallArg2TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)236 CallArg2TypeInfoAccessor::CallArg2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
237     : CallTypeInfoAccessor(thread, circuit, gate)
238 {
239     argc_ = 2; // 2: number of argc
240     func_ = acc_.GetValueIn(gate, 2); // 2: func
241 }
242 
CallArg3TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)243 CallArg3TypeInfoAccessor::CallArg3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
244     : CallTypeInfoAccessor(thread, circuit, gate)
245 {
246     argc_ = 3; // 3: number of argc
247     func_ = acc_.GetValueIn(gate, 3); // 3: func
248 }
249 
CallRangeTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)250 CallRangeTypeInfoAccessor::CallRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
251     : CallTypeInfoAccessor(thread, circuit, gate)
252 {
253     size_t numArgs = acc_.GetNumValueIn(gate);
254     constexpr size_t callTargetIndex = 1; // acc
255     argc_ = numArgs - callTargetIndex;
256     func_ = acc_.GetValueIn(gate, argc_);
257 }
258 
CanOptimizeAsFastCall()259 bool CallThisTypeInfoAccessor::CanOptimizeAsFastCall()
260 {
261     GateType funcType = acc_.GetGateType(func_);
262     if (!tsManager_->IsFunctionTypeKind(funcType)) {
263         return false;
264     }
265     auto op = acc_.GetOpCode(func_);
266     if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func_)) {
267         return false;
268     }
269     return true;
270 }
271 
CallThis0TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)272 CallThis0TypeInfoAccessor::CallThis0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
273     : CallThisTypeInfoAccessor(thread, circuit, gate)
274 {
275     argc_ = 0; // 0: number of argc
276     func_ = acc_.GetValueIn(gate, 1); // 1: func
277 }
278 
CallThis1TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)279 CallThis1TypeInfoAccessor::CallThis1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
280     : CallThisTypeInfoAccessor(thread, circuit, gate)
281 {
282     argc_ = 1; // 1: number of argc
283     func_ = acc_.GetValueIn(gate, 2); // 2: func
284     a0_ = acc_.GetValueIn(gate, 1); // 1: arg0
285 }
286 
CallThis2TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)287 CallThis2TypeInfoAccessor::CallThis2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
288     : CallThisTypeInfoAccessor(thread, circuit, gate)
289 {
290     argc_ = 2; // 2: number of argc
291     func_ = acc_.GetValueIn(gate, 3); // 3: func
292 }
293 
CallThis3TypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)294 CallThis3TypeInfoAccessor::CallThis3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
295     : CallThisTypeInfoAccessor(thread, circuit, gate)
296 {
297     argc_ = 3; // 3: number of argc
298     func_ = acc_.GetValueIn(gate, 3); // 3: func
299     a0_ = acc_.GetValueIn(gate, 1); // 1: arg0
300     a1_ = acc_.GetValueIn(gate, 2); // 2: arg1
301     a2_ = acc_.GetValueIn(gate, 3); // 3: arg2
302 }
303 
CallThisRangeTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate)304 CallThisRangeTypeInfoAccessor::CallThisRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate)
305     : CallThisTypeInfoAccessor(thread, circuit, gate)
306 {
307     constexpr size_t fixedInputsNum = 1;
308     constexpr size_t callTargetIndex = 1;  // 1: acc
309     ASSERT(acc_.GetNumValueIn(gate) - fixedInputsNum >= 0);
310     size_t numIns = acc_.GetNumValueIn(gate);
311     argc_ = numIns - callTargetIndex - fixedInputsNum;
312     func_ = acc_.GetValueIn(gate, numIns - callTargetIndex); // acc
313 }
314 
InlineTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,GateRef receiver,CallKind kind)315 InlineTypeInfoAccessor::InlineTypeInfoAccessor(
316     const JSThread *thread, Circuit *circuit, GateRef gate, GateRef receiver, CallKind kind)
317     : TypeInfoAccessor(thread, circuit, gate), receiver_(receiver), kind_(kind)
318 {
319     if (IsCallAccessor()) {
320         plr_ = GetAccessorPlr();
321     }
322 }
323 
GetAccessorFuncGT() const324 GlobalTSTypeRef InlineTypeInfoAccessor::GetAccessorFuncGT() const
325 {
326     GateType receiverType = acc_.GetGateType(receiver_);
327     receiverType = tsManager_->TryNarrowUnionType(receiverType);
328     GlobalTSTypeRef classInstanceGT = receiverType.GetGTRef();
329     GlobalTSTypeRef classGT = tsManager_->GetClassType(classInstanceGT);
330     TSTypeAccessor tsTypeAcc(tsManager_, classGT);
331     GateRef constData = acc_.GetValueIn(gate_, 1);
332     uint16_t propIndex = acc_.GetConstantValue(constData);
333     auto methodOffset = acc_.TryGetMethodOffset(gate_);
334     auto prop = tsManager_->GetStringFromConstantPool(methodOffset, propIndex);
335     GlobalTSTypeRef funcGT = tsTypeAcc.GetAccessorGT(prop, IsCallSetter());
336     return funcGT;
337 }
338 
GetAccessorPlr() const339 PropertyLookupResult InlineTypeInfoAccessor::GetAccessorPlr() const
340 {
341     GateRef constData = acc_.GetValueIn(gate_, 1);
342     uint16_t propIndex = acc_.GetConstantValue(constData);
343     auto methodOffset = acc_.TryGetMethodOffset(gate_);
344     auto prop = tsManager_->GetStringFromConstantPool(methodOffset, propIndex);
345     // PGO currently does not support call, so GT is still used to support inline operations.
346     // However, the original GT solution cannot support accessing the property of prototype, so it is filtered here
347     if (EcmaStringAccessor(prop).ToStdString() == "prototype") {
348         return PropertyLookupResult();
349     }
350 
351     const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
352     if (pgoTypes->GetCount() != 1) {
353         return PropertyLookupResult();
354     }
355     auto pgoType = pgoTypes->GetObjectInfo(0);
356     ProfileTyper receiverType = std::make_pair(pgoType.GetReceiverRootType(), pgoType.GetReceiverType());
357     ProfileTyper holderType = std::make_pair(pgoType.GetHoldRootType(), pgoType.GetHoldType());
358 
359     PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
360     JSHClass *hclass = nullptr;
361     if (receiverType == holderType) {
362         int hclassIndex = static_cast<int>(ptManager->GetHClassIndexByProfileType(receiverType));
363         if (hclassIndex == -1) {
364             return PropertyLookupResult();
365         }
366         hclass = JSHClass::Cast(ptManager->QueryHClass(receiverType.first, receiverType.second).GetTaggedObject());
367     } else {
368         int hclassIndex = static_cast<int>(ptManager->GetHClassIndexByProfileType(holderType));
369         if (hclassIndex == -1) {
370             return PropertyLookupResult();
371         }
372         hclass = JSHClass::Cast(ptManager->QueryHClass(holderType.first, holderType.second).GetTaggedObject());
373     }
374 
375     PropertyLookupResult plr = JSHClass::LookupPropertyInPGOHClass(thread_, hclass, prop);
376     return plr;
377 }
378 
GetCallMethodId() const379 uint32_t InlineTypeInfoAccessor::GetCallMethodId() const
380 {
381     uint32_t methodOffset = 0;
382     if (IsNormalCall() && IsValidCallMethodId()) {
383         methodOffset = GetFuncMethodOffsetFromPGO();
384         if (methodOffset == base::PGO_POLY_INLINE_REP) {
385             methodOffset = 0;
386             return methodOffset;
387         }
388     }
389     if (methodOffset == 0) {
390         if (IsFunctionTypeKind()) {
391             auto funcGT = GetReceiverGT().GetGTRef();
392             methodOffset = tsManager_->GetFuncMethodOffset(funcGT);
393         } else if (IsClassInstanceTypeKind()) {
394             auto funcGT = GetAccessorFuncGT();
395             methodOffset = tsManager_->GetFuncMethodOffset(funcGT);
396         }
397     }
398     return methodOffset;
399 }
400 
GetKeyTaggedValue() const401 JSTaggedValue ObjectAccessTypeInfoAccessor::GetKeyTaggedValue() const
402 {
403     uint16_t index = acc_.GetConstantValue(key_);
404     auto methodOffset = acc_.TryGetMethodOffset(GetGate());
405     return TypeInfoAccessor::GetStringFromConstantPool(thread_, methodOffset, index);
406 }
407 
GeneratePlr(ProfileTyper type,ObjectAccessInfo & info,JSTaggedValue key) const408 bool ObjAccByNameTypeInfoAccessor::GeneratePlr(ProfileTyper type, ObjectAccessInfo &info, JSTaggedValue key) const
409 {
410     int hclassIndex = static_cast<int>(ptManager_->GetHClassIndexByProfileType(type));
411     if (hclassIndex == -1) {
412         return false;
413     }
414     JSHClass *hclass = JSHClass::Cast(ptManager_->QueryHClass(type.first, type.second).GetTaggedObject());
415     PropertyLookupResult plr = JSHClass::LookupPropertyInPGOHClass(thread_, hclass, key);
416     info.Set(hclassIndex, plr);
417 
418     if (mode_ == AccessMode::LOAD) {
419         return plr.IsFound();
420     }
421 
422     return (plr.IsFound() && !plr.IsFunction());
423 }
424 
LoadObjByNameTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,Chunk * chunk)425 LoadObjByNameTypeInfoAccessor::LoadObjByNameTypeInfoAccessor(const JSThread *thread, Circuit *circuit,
426                                                              GateRef gate, Chunk *chunk)
427     : ObjAccByNameTypeInfoAccessor(thread, circuit, gate, chunk, AccessMode::LOAD), types_(chunk_)
428 {
429     key_ = acc_.GetValueIn(gate, 1); // 1: key
430     receiver_ = acc_.GetValueIn(gate, 2); // 2: receiver
431     FetchPGORWTypesDual();
432     hasIllegalType_ = !GenerateObjectAccessInfo();
433 }
434 
FetchPGORWTypesDual()435 void LoadObjByNameTypeInfoAccessor::FetchPGORWTypesDual()
436 {
437     const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
438     for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
439         auto temp = pgoTypes->GetObjectInfo(i);
440         if (temp.GetReceiverType().IsBuiltinsType()) {
441             continue;
442         }
443         types_.emplace_back(std::make_pair(
444             std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
445             std::make_pair(temp.GetHoldRootType(), temp.GetHoldType())
446         ));
447     }
448 }
449 
GenerateObjectAccessInfo()450 bool LoadObjByNameTypeInfoAccessor::GenerateObjectAccessInfo()
451 {
452     JSTaggedValue key = GetKeyTaggedValue();
453     for (size_t i = 0; i < types_.size(); ++i) {
454         ProfileTyper receiverType = types_[i].first;
455         ProfileTyper holderType = types_[i].second;
456         if (receiverType == holderType) {
457             ObjectAccessInfo info;
458             if (!GeneratePlr(receiverType, info, key)) {
459                 return false;
460             }
461             accessInfos_.emplace_back(info);
462             checkerInfos_.emplace_back(info);
463         } else {
464             ObjectAccessInfo accInfo;
465             if (!GeneratePlr(holderType, accInfo, key)) {
466                 return false;
467             }
468             accessInfos_.emplace_back(accInfo);
469             ObjectAccessInfo checkInfo;
470             GeneratePlr(receiverType, checkInfo, key);
471             if (checkInfo.HClassIndex() == -1) {
472                 return false;
473             }
474             checkerInfos_.emplace_back(checkInfo);
475         }
476     }
477     return true;
478 }
479 
StoreObjByNameTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,Chunk * chunk)480 StoreObjByNameTypeInfoAccessor::StoreObjByNameTypeInfoAccessor(const JSThread *thread, Circuit *circuit,
481                                                                GateRef gate, Chunk *chunk)
482     : ObjAccByNameTypeInfoAccessor(thread, circuit, gate, chunk, AccessMode::STORE), types_(chunk_)
483 {
484     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
485     switch (ecmaOpcode) {
486         case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
487         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
488         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8: {
489             key_ = acc_.GetValueIn(gate, 1); // 1: key
490             receiver_ = acc_.GetValueIn(gate, 2); // 2: receiver
491             value_ = acc_.GetValueIn(gate, 3); // 3: value
492             break;
493         }
494         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
495         case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
496             key_ = acc_.GetValueIn(gate, 1); // 1: key
497             receiver_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
498             value_ = acc_.GetValueIn(gate, 2); // 2: value
499             break;
500         }
501         case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
502         case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8: {
503             key_ = acc_.GetValueIn(gate, 0); // 0: key
504             receiver_ = acc_.GetValueIn(gate, 1); // 1: receiver
505             value_ = acc_.GetValueIn(gate, 2); // 2: value
506             break;
507         }
508         default:
509             UNREACHABLE();
510     }
511 
512     FetchPGORWTypesDual();
513     hasIllegalType_ = !GenerateObjectAccessInfo();
514 }
515 
FetchPGORWTypesDual()516 void StoreObjByNameTypeInfoAccessor::FetchPGORWTypesDual()
517 {
518     const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
519     for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
520         auto temp = pgoTypes->GetObjectInfo(i);
521         types_.emplace_back(std::make_tuple(
522             std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
523             std::make_pair(temp.GetHoldRootType(), temp.GetHoldType()),
524             std::make_pair(temp.GetHoldTraRootType(), temp.GetHoldTraType())
525         ));
526     }
527 }
528 
GenerateObjectAccessInfo()529 bool StoreObjByNameTypeInfoAccessor::GenerateObjectAccessInfo()
530 {
531     JSTaggedValue key = GetKeyTaggedValue();
532     for (size_t i = 0; i < types_.size(); ++i) {
533         ProfileTyper receiverType = std::get<0>(types_[i]);
534         ProfileTyper holderType = std::get<1>(types_[i]);
535         ProfileTyper newHolderType = std::get<2>(types_[i]);
536 
537         if (receiverType != newHolderType) {
538             // transition happened ==> slowpath
539             ObjectAccessInfo newHolderInfo;
540             if (!GeneratePlr(newHolderType, newHolderInfo, key)) {
541                 return false;
542             }
543             accessInfos_.emplace_back(newHolderInfo);
544 
545             ObjectAccessInfo receiverInfo;
546             GeneratePlr(receiverType, receiverInfo, key);
547             if (receiverInfo.HClassIndex() == -1) {
548                 return false;
549             }
550             checkerInfos_.emplace_back(receiverInfo);
551         } else if (receiverType == holderType) {
552             ObjectAccessInfo receiverInfo;
553             if (!GeneratePlr(receiverType, receiverInfo, key)) {
554                 return false;
555             }
556             accessInfos_.emplace_back(receiverInfo);
557             checkerInfos_.emplace_back(receiverInfo);
558         } else {
559             UNREACHABLE();
560         }
561     }
562     return true;
563 }
564 
InstanceOfTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,Chunk * chunk)565 InstanceOfTypeInfoAccessor::InstanceOfTypeInfoAccessor(const JSThread *thread, Circuit *circuit,
566                                                        GateRef gate, Chunk *chunk)
567     : ObjAccByNameTypeInfoAccessor(thread, circuit, gate, chunk, AccessMode::LOAD), types_(chunk_)
568 {
569     receiver_ = acc_.GetValueIn(gate, 1); // 2: receiver
570     target_ = acc_.GetValueIn(gate, 2);  // 2: the third parameter
571 
572     FetchPGORWTypesDual();
573     hasIllegalType_ = !GenerateObjectAccessInfo();
574 }
575 
GetKeyTaggedValue() const576 JSTaggedValue InstanceOfTypeInfoAccessor::GetKeyTaggedValue() const
577 {
578     JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
579     auto hasInstanceEnvIndex = static_cast<size_t>(GlobalEnvField::HASINSTANCE_SYMBOL_INDEX);
580     return globalEnv->GetGlobalEnvObjectByIndex(hasInstanceEnvIndex).GetTaggedValue();
581 }
582 
FetchPGORWTypesDual()583 void InstanceOfTypeInfoAccessor::FetchPGORWTypesDual()
584 {
585     const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
586     for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
587         auto temp = pgoTypes->GetObjectInfo(i);
588         if (temp.GetReceiverType().IsBuiltinsType()) {
589             continue;
590         }
591         types_.emplace_back(std::make_pair(
592             std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
593             std::make_pair(temp.GetHoldRootType(), temp.GetHoldType())
594         ));
595     }
596 }
597 
ClassInstanceIsCallable(ProfileTyper type) const598 bool InstanceOfTypeInfoAccessor::ClassInstanceIsCallable(ProfileTyper type) const
599 {
600     int hclassIndex = static_cast<int>(ptManager_->GetHClassIndexByProfileType(type));
601     if (hclassIndex == -1) {
602         return false;
603     }
604 
605     JSHClass *hclass = JSHClass::Cast(ptManager_->QueryHClass(type.first, type.second).GetTaggedObject());
606 
607     return hclass->IsCallable();
608 }
609 
GenerateObjectAccessInfo()610 bool InstanceOfTypeInfoAccessor::GenerateObjectAccessInfo()
611 {
612     // Instanceof does not support Poly for now
613     if (!IsMono()) {
614         return false;
615     }
616     JSTaggedValue key = GetKeyTaggedValue();
617     for (size_t i = 0; i < types_.size(); ++i) {
618         ProfileTyper targetPgoType = types_[i].first;
619         ObjectAccessInfo targetInfo;
620         // If @@hasInstance is found on prototype Chain of ctor -> slowpath
621         // Future work: pgo support Symbol && Dump Object.defineProperty && FunctionPrototypeHclass
622         // Current temporary solution:
623         // Try searching @@hasInstance in pgo dump stage,
624         // If found, pgo dump no types and we go slowpath in aot
625         GeneratePlr(targetPgoType, targetInfo, key);
626         if (targetInfo.HClassIndex() == -1 || !ClassInstanceIsCallable(targetPgoType)) {
627             return false;
628         }
629         accessInfos_.emplace_back(targetInfo);
630         checkerInfos_.emplace_back(targetInfo);
631     }
632     return true;
633 }
634 
LoadBulitinObjTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,Chunk * chunk)635 LoadBulitinObjTypeInfoAccessor::LoadBulitinObjTypeInfoAccessor(const JSThread *thread, Circuit *circuit,
636                                                                GateRef gate, Chunk *chunk)
637     : AccBuiltinObjTypeInfoAccessor(thread, circuit, gate, chunk, AccessMode::LOAD)
638 {
639     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
640     switch (ecmaOpcode) {
641         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
642         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8: {
643             receiver_ = acc_.GetValueIn(gate, 1); // 1: receiver
644             key_ = acc_.GetValueIn(gate, 2);  // 2: key
645             break;
646         }
647         case EcmaOpcode::LDTHISBYVALUE_IMM8:
648         case EcmaOpcode::LDTHISBYVALUE_IMM16: {
649             receiver_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
650             key_ = acc_.GetValueIn(gate, 1); // 1: key
651             break;
652         }
653         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
654         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
655             key_ = acc_.GetValueIn(gate, 1); // 1: key
656             receiver_ = acc_.GetValueIn(gate, 2); // 2: receiver
657             break;
658         }
659         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
660         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16: {
661             key_ = acc_.GetValueIn(gate, 1); // 1: key
662             receiver_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
663             break;
664         }
665         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
666         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
667         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32: {
668             key_ = acc_.GetValueIn(gate, 0);
669             receiver_ = acc_.GetValueIn(gate, 1);
670             break;
671         }
672         default:
673             UNREACHABLE();
674     }
675     FetchBuiltinsTypes();
676 }
677 
IsAllString() const678 bool AccBuiltinObjTypeInfoAccessor::IsAllString() const
679 {
680     if (types_.empty()) {
681         return false;
682     }
683     for (auto type : types_) {
684         if (!type.IsBuiltinsString()) {
685             return false;
686         }
687     }
688     return true;
689 }
690 
FetchBuiltinsTypes()691 void AccBuiltinObjTypeInfoAccessor::FetchBuiltinsTypes()
692 {
693     const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
694     for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
695         auto temp = pgoTypes->GetObjectInfo(i);
696         if (temp.GetReceiverType().IsBuiltinsType()) {
697             if (CheckDuplicatedBuiltinType(temp.GetReceiverType())) {
698                 continue;
699             }
700             types_.emplace_back(temp.GetReceiverType());
701         }
702     }
703 }
704 
CheckDuplicatedBuiltinType(ProfileType newType) const705 bool AccBuiltinObjTypeInfoAccessor::CheckDuplicatedBuiltinType(ProfileType newType) const
706 {
707     for (auto &type : types_) {
708         if (type.GetBuiltinsId() == newType.GetBuiltinsId()) {
709             return true;
710         }
711     }
712     return false;
713 }
714 
StoreBulitinObjTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,Chunk * chunk)715 StoreBulitinObjTypeInfoAccessor::StoreBulitinObjTypeInfoAccessor(const JSThread *thread, Circuit *circuit,
716                                                                  GateRef gate, Chunk *chunk)
717     : AccBuiltinObjTypeInfoAccessor(thread, circuit, gate, chunk, AccessMode::STORE)
718 {
719     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
720     switch (ecmaOpcode) {
721         case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
722         case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
723         case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32: {
724             key_ = acc_.GetValueIn(gate, 0); // 0: key
725             receiver_ = acc_.GetValueIn(gate, 1);  // 1: receiver
726             value_ = acc_.GetValueIn(gate, 2); // 2: value
727             break;
728         }
729         case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
730         case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8: {
731             receiver_ = acc_.GetValueIn(gate, 1);  // 1: receiver
732             key_ = acc_.GetValueIn(gate, 2);   // 2: key
733             value_ = acc_.GetValueIn(gate, 3);     // 3: value
734             break;
735         }
736         default:
737             UNREACHABLE();
738     }
739     FetchBuiltinsTypes();
740 }
741 
CreateObjWithBufferTypeInfoAccessor(const JSThread * thread,Circuit * circuit,GateRef gate,const CString & recordName)742 CreateObjWithBufferTypeInfoAccessor::CreateObjWithBufferTypeInfoAccessor(const JSThread *thread, Circuit *circuit,
743                                                                          GateRef gate, const CString &recordName)
744     : TypeInfoAccessor(thread, circuit, gate), recordName_(recordName), objHandle_(thread, JSTaggedValue::Undefined())
745 {
746     ASSERT(acc_.GetNumValueIn(gate) == 2);  // 2: number of value ins
747     index_ = acc_.GetValueIn(gate, 0);
748     Init();
749 }
750 
Init()751 void CreateObjWithBufferTypeInfoAccessor::Init()
752 {
753     auto imm = acc_.GetConstantValue(index_);
754     auto methodOffset = acc_.TryGetMethodOffset(GetGate());
755     JSTaggedValue cp = tsManager_->GetConstantPool(methodOffset);
756     JSTaggedValue obj = ConstantPool::GetLiteralFromCache<ConstPoolType::OBJECT_LITERAL>(
757         tsManager_->GetEcmaVM()->GetJSThread(), cp, imm, recordName_);
758     objHandle_ = JSHandle<JSObject>(thread_, obj);
759 }
760 
GetHClass() const761 JSTaggedValue CreateObjWithBufferTypeInfoAccessor::GetHClass() const
762 {
763     auto sampleType = acc_.TryGetPGOType(gate_).GetPGODefineOpType();
764     auto type = std::make_pair(sampleType->GetProfileType(), sampleType->GetProfileType());
765     int hclassIndex = static_cast<int>(ptManager_->GetHClassIndexByProfileType(type));
766 
767     JSHClass *oldClass = objHandle_->GetClass();
768     if (hclassIndex == -1) {
769         if (objHandle_->ElementsAndPropertiesIsEmpty()) {
770             return JSTaggedValue(oldClass);
771         }
772         return JSTaggedValue::Undefined();
773     }
774     JSHClass *newClass = JSHClass::Cast(ptManager_->QueryHClass(type.first, type.second).GetTaggedObject());
775     if (oldClass->GetInlinedProperties() != newClass->GetInlinedProperties()) {
776         return JSTaggedValue::Undefined();
777     }
778     return JSTaggedValue(newClass);
779 }
780 }  // namespace panda::ecmascript::kungfu
781