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