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