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