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/compiler/pgo_type/pgo_type_manager.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/global_env_fields.h"
23 #include "ecmascript/jspandafile/program_object.h"
24
25 namespace panda::ecmascript::kungfu {
PGOSampleTypeToParamType() const26 ParamType TypeInfoAccessor::PGOSampleTypeToParamType() const
27 {
28 if (pgoType_.IsPGOSampleType()) {
29 auto sample = pgoType_.GetPGOSampleType();
30 if (sample->IsInt()) {
31 return ParamType::IntType();
32 } else if (sample->IsIntOverFlow()) {
33 return ParamType::IntOverflowType();
34 } else if (sample->IsDouble()) {
35 return ParamType::DoubleType();
36 } else if (sample->IsString()) {
37 return ParamType::StringType();
38 } else if (sample->IsBigInt()) {
39 return ParamType::BigIntType();
40 } else if (sample->IsBoolean()) {
41 return ParamType::BooleanType();
42 } else if (sample->IsNumber()) {
43 return ParamType::NumberType();
44 } else if (sample->IsNumberOrString()) {
45 return ParamType::StringType();
46 }
47 }
48 return ParamType::AnyType();
49 }
50
PGOBuiltinTypeToParamType(ProfileType pgoType)51 ParamType TypeInfoAccessor::PGOBuiltinTypeToParamType(ProfileType pgoType)
52 {
53 if (pgoType.IsBuiltinsType()) {
54 return ParamType(pgoType.GetBuiltinsType());
55 }
56 return ParamType::AnyType();
57 }
58
59 // TypeTrusted means the type of gate is already PrimitiveTypeCheck-passed,
60 // or the gate is constant and no need to check.
IsTrustedBooleanType(GateAccessor acc,GateRef gate)61 bool TypeInfoAccessor::IsTrustedBooleanType(GateAccessor acc, GateRef gate)
62 {
63 if (acc.IsConstant(gate) && acc.GetGateType(gate).IsBooleanType()) {
64 return true;
65 }
66 auto op = acc.GetOpCode(gate);
67 if (op == OpCode::TYPED_BINARY_OP) {
68 TypedBinaryAccessor accessor(acc.TryGetValue(gate));
69 TypedBinOp binOp = accessor.GetTypedBinOp();
70 switch (binOp) {
71 case TypedBinOp::TYPED_EQ:
72 case TypedBinOp::TYPED_LESS:
73 case TypedBinOp::TYPED_NOTEQ:
74 case TypedBinOp::TYPED_LESSEQ:
75 case TypedBinOp::TYPED_GREATER:
76 case TypedBinOp::TYPED_STRICTEQ:
77 case TypedBinOp::TYPED_GREATEREQ:
78 case TypedBinOp::TYPED_STRICTNOTEQ:
79 return true;
80 default:
81 return false;
82 }
83 } else if (op == OpCode::TYPED_UNARY_OP) {
84 TypedUnaryAccessor accessor(acc.TryGetValue(gate));
85 TypedUnOp unOp = accessor.GetTypedUnOp();
86 switch (unOp) {
87 case TypedUnOp::TYPED_ISTRUE:
88 case TypedUnOp::TYPED_ISFALSE:
89 return true;
90 default:
91 return false;
92 }
93 }
94 if (op == OpCode::JS_BYTECODE) {
95 EcmaOpcode ecmaOpcode = acc.GetByteCodeOpcode(gate);
96 switch (ecmaOpcode) {
97 case EcmaOpcode::LESS_IMM8_V8:
98 case EcmaOpcode::LESSEQ_IMM8_V8:
99 case EcmaOpcode::GREATER_IMM8_V8:
100 case EcmaOpcode::GREATEREQ_IMM8_V8:
101 case EcmaOpcode::EQ_IMM8_V8:
102 case EcmaOpcode::NOTEQ_IMM8_V8:
103 case EcmaOpcode::STRICTEQ_IMM8_V8:
104 case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
105 case EcmaOpcode::ISTRUE:
106 case EcmaOpcode::ISFALSE:
107 return true;
108 default:
109 break;
110 }
111 }
112 return false;
113 }
114
IsTrustedNumberType(GateAccessor acc,GateRef gate)115 bool TypeInfoAccessor::IsTrustedNumberType(GateAccessor acc, GateRef gate)
116 {
117 if (acc.IsConstant(gate) && acc.GetGateType(gate).IsNumberType()) {
118 return true;
119 }
120 auto op = acc.GetOpCode(gate);
121 if (op == OpCode::TYPED_BINARY_OP) {
122 TypedBinaryAccessor accessor(acc.TryGetValue(gate));
123 TypedBinOp binOp = accessor.GetTypedBinOp();
124 switch (binOp) {
125 case TypedBinOp::TYPED_ADD:
126 case TypedBinOp::TYPED_SUB:
127 case TypedBinOp::TYPED_MUL:
128 case TypedBinOp::TYPED_DIV:
129 case TypedBinOp::TYPED_MOD:
130 case TypedBinOp::TYPED_SHL:
131 case TypedBinOp::TYPED_SHR:
132 case TypedBinOp::TYPED_ASHR:
133 case TypedBinOp::TYPED_AND:
134 case TypedBinOp::TYPED_OR:
135 case TypedBinOp::TYPED_XOR:
136 return accessor.GetParamType().HasNumberType();
137 default:
138 return false;
139 }
140 } else if (op == OpCode::TYPED_UNARY_OP) {
141 TypedUnaryAccessor accessor(acc.TryGetValue(gate));
142 TypedUnOp unOp = accessor.GetTypedUnOp();
143 switch (unOp) {
144 case TypedUnOp::TYPED_DEC:
145 case TypedUnOp::TYPED_INC:
146 case TypedUnOp::TYPED_NEG:
147 case TypedUnOp::TYPED_NOT:
148 return accessor.GetParamType().HasNumberType();
149 default:
150 return false;
151 }
152 } else if (op == OpCode::TYPE_CONVERT) {
153 // typeconvert only use in tomumeric
154 return true;
155 } else if (op == OpCode::LOAD_ELEMENT) {
156 auto loadOp = acc.GetTypedLoadOp(gate);
157 switch (loadOp) {
158 case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT:
159 case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT:
160 case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT:
161 case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT:
162 case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT:
163 case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT:
164 case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT:
165 case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT:
166 case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT:
167 return true;
168 default:
169 return false;
170 }
171 }
172
173 if (op == OpCode::JS_BYTECODE) {
174 EcmaOpcode ecmaOpcode = acc.GetByteCodeOpcode(gate);
175 switch (ecmaOpcode) {
176 case EcmaOpcode::ADD2_IMM8_V8:
177 case EcmaOpcode::SUB2_IMM8_V8:
178 case EcmaOpcode::MUL2_IMM8_V8:
179 case EcmaOpcode::DIV2_IMM8_V8:
180 case EcmaOpcode::MOD2_IMM8_V8:
181 case EcmaOpcode::SHL2_IMM8_V8:
182 case EcmaOpcode::SHR2_IMM8_V8:
183 case EcmaOpcode::ASHR2_IMM8_V8:
184 case EcmaOpcode::AND2_IMM8_V8:
185 case EcmaOpcode::OR2_IMM8_V8:
186 case EcmaOpcode::XOR2_IMM8_V8:
187 case EcmaOpcode::INC_IMM8:
188 case EcmaOpcode::DEC_IMM8:
189 case EcmaOpcode::NEG_IMM8:
190 case EcmaOpcode::NOT_IMM8:
191 return acc.TryGetPGOType(gate).GetPGOSampleType()->HasNumber();
192 default:
193 break;
194 }
195 }
196 return false;
197 }
198
IsTrustedStringType(const CompilationEnv * env,Circuit * circuit,Chunk * chunk,GateAccessor acc,GateRef gate)199 bool TypeInfoAccessor::IsTrustedStringType(
200 const CompilationEnv *env, Circuit *circuit, Chunk *chunk, GateAccessor acc, GateRef gate)
201 {
202 auto op = acc.GetOpCode(gate);
203 if (op == OpCode::LOAD_ELEMENT) {
204 return acc.GetTypedLoadOp(gate) == TypedLoadOp::STRING_LOAD_ELEMENT;
205 }
206 if (op == OpCode::NUMBER_TO_STRING) {
207 return true;
208 }
209 if (op == OpCode::TYPED_BINARY_OP) {
210 auto binaryOp = acc.GetTypedBinaryOp(gate);
211 if (binaryOp == TypedBinOp::TYPED_ADD) {
212 auto value = acc.GetTypedBinaryAccessor(gate);
213 return value.GetParamType().IsStringType();
214 }
215 }
216
217 if (op == OpCode::JS_BYTECODE) {
218 EcmaOpcode ecmaOpcode = acc.GetByteCodeOpcode(gate);
219 switch (ecmaOpcode) {
220 case EcmaOpcode::LDA_STR_ID16:
221 return true;
222 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
223 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8: {
224 LoadBulitinObjTypeInfoAccessor tacc(env, circuit, gate, chunk);
225 if (tacc.IsMono()) {
226 return tacc.IsBuiltinsString();
227 }
228 break;
229 }
230 default:
231 break;
232 }
233 }
234 return false;
235 }
236
IsTrustedNotSameType(const CompilationEnv * env,Circuit * circuit,Chunk * chunk,GateAccessor acc,GateRef left,GateRef right)237 bool TypeInfoAccessor::IsTrustedNotSameType(const CompilationEnv *env, Circuit *circuit, Chunk *chunk,
238 GateAccessor acc, GateRef left, GateRef right)
239 {
240 bool leftIsBoolean = IsTrustedBooleanType(acc, left);
241 bool rightIsBoolean = IsTrustedBooleanType(acc, right);
242 bool leftIsNumber = IsTrustedNumberType(acc, left);
243 bool rightIsNumber = IsTrustedNumberType(acc, right);
244 bool leftIsString = IsTrustedStringType(env, circuit, chunk, acc, left);
245 bool rightIsString = IsTrustedStringType(env, circuit, chunk, acc, right);
246 if (leftIsBoolean) {
247 return rightIsNumber || rightIsString;
248 }
249
250 if (leftIsNumber) {
251 return rightIsBoolean || rightIsString;
252 }
253
254 if (leftIsString) {
255 return rightIsBoolean || rightIsNumber;
256 }
257
258 return false;
259 }
260
TryGetPGOBuiltinMethodId() const261 BuiltinsStubCSigns::ID TypeInfoAccessor::TryGetPGOBuiltinMethodId() const
262 {
263 PGOTypeRef sampleType = acc_.TryGetPGOType(gate_);
264 if (sampleType.GetPGOSampleType()->IsNone()) {
265 return BuiltinsStubCSigns::ID::NONE;
266 }
267 if (sampleType.GetPGOSampleType()->GetProfileType().IsBuiltinFunctionId()) {
268 return static_cast<BuiltinsStubCSigns::ID>(sampleType.GetPGOSampleType()->GetProfileType().GetId());
269 }
270 return BuiltinsStubCSigns::ID::NONE;
271 }
272
FindHClass() const273 bool NewObjRangeTypeInfoAccessor::AotAccessorStrategy::FindHClass() const
274 {
275 auto sampleType = parent_.pgoType_.GetPGOSampleType();
276 if (!sampleType->IsProfileType()) {
277 return false;
278 }
279 ProfileType profileType = sampleType->GetProfileType();
280 auto type = std::make_pair(profileType, profileType);
281 parent_.hclassIndex_ = static_cast<int>(parent_.ptManager_->GetHClassIndexByProfileType(type));
282 if (parent_.hclassIndex_ == -1) {
283 return false;
284 }
285 profileType.UpdateKind(pgo::ProfileType::Kind::TransitionClassId);
286 auto transType = std::make_pair(profileType, profileType);
287 parent_.traHClassIndex_ = static_cast<int>(parent_.ptManager_->GetHClassIndexByProfileType(transType));
288 if (parent_.traHClassIndex_ == -1) {
289 return parent_.ptManager_->QueryHClass(type.first, type.second).IsJSHClass();
290 }
291 return parent_.ptManager_->QueryHClass(transType.first, transType.second).IsJSHClass();
292 }
293
FindHClass() const294 bool NewObjRangeTypeInfoAccessor::JitAccessorStrategy::FindHClass() const
295 {
296 // For JIT, it handles Builtin using SampleType. For handling others, it uses DefType.
297 // Therefore, when it's SampleType, it can directly return.
298 if (parent_.pgoType_.IsPGOSampleType()) {
299 return false;
300 }
301 auto sampleType = parent_.pgoType_.GetPGODefineOpType();
302 if (sampleType->IsNone()) {
303 return false;
304 }
305 JSHClass *hclass = sampleType->GetReceiver();
306 bool result = hclass != nullptr;
307 if (result) {
308 parent_.hclassIndex_ = parent_.ptManager_->RecordAndGetHclassIndexForJIT(hclass);
309 }
310 return result;
311 }
312
GetHClass() const313 JSTaggedValue NewObjRangeTypeInfoAccessor::AotAccessorStrategy::GetHClass() const
314 {
315 auto sampleType = parent_.pgoType_.GetPGOSampleType();
316 ASSERT(sampleType->IsProfileType());
317 ProfileType profileType = sampleType->GetProfileType();
318 auto type = std::make_pair(profileType, profileType);
319 parent_.hclassIndex_ = static_cast<int>(parent_.ptManager_->GetHClassIndexByProfileType(type));
320 ASSERT(parent_.hclassIndex_ != -1);
321 profileType.UpdateKind(pgo::ProfileType::Kind::TransitionClassId);
322 auto transType = std::make_pair(profileType, profileType);
323 parent_.traHClassIndex_ = static_cast<int>(parent_.ptManager_->GetHClassIndexByProfileType(transType));
324 if (parent_.traHClassIndex_ == -1) {
325 return parent_.ptManager_->QueryHClass(type.first, type.second);
326 }
327 return parent_.ptManager_->QueryHClass(transType.first, transType.second);
328 }
329
GetHClass() const330 JSTaggedValue NewObjRangeTypeInfoAccessor::JitAccessorStrategy::GetHClass() const
331 {
332 auto sampleType = parent_.pgoType_.GetPGODefineOpType();
333 ASSERT(!sampleType->IsNone());
334 JSHClass *hclass = sampleType->GetReceiver();
335 parent_.hclassIndex_ = parent_.ptManager_->RecordAndGetHclassIndexForJIT(hclass);
336 return JSTaggedValue(sampleType->GetReceiver());
337 }
338
IsIllegalType() const339 bool TypeOfTypeInfoAccessor::IsIllegalType() const
340 {
341 return true;
342 }
343
SuperCallTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)344 SuperCallTypeInfoAccessor::SuperCallTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
345 const JSPandaFile *jsPandaFile,
346 const CallMethodFlagMap *callMethodFlagMap)
347 : TypeInfoAccessor(env, circuit, gate), jsPandaFile_(jsPandaFile), callMethodFlagMap_(callMethodFlagMap)
348 {
349 ctor_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
350 }
351
GetIteratorTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)352 GetIteratorTypeInfoAccessor::GetIteratorTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
353 const JSPandaFile *jsPandaFile,
354 const CallMethodFlagMap *callMethodFlagMap)
355 : CallTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
356 {
357 argc_ = 0; // 0: number of argc
358 func_ = acc_.GetValueIn(gate, 0); // 1: func
359 }
360
CallArg0TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)361 CallArg0TypeInfoAccessor::CallArg0TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
362 const JSPandaFile *jsPandaFile,
363 const CallMethodFlagMap *callMethodFlagMap)
364 : CallTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
365 {
366 argc_ = 0; // 0: number of argc
367 func_ = acc_.GetValueIn(gate, 0); // 0: func
368 }
369
CallArg1TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)370 CallArg1TypeInfoAccessor::CallArg1TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
371 const JSPandaFile *jsPandaFile,
372 const CallMethodFlagMap *callMethodFlagMap)
373 : CallTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
374 {
375 argc_ = 1; // 1: number of argc
376 value_ = acc_.GetValueIn(gate, 0); // 0: value
377 func_ = acc_.GetValueIn(gate, 1); // 1: func
378 }
379
CallArg2TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)380 CallArg2TypeInfoAccessor::CallArg2TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
381 const JSPandaFile *jsPandaFile,
382 const CallMethodFlagMap *callMethodFlagMap)
383 : CallTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
384 {
385 argc_ = 2; // 2: number of argc
386 func_ = acc_.GetValueIn(gate, 2); // 2: func
387 }
388
CallArg3TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)389 CallArg3TypeInfoAccessor::CallArg3TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
390 const JSPandaFile *jsPandaFile,
391 const CallMethodFlagMap *callMethodFlagMap)
392 : CallTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
393 {
394 argc_ = 3; // 3: number of argc
395 func_ = acc_.GetValueIn(gate, 3); // 3: func
396 }
397
CallRangeTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)398 CallRangeTypeInfoAccessor::CallRangeTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
399 const JSPandaFile *jsPandaFile,
400 const CallMethodFlagMap *callMethodFlagMap)
401 : CallTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
402 {
403 size_t numArgs = acc_.GetNumValueIn(gate);
404 constexpr size_t callTargetIndex = 1; // acc
405 ASSERT(numArgs > 0);
406 argc_ = numArgs - callTargetIndex;
407 func_ = acc_.GetValueIn(gate, argc_);
408 }
409
CanOptimizeAsFastCall()410 bool CallThisTypeInfoAccessor::CanOptimizeAsFastCall()
411 {
412 auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType();
413 auto op = acc_.GetOpCode(func_);
414 if (!IsValidCallMethodId()) {
415 return false;
416 }
417 if (!profileType->IsNone()) {
418 if (profileType->IsProfileTypeNone() ||
419 (op != OpCode::LOAD_PROPERTY && op != OpCode::MONO_LOAD_PROPERTY_ON_PROTO)) {
420 return false;
421 }
422 return true;
423 }
424 return false;
425 }
426
CallThis0TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)427 CallThis0TypeInfoAccessor::CallThis0TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
428 const JSPandaFile *jsPandaFile,
429 const CallMethodFlagMap *callMethodFlagMap)
430 : CallThisTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
431 {
432 argc_ = 0; // 0: number of argc
433 func_ = acc_.GetValueIn(gate, 1); // 1: func
434 }
435
CallThis1TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)436 CallThis1TypeInfoAccessor::CallThis1TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
437 const JSPandaFile *jsPandaFile,
438 const CallMethodFlagMap *callMethodFlagMap)
439 : CallThisTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
440 {
441 argc_ = 1; // 1: number of argc
442 func_ = acc_.GetValueIn(gate, 2); // 2: func
443 a0_ = acc_.GetValueIn(gate, 1); // 1: arg0
444 }
445
CallThis2TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)446 CallThis2TypeInfoAccessor::CallThis2TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
447 const JSPandaFile *jsPandaFile,
448 const CallMethodFlagMap *callMethodFlagMap)
449 : CallThisTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
450 {
451 argc_ = 2; // 2: number of argc
452 func_ = acc_.GetValueIn(gate, 3); // 3: func
453 }
454
CallThis3TypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)455 CallThis3TypeInfoAccessor::CallThis3TypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
456 const JSPandaFile *jsPandaFile,
457 const CallMethodFlagMap *callMethodFlagMap)
458 : CallThisTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
459 {
460 argc_ = 3; // 3: number of argc
461 func_ = acc_.GetValueIn(gate, 4); // 4: func
462 a0_ = acc_.GetValueIn(gate, 1); // 1: arg0
463 a1_ = acc_.GetValueIn(gate, 2); // 2: arg1
464 a2_ = acc_.GetValueIn(gate, 3); // 3: arg2
465 }
466
CallThisRangeTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const JSPandaFile * jsPandaFile,const CallMethodFlagMap * callMethodFlagMap)467 CallThisRangeTypeInfoAccessor::CallThisRangeTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
468 const JSPandaFile *jsPandaFile,
469 const CallMethodFlagMap *callMethodFlagMap)
470 : CallThisTypeInfoAccessor(env, circuit, gate, jsPandaFile, callMethodFlagMap)
471 {
472 constexpr size_t fixedInputsNum = 1;
473 constexpr size_t callTargetIndex = 1; // 1: acc
474 size_t numIns = acc_.GetNumValueIn(gate);
475 ASSERT(numIns >= fixedInputsNum + callTargetIndex);
476 argc_ = numIns - callTargetIndex - fixedInputsNum;
477 func_ = acc_.GetValueIn(gate, numIns - callTargetIndex); // acc
478 }
479
InlineTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,GateRef receiver,CallKind kind)480 InlineTypeInfoAccessor::InlineTypeInfoAccessor(
481 const CompilationEnv *env, Circuit *circuit, GateRef gate, GateRef receiver, CallKind kind)
482 : TypeInfoAccessor(env, circuit, gate), receiver_(receiver), kind_(kind)
483 {
484 if (IsCallAccessor()) {
485 if (IsAot()) {
486 plr_ = GetAccessorPlr();
487 } else {
488 plr_ = GetAccessorPlrInJIT();
489 }
490 }
491 }
InitPropAndCheck(JSTaggedValue & prop) const492 bool InlineTypeInfoAccessor::InitPropAndCheck(JSTaggedValue& prop) const
493 {
494 GateRef constData = acc_.GetValueIn(gate_, 1);
495 uint16_t propIndex = acc_.GetConstantValue(constData);
496 auto methodOffset = acc_.TryGetMethodOffset(gate_);
497 prop = compilationEnv_->GetStringFromConstantPool(methodOffset, propIndex);
498 if (prop.IsUndefined()) {
499 return false;
500 }
501 // PGO currently does not support call, so GT is still used to support inline operations.
502 // However, the original GT solution cannot support accessing the property of prototype, so it is filtered here
503 if (EcmaStringAccessor(prop).ToStdString() == "prototype") {
504 return false;
505 }
506 return true;
507 }
508
GetAccessorPlr() const509 PropertyLookupResult InlineTypeInfoAccessor::GetAccessorPlr() const
510 {
511 JSTaggedValue prop = JSTaggedValue::Undefined();
512 if (!InitPropAndCheck(prop)) {
513 return PropertyLookupResult();
514 }
515
516 const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
517 if (pgoTypes->GetCount() != 1) {
518 return PropertyLookupResult();
519 }
520 auto pgoType = pgoTypes->GetObjectInfo(0);
521 ProfileTyper holderType = std::make_pair(pgoType.GetHoldRootType(), pgoType.GetHoldType());
522
523 PGOTypeManager *ptManager = compilationEnv_->GetPTManager();
524
525 int hclassIndex = static_cast<int>(ptManager->GetHClassIndexByProfileType(holderType));
526 if (hclassIndex == -1) {
527 return PropertyLookupResult();
528 }
529 JSTaggedValue hclass = ptManager->QueryHClass(holderType.first, holderType.second);
530 if (!hclass.IsJSHClass()) {
531 return PropertyLookupResult();
532 }
533
534 PropertyLookupResult plr = JSHClass::LookupPropertyInPGOHClass(compilationEnv_->GetJSThread(),
535 JSHClass::Cast(hclass.GetTaggedObject()), prop);
536 return plr;
537 }
538
539
GetAccessorPlrInJIT() const540 PropertyLookupResult InlineTypeInfoAccessor::GetAccessorPlrInJIT() const
541 {
542 JSTaggedValue prop = JSTaggedValue::Undefined();
543 if (!InitPropAndCheck(prop)) {
544 return PropertyLookupResult();
545 }
546
547 const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
548 if (pgoTypes->GetCount() != 1) {
549 return PropertyLookupResult();
550 }
551 if (!pgoTypes->GetObjectInfo(0).IsJITClassType()) {
552 return PropertyLookupResult();
553 }
554 auto pgoType = pgoTypes->GetObjectInfo(0);
555 JSHClass* receiverType = pgoType.GetReceiverHclass();
556 JSHClass* holderType = pgoType.GetHolderHclass();
557 JSHClass *hclass = nullptr;
558 if (receiverType == holderType) {
559 hclass = receiverType;
560 } else {
561 hclass = holderType;
562 }
563
564 PropertyLookupResult plr = JSHClass::LookupPropertyInPGOHClass(compilationEnv_->GetJSThread(), hclass, prop);
565 return plr;
566 }
567
GetCallMethodId() const568 uint32_t InlineTypeInfoAccessor::GetCallMethodId() const
569 {
570 uint32_t methodOffset = 0;
571 if (IsNormalCall() && IsValidCallMethodId()) {
572 methodOffset = GetFuncMethodOffsetFromPGO();
573 }
574 if (IsCallAccessor()) {
575 const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
576 auto pgoType = pgoTypes->GetObjectInfo(0);
577 if (pgoType.GetAccessorMethod().GetProfileType().IsValidCallMethodId()) {
578 return pgoType.GetAccessorMethod().GetProfileType().GetCallMethodId();
579 }
580 }
581 return methodOffset;
582 }
583
GetKeyTaggedValue() const584 JSTaggedValue ObjectAccessTypeInfoAccessor::GetKeyTaggedValue() const
585 {
586 uint16_t index = acc_.GetConstantValue(key_);
587 auto methodOffset = acc_.TryGetMethodOffset(GetGate());
588 return compilationEnv_->GetStringFromConstantPool(methodOffset, index);
589 }
590
GeneratePlr(ProfileTyper type,ObjectAccessInfo & info,JSTaggedValue key) const591 bool ObjAccByNameTypeInfoAccessor::GeneratePlr(ProfileTyper type, ObjectAccessInfo &info, JSTaggedValue key) const
592 {
593 int hclassIndex = static_cast<int>(ptManager_->GetHClassIndexByProfileType(type));
594 if (hclassIndex == -1) {
595 return false;
596 }
597 JSTaggedValue hclass = ptManager_->QueryHClass(type.first, type.second);
598 if (!hclass.IsJSHClass()) {
599 return false;
600 }
601 PropertyLookupResult plr = JSHClass::LookupPropertyInPGOHClass(compilationEnv_->GetJSThread(),
602 JSHClass::Cast(hclass.GetTaggedObject()), key);
603 info.Set(hclassIndex, plr);
604
605 if (mode_ == AccessMode::LOAD) {
606 return plr.IsFound();
607 }
608
609 return (plr.IsFound() && !plr.IsFunction());
610 }
611
GeneratePlrInJIT(JSHClass * hclass,ObjectAccessInfo & info,JSTaggedValue key) const612 bool ObjAccByNameTypeInfoAccessor::GeneratePlrInJIT(JSHClass* hclass, ObjectAccessInfo &info, JSTaggedValue key) const
613 {
614 PropertyLookupResult plr = JSHClass::LookupPropertyInPGOHClass(compilationEnv_->GetJSThread(), hclass, key);
615 int hclassIndex = ptManager_->RecordAndGetHclassIndexForJIT(hclass);
616 info.Set(hclassIndex, plr);
617
618 if (mode_ == AccessMode::LOAD) {
619 return plr.IsFound();
620 }
621
622 return (plr.IsFound() && !plr.IsFunction());
623 }
624
FetchPGORWTypesDual()625 void StorePrivatePropertyTypeInfoAccessor::AotAccessorStrategy::FetchPGORWTypesDual()
626 {
627 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
628 if (IsMegaType(pgoTypes)) {
629 return;
630 }
631 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
632 auto temp = pgoTypes->GetObjectInfo(i);
633 parent_.types_.emplace_back(std::make_tuple(std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
634 std::make_pair(temp.GetHoldRootType(), temp.GetHoldType()),
635 std::make_pair(temp.GetHoldTraRootType(), temp.GetHoldTraType())));
636 }
637 }
638
FetchPGORWTypesDual()639 void StorePrivatePropertyTypeInfoAccessor::JitAccessorStrategy::FetchPGORWTypesDual()
640 {
641 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
642 if (IsMegaType(pgoTypes)) {
643 return;
644 }
645 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
646 auto temp = pgoTypes->GetObjectInfo(i);
647 if (temp.GetReceiverType().IsJITClassType()) {
648 parent_.jitTypes_.emplace_back(temp);
649 }
650 }
651 }
652
GetKeyTaggedValue() const653 JSTaggedValue StorePrivatePropertyTypeInfoAccessor::GetKeyTaggedValue() const
654 {
655 if (types_.empty()) {
656 return JSTaggedValue::Hole();
657 }
658
659 ProfileTyper receiverType = std::get<0>(types_.at(0));
660 auto slotIndex = acc_.GetConstantValue(slotIndex_);
661 ProfileTypeTuple type = std::make_tuple(receiverType.first, receiverType.second, slotIndex);
662 auto privateId = ptManager_->GetSymbolIdByProfileType(type);
663 if (!privateId) {
664 return JSTaggedValue::Hole();
665 }
666
667 AOTSnapshot& snapshot = ptManager_->GetAOTSnapshot();
668 auto symbolInfo = snapshot.GetSymbolInfo();
669 auto symbol = ConstantPool::GetSymbolFromSymbolInfo(symbolInfo, *privateId);
670 return symbol;
671 }
672
GenerateObjectAccessInfo()673 bool StorePrivatePropertyTypeInfoAccessor::AotAccessorStrategy::GenerateObjectAccessInfo()
674 {
675 JSTaggedValue key = parent_.GetKeyTaggedValue();
676 if (key.IsHole()) {
677 parent_.isAccessor_ = true;
678 return true;
679 }
680
681 ProfileTyper receiverType = std::get<0>(parent_.types_.at(0));
682 ProfileTyper holderType = std::get<1>(parent_.types_.at(0));
683 if (receiverType == holderType) {
684 ObjectAccessInfo receiverInfo;
685 if (!parent_.GeneratePlr(receiverType, receiverInfo, key)) {
686 return false;
687 }
688 parent_.accessInfos_.emplace_back(receiverInfo);
689 parent_.checkerInfos_.emplace_back(receiverInfo);
690 } else {
691 UNREACHABLE();
692 }
693
694 return true;
695 }
696
GenerateObjectAccessInfo()697 bool StorePrivatePropertyTypeInfoAccessor::JitAccessorStrategy::GenerateObjectAccessInfo()
698 {
699 JSTaggedValue key = parent_.GetKeyTaggedValue();
700 if (key.IsHole()) {
701 parent_.isAccessor_ = true;
702 return true;
703 }
704
705 JSHClass *receiverType = parent_.jitTypes_[0].GetReceiverHclass();
706 JSHClass *holderType = parent_.jitTypes_[0].GetHolderHclass();
707 if (receiverType->IsJsPrimitiveRef() || holderType->IsJsPrimitiveRef()) {
708 return false;
709 }
710
711 if (receiverType == holderType) {
712 ObjectAccessInfo receiverInfo;
713 if (!parent_.GeneratePlrInJIT(receiverType, receiverInfo, key)) {
714 return false;
715 }
716 parent_.accessInfos_.emplace_back(receiverInfo);
717 parent_.checkerInfos_.emplace_back(receiverInfo);
718 } else {
719 UNREACHABLE();
720 }
721
722 return true;
723 }
724
FetchPGORWTypesDual()725 void LoadPrivatePropertyTypeInfoAccessor::AotAccessorStrategy::FetchPGORWTypesDual()
726 {
727 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
728 if (IsMegaType(pgoTypes)) {
729 return;
730 }
731 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
732 auto temp = pgoTypes->GetObjectInfo(i);
733 parent_.types_.emplace_back(std::make_pair(std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
734 std::make_pair(temp.GetHoldRootType(), temp.GetHoldType())));
735 }
736 }
737
FetchPGORWTypesDual()738 void LoadPrivatePropertyTypeInfoAccessor::JitAccessorStrategy::FetchPGORWTypesDual()
739 {
740 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
741 if (IsMegaType(pgoTypes)) {
742 return;
743 }
744 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
745 auto temp = pgoTypes->GetObjectInfo(i);
746 if (temp.GetReceiverType().IsJITClassType()) {
747 parent_.jitTypes_.emplace_back(temp);
748 }
749 }
750 }
751
752
GetKeyTaggedValue() const753 JSTaggedValue LoadPrivatePropertyTypeInfoAccessor::GetKeyTaggedValue() const
754 {
755 if (types_.empty()) {
756 return JSTaggedValue::Hole();
757 }
758
759 ProfileTyper receiverType = types_.at(0).first;
760 auto slotIndex = acc_.GetConstantValue(slotIndex_);
761 ProfileTypeTuple type = std::make_tuple(receiverType.first, receiverType.second, slotIndex);
762 auto privateId = ptManager_->GetSymbolIdByProfileType(type);
763 if (!privateId) {
764 return JSTaggedValue::Hole();
765 }
766
767 AOTSnapshot& snapshot = ptManager_->GetAOTSnapshot();
768 auto symbolInfo = snapshot.GetSymbolInfo();
769 auto symbol = ConstantPool::GetSymbolFromSymbolInfo(symbolInfo, *privateId);
770 return symbol;
771 }
772
GenerateObjectAccessInfo()773 bool LoadPrivatePropertyTypeInfoAccessor::AotAccessorStrategy::GenerateObjectAccessInfo()
774 {
775 JSTaggedValue key = parent_.GetKeyTaggedValue();
776 if (key.IsHole()) {
777 parent_.isAccessor_ = true;
778 return true;
779 }
780
781 ProfileTyper receiverType = parent_.types_.at(0).first;
782 ProfileTyper holderType = parent_.types_.at(0).second;
783 if (receiverType == holderType) {
784 ObjectAccessInfo receiverInfo;
785 if (!parent_.GeneratePlr(receiverType, receiverInfo, key)) {
786 return false;
787 }
788 parent_.accessInfos_.emplace_back(receiverInfo);
789 parent_.checkerInfos_.emplace_back(receiverInfo);
790 } else {
791 UNREACHABLE();
792 }
793
794 return true;
795 }
796
GenerateObjectAccessInfo()797 bool LoadPrivatePropertyTypeInfoAccessor::JitAccessorStrategy::GenerateObjectAccessInfo()
798 {
799 JSTaggedValue key = parent_.GetKeyTaggedValue();
800 if (key.IsHole()) {
801 parent_.isAccessor_ = true;
802 return true;
803 }
804
805 JSHClass *receiver = parent_.jitTypes_[0].GetReceiverHclass();
806 JSHClass *holder = parent_.jitTypes_[0].GetHolderHclass();
807 // case: r.toFixed() => HeapObjectCheck Deopt
808 if (receiver->IsJsPrimitiveRef() || holder->IsJsPrimitiveRef()) {
809 return false;
810 }
811
812 if (receiver == holder) {
813 ObjectAccessInfo receiverInfo;
814 if (!parent_.GeneratePlrInJIT(receiver, receiverInfo, key)) {
815 return false;
816 }
817 parent_.accessInfos_.emplace_back(receiverInfo);
818 parent_.checkerInfos_.emplace_back(receiverInfo);
819 } else {
820 UNREACHABLE();
821 }
822
823 return true;
824 }
825
LoadObjByNameTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,Chunk * chunk)826 LoadObjByNameTypeInfoAccessor::LoadObjByNameTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
827 Chunk *chunk)
828 : ObjAccByNameTypeInfoAccessor(env, circuit, gate, chunk, AccessMode::LOAD), types_(chunk_), jitTypes_(chunk_)
829 {
830 key_ = acc_.GetValueIn(gate, 1); // 1: key
831 receiver_ = acc_.GetValueIn(gate, 2); // 2: receiver
832 if (IsAot()) {
833 strategy_ = chunk_->New<AotAccessorStrategy>(*this);
834 } else {
835 strategy_ = chunk_->New<JitAccessorStrategy>(*this);
836 }
837 strategy_->FetchPGORWTypesDual();
838 hasIllegalType_ = !strategy_->GenerateObjectAccessInfo();
839 }
840
FetchPGORWTypesDual()841 void LoadObjByNameTypeInfoAccessor::AotAccessorStrategy::FetchPGORWTypesDual()
842 {
843 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
844 if (IsMegaType(pgoTypes)) {
845 return;
846 }
847 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
848 auto temp = pgoTypes->GetObjectInfo(i);
849 if (temp.GetReceiverType().IsBuiltinsType()) {
850 continue;
851 }
852 parent_.types_.emplace_back(std::make_pair(std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
853 std::make_pair(temp.GetHoldRootType(), temp.GetHoldType())));
854 }
855 }
856
FetchPGORWTypesDual()857 void LoadObjByNameTypeInfoAccessor::JitAccessorStrategy::FetchPGORWTypesDual()
858 {
859 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
860 if (IsMegaType(pgoTypes)) {
861 return;
862 }
863 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
864 auto temp = pgoTypes->GetObjectInfo(i);
865 if (temp.GetReceiverType().IsJITClassType()) {
866 parent_.jitTypes_.emplace_back(temp);
867 }
868 }
869 }
870
GenerateObjectAccessInfo()871 bool LoadObjByNameTypeInfoAccessor::AotAccessorStrategy::GenerateObjectAccessInfo()
872 {
873 JSTaggedValue key = parent_.GetKeyTaggedValue();
874 if (key.IsUndefined()) {
875 return false;
876 }
877 for (size_t i = 0; i < parent_.types_.size(); ++i) {
878 ProfileTyper receiverType = parent_.types_[i].first;
879 ProfileTyper holderType = parent_.types_[i].second;
880 if (receiverType == holderType) {
881 ObjectAccessInfo info;
882 if (!parent_.GeneratePlr(receiverType, info, key)) {
883 return false;
884 }
885 parent_.accessInfos_.emplace_back(info);
886 parent_.checkerInfos_.emplace_back(info);
887 } else {
888 ObjectAccessInfo accInfo;
889 if (!parent_.GeneratePlr(holderType, accInfo, key)) {
890 return false;
891 }
892 parent_.accessInfos_.emplace_back(accInfo);
893 ObjectAccessInfo checkInfo;
894 parent_.GeneratePlr(receiverType, checkInfo, key);
895 if (checkInfo.HClassIndex() == -1) {
896 return false;
897 }
898 parent_.checkerInfos_.emplace_back(checkInfo);
899 }
900 }
901 return true;
902 }
903
GenerateObjectAccessInfo()904 bool LoadObjByNameTypeInfoAccessor::JitAccessorStrategy::GenerateObjectAccessInfo()
905 {
906 JSTaggedValue key = parent_.GetKeyTaggedValue();
907 if (key.IsUndefined()) {
908 return false;
909 }
910 for (size_t i = 0; i < parent_.jitTypes_.size(); ++i) {
911 JSHClass *receiver = parent_.jitTypes_[i].GetReceiverHclass();
912 JSHClass *holder = parent_.jitTypes_[i].GetHolderHclass();
913 // case: r.toFixed() => HeapObjectCheck Deopt
914 if (receiver->IsJsPrimitiveRef() || holder->IsJsPrimitiveRef()) {
915 return false;
916 }
917 if (receiver == holder) {
918 ObjectAccessInfo info;
919 if (!parent_.GeneratePlrInJIT(receiver, info, key)) {
920 return false;
921 }
922 parent_.accessInfos_.emplace_back(info);
923 parent_.checkerInfos_.emplace_back(info);
924 } else {
925 ObjectAccessInfo accInfo;
926 if (!parent_.GeneratePlrInJIT(holder, accInfo, key)) {
927 return false;
928 }
929 parent_.accessInfos_.emplace_back(accInfo);
930 ObjectAccessInfo checkInfo;
931 parent_.GeneratePlrInJIT(receiver, checkInfo, key);
932 if (checkInfo.HClassIndex() == -1) {
933 return false;
934 }
935 parent_.checkerInfos_.emplace_back(checkInfo);
936 }
937 }
938 return true;
939 }
940
StoreObjByNameTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,Chunk * chunk)941 StoreObjByNameTypeInfoAccessor::StoreObjByNameTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit,
942 GateRef gate, Chunk *chunk)
943 : ObjAccByNameTypeInfoAccessor(env, circuit, gate, chunk, AccessMode::STORE), types_(chunk_), jitTypes_(chunk)
944 {
945 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
946 switch (ecmaOpcode) {
947 case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
948 case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
949 case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
950 case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8: {
951 key_ = acc_.GetValueIn(gate, 1); // 1: key
952 receiver_ = acc_.GetValueIn(gate, 2); // 2: receiver
953 value_ = acc_.GetValueIn(gate, 3); // 3: value
954 break;
955 }
956 case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
957 case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
958 key_ = acc_.GetValueIn(gate, 1); // 1: key
959 receiver_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
960 value_ = acc_.GetValueIn(gate, 2); // 2: value
961 break;
962 }
963 case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
964 case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8: {
965 key_ = acc_.GetValueIn(gate, 0); // 0: key
966 receiver_ = acc_.GetValueIn(gate, 1); // 1: receiver
967 value_ = acc_.GetValueIn(gate, 2); // 2: value
968 break;
969 }
970 default:
971 UNREACHABLE();
972 }
973
974 if (IsAot()) {
975 strategy_ = chunk_->New<AotAccessorStrategy>(*this);
976 } else {
977 strategy_ = chunk_->New<JitAccessorStrategy>(*this);
978 }
979 strategy_->FetchPGORWTypesDual();
980 hasIllegalType_ = !strategy_->GenerateObjectAccessInfo();
981 }
982
FetchPGORWTypesDual()983 void StoreObjByNameTypeInfoAccessor::AotAccessorStrategy::FetchPGORWTypesDual()
984 {
985 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
986 if (IsMegaType(pgoTypes)) {
987 return;
988 }
989 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
990 auto temp = pgoTypes->GetObjectInfo(i);
991 parent_.types_.emplace_back(std::make_tuple(
992 std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
993 std::make_pair(temp.GetHoldRootType(), temp.GetHoldType()),
994 std::make_pair(temp.GetHoldTraRootType(), temp.GetHoldTraType())
995 ));
996 }
997 }
998
FetchPGORWTypesDual()999 void StoreObjByNameTypeInfoAccessor::JitAccessorStrategy::FetchPGORWTypesDual()
1000 {
1001 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
1002 if (IsMegaType(pgoTypes)) {
1003 return;
1004 }
1005 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
1006 auto temp = pgoTypes->GetObjectInfo(i);
1007 if (temp.GetReceiverType().IsJITClassType()) {
1008 parent_.jitTypes_.emplace_back(temp);
1009 }
1010 }
1011 }
1012
GenerateObjectAccessInfo()1013 bool StoreObjByNameTypeInfoAccessor::AotAccessorStrategy::GenerateObjectAccessInfo()
1014 {
1015 JSTaggedValue key = parent_.GetKeyTaggedValue();
1016 for (size_t i = 0; i < parent_.types_.size(); ++i) {
1017 ProfileTyper receiverType = std::get<0>(parent_.types_[i]);
1018 ProfileTyper holderType = std::get<1>(parent_.types_[i]);
1019 ProfileTyper newHolderType = std::get<2>(parent_.types_[i]);
1020
1021 if (receiverType != newHolderType) {
1022 // transition happened ==> slowpath
1023 ObjectAccessInfo newHolderInfo;
1024 if (!parent_.GeneratePlr(newHolderType, newHolderInfo, key)) {
1025 return false;
1026 }
1027 parent_.accessInfos_.emplace_back(newHolderInfo);
1028
1029 ObjectAccessInfo receiverInfo;
1030 parent_.GeneratePlr(receiverType, receiverInfo, key);
1031 if (receiverInfo.HClassIndex() == -1) {
1032 return false;
1033 }
1034 parent_.checkerInfos_.emplace_back(receiverInfo);
1035 } else if (receiverType == holderType) {
1036 ObjectAccessInfo receiverInfo;
1037 if (!parent_.GeneratePlr(receiverType, receiverInfo, key)) {
1038 return false;
1039 }
1040 parent_.accessInfos_.emplace_back(receiverInfo);
1041 parent_.checkerInfos_.emplace_back(receiverInfo);
1042 } else {
1043 UNREACHABLE();
1044 }
1045 }
1046 return true;
1047 }
1048
GenerateObjectAccessInfo()1049 bool StoreObjByNameTypeInfoAccessor::JitAccessorStrategy::GenerateObjectAccessInfo()
1050 {
1051 JSTaggedValue key = parent_.GetKeyTaggedValue();
1052 if (key.IsUndefined()) {
1053 return false;
1054 }
1055 for (size_t i = 0; i < parent_.jitTypes_.size(); ++i) {
1056 JSHClass* receiverType = parent_.jitTypes_[i].GetReceiverHclass();
1057 JSHClass* holderType = parent_.jitTypes_[i].GetHolderHclass();
1058 if (receiverType->IsJsPrimitiveRef() || holderType->IsJsPrimitiveRef()) {
1059 return false;
1060 }
1061 JSHClass* newHolderType = parent_.jitTypes_[i].GetHolderTraHclass();
1062
1063 if (receiverType != newHolderType) {
1064 // transition happened ==> slowpath
1065 ObjectAccessInfo newHolderInfo;
1066 if (!parent_.GeneratePlrInJIT(newHolderType, newHolderInfo, key)) {
1067 return false;
1068 }
1069 parent_.accessInfos_.emplace_back(newHolderInfo);
1070
1071 ObjectAccessInfo receiverInfo;
1072 parent_.GeneratePlrInJIT(receiverType, receiverInfo, key);
1073 if (receiverInfo.HClassIndex() == -1) {
1074 return false;
1075 }
1076 parent_.checkerInfos_.emplace_back(receiverInfo);
1077 } else if (receiverType == holderType) {
1078 ObjectAccessInfo receiverInfo;
1079 if (!parent_.GeneratePlrInJIT(receiverType, receiverInfo, key)) {
1080 return false;
1081 }
1082 parent_.accessInfos_.emplace_back(receiverInfo);
1083 parent_.checkerInfos_.emplace_back(receiverInfo);
1084 } else {
1085 UNREACHABLE();
1086 }
1087 }
1088 return true;
1089 }
1090
InstanceOfTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,Chunk * chunk)1091 InstanceOfTypeInfoAccessor::InstanceOfTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit, GateRef gate,
1092 Chunk *chunk)
1093 : ObjAccByNameTypeInfoAccessor(env, circuit, gate, chunk, AccessMode::LOAD), types_(chunk_), jitTypes_(chunk)
1094 {
1095 receiver_ = acc_.GetValueIn(gate, 1); // 2: receiver
1096 target_ = acc_.GetValueIn(gate, 2); // 2: the third parameter
1097 if (IsAot()) {
1098 strategy_ = chunk_->New<AotAccessorStrategy>(*this);
1099 } else {
1100 strategy_ = chunk_->New<JitAccessorStrategy>(*this);
1101 }
1102 strategy_->FetchPGORWTypesDual();
1103 hasIllegalType_ = !strategy_->GenerateObjectAccessInfo();
1104 }
1105
GetKeyTaggedValue() const1106 JSTaggedValue InstanceOfTypeInfoAccessor::GetKeyTaggedValue() const
1107 {
1108 JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1109 auto hasInstanceEnvIndex = static_cast<size_t>(GlobalEnvField::HASINSTANCE_SYMBOL_INDEX);
1110 return globalEnv->GetGlobalEnvObjectByIndex(hasInstanceEnvIndex).GetTaggedValue();
1111 }
1112
FetchPGORWTypesDual()1113 void InstanceOfTypeInfoAccessor::AotAccessorStrategy::FetchPGORWTypesDual()
1114 {
1115 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
1116 if (IsMegaType(pgoTypes)) {
1117 return;
1118 }
1119 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
1120 auto temp = pgoTypes->GetObjectInfo(i);
1121 if (temp.GetReceiverType().IsBuiltinsType()) {
1122 continue;
1123 }
1124 parent_.types_.emplace_back(std::make_pair(std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
1125 std::make_pair(temp.GetHoldRootType(), temp.GetHoldType())));
1126 }
1127 }
1128
FetchPGORWTypesDual()1129 void InstanceOfTypeInfoAccessor::JitAccessorStrategy::FetchPGORWTypesDual()
1130 {
1131 const PGORWOpType *pgoTypes = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGORWOpType();
1132 if (IsMegaType(pgoTypes)) {
1133 return;
1134 }
1135 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
1136 auto temp = pgoTypes->GetObjectInfo(i);
1137 if (temp.GetReceiverType().IsJITClassType()) {
1138 parent_.jitTypes_.emplace_back(temp);
1139 }
1140 }
1141 }
1142
1143
ClassInstanceIsCallable(ProfileTyper type) const1144 bool InstanceOfTypeInfoAccessor::AotAccessorStrategy::ClassInstanceIsCallable(ProfileTyper type) const
1145 {
1146 int hclassIndex = static_cast<int>(parent_.ptManager_->GetHClassIndexByProfileType(type));
1147 if (hclassIndex == -1) {
1148 return false;
1149 }
1150
1151 JSTaggedValue hclass = parent_.ptManager_->QueryHClass(type.first, type.second);
1152 if (!hclass.IsJSHClass()) {
1153 return false;
1154 }
1155 return JSHClass::Cast(hclass.GetTaggedObject())->IsCallable();
1156 }
1157
ClassInstanceIsCallable(JSHClass * hclass) const1158 bool InstanceOfTypeInfoAccessor::JitAccessorStrategy::ClassInstanceIsCallable(JSHClass *hclass) const
1159 {
1160 return hclass->IsCallable();
1161 }
1162
1163
GenerateObjectAccessInfo()1164 bool InstanceOfTypeInfoAccessor::AotAccessorStrategy::GenerateObjectAccessInfo()
1165 {
1166 // Instanceof does not support Poly for now
1167 if (!IsMono()) {
1168 return false;
1169 }
1170 JSTaggedValue key = parent_.GetKeyTaggedValue();
1171 for (size_t i = 0; i < parent_.types_.size(); ++i) {
1172 ProfileTyper targetPgoType = parent_.types_[i].first;
1173 ObjectAccessInfo targetInfo;
1174 // If @@hasInstance is found on prototype Chain of ctor -> slowpath
1175 // Future work: pgo support Symbol && Dump Object.defineProperty && FunctionPrototypeHclass
1176 // Current temporary solution:
1177 // Try searching @@hasInstance in pgo dump stage,
1178 // If found, pgo dump no types and we go slowpath in aot
1179 parent_.GeneratePlr(targetPgoType, targetInfo, key);
1180 if (targetInfo.HClassIndex() == -1 || !ClassInstanceIsCallable(targetPgoType)) {
1181 return false;
1182 }
1183 parent_.accessInfos_.emplace_back(targetInfo);
1184 parent_.checkerInfos_.emplace_back(targetInfo);
1185 }
1186 return true;
1187 }
1188
GenerateObjectAccessInfo()1189 bool InstanceOfTypeInfoAccessor::JitAccessorStrategy::GenerateObjectAccessInfo()
1190 {
1191 // Instanceof does not support Poly for now
1192 if (!IsMono()) {
1193 return false;
1194 }
1195 JSTaggedValue key = parent_.GetKeyTaggedValue();
1196 if (key.IsUndefined()) {
1197 return false;
1198 }
1199 for (size_t i = 0; i < parent_.jitTypes_.size(); ++i) {
1200 JSHClass *receiver = parent_.jitTypes_[i].GetReceiverHclass();
1201 if (receiver->IsJsPrimitiveRef()) {
1202 return false;
1203 }
1204 ObjectAccessInfo targetInfo;
1205 // If @@hasInstance is found on prototype Chain of ctor -> slowpath
1206 // Future work: pgo support Symbol && Dump Object.defineProperty && FunctionPrototypeHclass
1207 // Current temporary solution:
1208 // Try searching @@hasInstance in pgo dump stage,
1209 // If found, pgo dump no types and we go slowpath in aot
1210 parent_.GeneratePlrInJIT(receiver, targetInfo, key);
1211 if (targetInfo.HClassIndex() == -1 || !ClassInstanceIsCallable(receiver)) {
1212 return false;
1213 }
1214 parent_.accessInfos_.emplace_back(targetInfo);
1215 parent_.checkerInfos_.emplace_back(targetInfo);
1216 }
1217 return true;
1218 }
1219
LoadBulitinObjTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,Chunk * chunk)1220 LoadBulitinObjTypeInfoAccessor::LoadBulitinObjTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit,
1221 GateRef gate, Chunk *chunk)
1222 : AccBuiltinObjTypeInfoAccessor(env, circuit, gate, chunk, AccessMode::LOAD)
1223 {
1224 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1225 switch (ecmaOpcode) {
1226 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
1227 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8: {
1228 receiver_ = acc_.GetValueIn(gate, 1); // 1: receiver
1229 key_ = acc_.GetValueIn(gate, 2); // 2: key
1230 break;
1231 }
1232 case EcmaOpcode::LDTHISBYVALUE_IMM8:
1233 case EcmaOpcode::LDTHISBYVALUE_IMM16: {
1234 receiver_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
1235 key_ = acc_.GetValueIn(gate, 1); // 1: key
1236 break;
1237 }
1238 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
1239 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
1240 key_ = acc_.GetValueIn(gate, 1); // 1: key
1241 receiver_ = acc_.GetValueIn(gate, 2); // 2: receiver
1242 break;
1243 }
1244 case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
1245 case EcmaOpcode::LDTHISBYNAME_IMM16_ID16: {
1246 key_ = acc_.GetValueIn(gate, 1); // 1: key
1247 receiver_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
1248 break;
1249 }
1250 case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
1251 case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
1252 case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32: {
1253 key_ = acc_.GetValueIn(gate, 0);
1254 receiver_ = acc_.GetValueIn(gate, 1);
1255 break;
1256 }
1257 default:
1258 UNREACHABLE();
1259 }
1260 FetchBuiltinsTypes();
1261 }
1262
IsStringMonoBuiltins() const1263 bool AccBuiltinObjTypeInfoAccessor::IsStringMonoBuiltins() const
1264 {
1265 for (auto type : types_) {
1266 if (!type.IsBuiltinsString()) {
1267 return false;
1268 }
1269 }
1270 return true;
1271 }
1272
IsMonoBuiltins() const1273 bool AccBuiltinObjTypeInfoAccessor::IsMonoBuiltins() const
1274 {
1275 if (types_.size() == 0) {
1276 return false;
1277 }
1278
1279 if (IsStringMonoBuiltins()) {
1280 return true;
1281 }
1282
1283 for (size_t i = 0; i < types_.size(); i++) {
1284 if (!types_[i].IsBuiltinsType()) {
1285 return false;
1286 }
1287 if (types_[i].GetBuiltinsType() != types_[0].GetBuiltinsType()) {
1288 return false;
1289 }
1290 }
1291 return true;
1292 }
1293
FetchBuiltinsTypes()1294 void AccBuiltinObjTypeInfoAccessor::FetchBuiltinsTypes()
1295 {
1296 const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType();
1297 if (IsMegaType(pgoTypes)) {
1298 return;
1299 }
1300 for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
1301 auto temp = pgoTypes->GetObjectInfo(i);
1302 if (temp.GetReceiverType().IsBuiltinsType()) {
1303 if (CheckDuplicatedBuiltinType(temp.GetReceiverType())) {
1304 continue;
1305 }
1306 types_.emplace_back(temp.GetReceiverType());
1307 } else if (temp.GetReceiverType().IsGlobalsType()) {
1308 types_.emplace_back(temp.GetReceiverType());
1309 }
1310 }
1311 }
1312
CheckDuplicatedBuiltinType(ProfileType newType) const1313 bool AccBuiltinObjTypeInfoAccessor::CheckDuplicatedBuiltinType(ProfileType newType) const
1314 {
1315 for (auto &type : types_) {
1316 if (type.GetBuiltinsType() == newType.GetBuiltinsType()) {
1317 if (type.IsBuiltinsArray()) {
1318 // When array elementsKind switch on, we should check elementsKind too.
1319 return (type.GetElementsKindBeforeTransition() == newType.GetElementsKindBeforeTransition() &&
1320 type.GetElementsKindAfterTransition() == newType.GetElementsKindAfterTransition());
1321 }
1322 return true;
1323 }
1324 }
1325 return false;
1326 }
1327
StoreBulitinObjTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,Chunk * chunk)1328 StoreBulitinObjTypeInfoAccessor::StoreBulitinObjTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit,
1329 GateRef gate, Chunk *chunk)
1330 : AccBuiltinObjTypeInfoAccessor(env, circuit, gate, chunk, AccessMode::STORE)
1331 {
1332 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1333 switch (ecmaOpcode) {
1334 case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
1335 case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
1336 case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
1337 case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
1338 case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32: {
1339 key_ = acc_.GetValueIn(gate, 0); // 0: key
1340 receiver_ = acc_.GetValueIn(gate, 1); // 1: receiver
1341 value_ = acc_.GetValueIn(gate, 2); // 2: value
1342 break;
1343 }
1344 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
1345 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8: {
1346 receiver_ = acc_.GetValueIn(gate, 1); // 1: receiver
1347 key_ = acc_.GetValueIn(gate, 2); // 2: key
1348 value_ = acc_.GetValueIn(gate, 3); // 3: value
1349 break;
1350 }
1351 default:
1352 UNREACHABLE();
1353 }
1354 FetchBuiltinsTypes();
1355 }
1356
CreateObjWithBufferTypeInfoAccessor(const CompilationEnv * env,Circuit * circuit,GateRef gate,const CString & recordName,Chunk * chunk)1357 CreateObjWithBufferTypeInfoAccessor::CreateObjWithBufferTypeInfoAccessor(const CompilationEnv *env, Circuit *circuit,
1358 GateRef gate, const CString &recordName,
1359 Chunk *chunk)
1360 : TypeInfoAccessor(env, circuit, gate), recordName_(recordName)
1361 {
1362 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: number of value ins
1363 index_ = acc_.GetValueIn(gate, 0);
1364 if (IsAot()) {
1365 strategy_ = chunk->New<AotAccessorStrategy>(*this);
1366 } else {
1367 strategy_ = chunk->New<JitAccessorStrategy>(*this);
1368 }
1369 }
1370
GetObject() const1371 JSTaggedValue CreateObjWithBufferTypeInfoAccessor::GetObject() const
1372 {
1373 auto imm = acc_.GetConstantValue(index_);
1374 auto methodOffset = acc_.TryGetMethodOffset(GetGate());
1375 JSTaggedValue unsharedCp = compilationEnv_->FindOrCreateUnsharedConstpool(methodOffset);
1376 if (unsharedCp.IsUndefined()) {
1377 return JSTaggedValue::Undefined();
1378 }
1379 return compilationEnv_->GetObjectLiteralFromCache(unsharedCp, imm, recordName_);
1380 }
1381
GetHClass() const1382 JSTaggedValue CreateObjWithBufferTypeInfoAccessor::AotAccessorStrategy::GetHClass() const
1383 {
1384 JSTaggedValue obj = parent_.GetObject();
1385 if (obj.IsUndefined()) {
1386 return JSTaggedValue::Undefined();
1387 }
1388 auto sampleType = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGODefineOpType();
1389 auto type = std::make_pair(sampleType->GetProfileType(), sampleType->GetProfileType());
1390 int hclassIndex = static_cast<int>(parent_.ptManager_->GetHClassIndexByProfileType(type));
1391
1392 JSObject *jsObj = JSObject::Cast(obj);
1393 JSHClass *oldClass = jsObj->GetClass();
1394 if (hclassIndex == -1) {
1395 if (jsObj->ElementsAndPropertiesIsEmpty()) {
1396 return JSTaggedValue(oldClass);
1397 }
1398 return JSTaggedValue::Undefined();
1399 }
1400 JSTaggedValue newClass = parent_.ptManager_->QueryHClass(type.first, type.second);
1401 if (!newClass.IsJSHClass()) {
1402 return JSTaggedValue::Undefined();
1403 }
1404 if (oldClass->GetInlinedProperties() != JSHClass::Cast(newClass.GetTaggedObject())->GetInlinedProperties()) {
1405 return JSTaggedValue::Undefined();
1406 }
1407 return newClass;
1408 }
1409
GetHClass() const1410 JSTaggedValue CreateObjWithBufferTypeInfoAccessor::JitAccessorStrategy::GetHClass() const
1411 {
1412 JSTaggedValue obj = parent_.GetObject();
1413 if (obj.IsUndefined()) {
1414 return JSTaggedValue::Undefined();
1415 }
1416 auto sampleType = parent_.acc_.TryGetPGOType(parent_.gate_).GetPGODefineOpType();
1417 if (sampleType->IsNone()) {
1418 return JSTaggedValue::Undefined();
1419 }
1420 JSObject *jsObj = JSObject::Cast(obj);
1421 JSHClass *oldClass = jsObj->GetClass();
1422 JSHClass *newClass = sampleType->GetReceiver();
1423 if (newClass == nullptr) {
1424 if (jsObj->ElementsAndPropertiesIsEmpty()) {
1425 return JSTaggedValue(oldClass);
1426 }
1427 return JSTaggedValue::Undefined();
1428 }
1429 if (oldClass->GetInlinedProperties() != newClass->GetInlinedProperties()) {
1430 return JSTaggedValue::Undefined();
1431 }
1432 return JSTaggedValue(newClass);
1433 }
1434
1435 } // namespace panda::ecmascript::kungfu
1436