• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "pandagen.h"
17 
18 #include <binder/binder.h>
19 #include <binder/scope.h>
20 #include <binder/variable.h>
21 #include <compiler/base/catchTable.h>
22 #include <compiler/base/lexenv.h>
23 #include <compiler/base/literals.h>
24 #include <compiler/core/compilerContext.h>
25 #include <compiler/core/labelTarget.h>
26 #include <compiler/core/regAllocator.h>
27 #include <compiler/function/asyncFunctionBuilder.h>
28 #include <compiler/function/asyncGeneratorFunctionBuilder.h>
29 #include <compiler/function/functionBuilder.h>
30 #include <compiler/function/generatorFunctionBuilder.h>
31 #include <es2panda.h>
32 #include <gen/isa.h>
33 #include <ir/base/classDefinition.h>
34 #include <ir/base/methodDefinition.h>
35 #include <ir/base/scriptFunction.h>
36 #include <ir/base/spreadElement.h>
37 #include <ir/expressions/callExpression.h>
38 #include <ir/expressions/functionExpression.h>
39 #include <ir/expressions/identifier.h>
40 #include <ir/expressions/literals/numberLiteral.h>
41 #include <ir/expressions/literals/stringLiteral.h>
42 #include <ir/expressions/newExpression.h>
43 #include <ir/module/importSpecifier.h>
44 #include <ir/statement.h>
45 #include <util/concurrent.h>
46 #include <util/helpers.h>
47 #include <util/patchFix.h>
48 
49 namespace panda::es2panda::compiler {
50 
51 // PandaGen
52 
SetFunctionKind()53 void PandaGen::SetFunctionKind()
54 {
55     int targetApiVersion = Binder()->Program()->TargetApiVersion();
56     if (rootNode_->IsProgram()) {
57         funcKind_ = panda::panda_file::FunctionKind::FUNCTION;
58         return;
59     }
60 
61     auto *func = rootNode_->AsScriptFunction();
62     if (func->IsConcurrent()) {
63         funcKind_ = panda::panda_file::FunctionKind::CONCURRENT_FUNCTION;
64         return;
65     }
66 
67     if (func->IsMethod()) {
68         if (func->IsAsync()) {
69             funcKind_ = panda::panda_file::FunctionKind::ASYNC_FUNCTION;
70         }
71         return;
72     }
73 
74     if (func->IsAsync()) {
75         if (func->IsGenerator()) {
76             funcKind_ = panda::panda_file::FunctionKind::ASYNC_GENERATOR_FUNCTION;
77             return;
78         }
79 
80         if (func->IsArrow()) {
81             funcKind_ = panda::panda_file::FunctionKind::ASYNC_NC_FUNCTION;
82             return;
83         }
84 
85         funcKind_ = panda::panda_file::FunctionKind::ASYNC_FUNCTION;
86 
87         if (func->IsSendable() && targetApiVersion >= util::Helpers::SENDABLE_FUNCTION_MIN_SUPPORTED_API_VERSION) {
88             funcKind_ |= panda::panda_file::FunctionKind::SENDABLE_FUNCTION;
89         }
90         return;
91     }
92 
93     if (func->IsGenerator()) {
94         funcKind_ = panda::panda_file::FunctionKind::GENERATOR_FUNCTION;
95         return;
96     }
97 
98     if (func->IsArrow()) {
99         funcKind_ = panda::panda_file::FunctionKind::NC_FUNCTION;
100         return;
101     }
102 
103     funcKind_ = panda::panda_file::FunctionKind::FUNCTION;
104 
105     if (func->IsSendable() && targetApiVersion >= util::Helpers::SENDABLE_FUNCTION_MIN_SUPPORTED_API_VERSION) {
106         funcKind_ |= panda::panda_file::FunctionKind::SENDABLE_FUNCTION;
107     }
108 }
109 
SetInSendable()110 void PandaGen::SetInSendable()
111 {
112     if (rootNode_->IsProgram()) {
113         return;
114     }
115 
116     auto *func = rootNode_->AsScriptFunction();
117     inSendable_ = func->InSendable();
118 }
119 
AllocLabel()120 Label *PandaGen::AllocLabel()
121 {
122     std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++);
123     return ra_.AllocLabel(std::move(id));
124 }
125 
IsDebug() const126 bool PandaGen::IsDebug() const
127 {
128     return context_->IsDebug();
129 }
130 
isDebuggerEvaluateExpressionMode() const131 bool PandaGen::isDebuggerEvaluateExpressionMode() const
132 {
133     return context_->isDebuggerEvaluateExpressionMode();
134 }
135 
SourceFile() const136 std::string PandaGen::SourceFile() const
137 {
138     return context_->SourceFile();
139 }
140 
ParamCount() const141 uint32_t PandaGen::ParamCount() const
142 {
143     if (rootNode_->IsProgram()) {
144         return 0;
145     }
146 
147     return rootNode_->AsScriptFunction()->Params().size();
148 }
149 
FormalParametersCount() const150 uint32_t PandaGen::FormalParametersCount() const
151 {
152     if (rootNode_->IsProgram()) {
153         return 0;
154     }
155 
156     ASSERT(rootNode_->IsScriptFunction());
157 
158     return rootNode_->AsScriptFunction()->FormalParamsLength();
159 }
160 
InternalParamCount() const161 uint32_t PandaGen::InternalParamCount() const
162 {
163     if (rootNode_->IsProgram() && context_->Binder()->Program()->IsCommonjs()) {
164         return binder::Binder::CJS_MANDATORY_PARAMS_NUMBER;
165     }
166     return ParamCount() + binder::Binder::MANDATORY_PARAMS_NUMBER;
167 }
168 
InternalName() const169 const util::StringView &PandaGen::InternalName() const
170 {
171     return topScope_->InternalName();
172 }
173 
FunctionName() const174 const util::StringView &PandaGen::FunctionName() const
175 {
176     return topScope_->Name();
177 }
178 
Binder() const179 binder::Binder *PandaGen::Binder() const
180 {
181     return context_->Binder();
182 }
183 
FunctionInit(CatchTable * catchTable)184 void PandaGen::FunctionInit(CatchTable *catchTable)
185 {
186     if (rootNode_->IsProgram()) {
187         if (context_->Binder()->Program()->HasTLA()) {
188             builder_ = allocator_->New<AsyncFunctionBuilder>(this, catchTable);
189         } else {
190             builder_ = allocator_->New<FunctionBuilder>(this, catchTable);
191         }
192         return;
193     }
194 
195     const ir::ScriptFunction *func = rootNode_->AsScriptFunction();
196 
197     if (func->IsAsync()) {
198         if (func->IsGenerator()) {
199             builder_ = allocator_->New<AsyncGeneratorFunctionBuilder>(this, catchTable);
200             return;
201         }
202 
203         builder_ = allocator_->New<AsyncFunctionBuilder>(this, catchTable);
204         return;
205     }
206 
207     if (func->IsGenerator()) {
208         builder_ = allocator_->New<GeneratorFunctionBuilder>(this, catchTable);
209         return;
210     }
211 
212     builder_ = allocator_->New<FunctionBuilder>(this, catchTable);
213 }
214 
FunctionHasFinalizer() const215 bool PandaGen::FunctionHasFinalizer() const
216 {
217     if (rootNode_->IsProgram()) {
218         return context_->Binder()->Program()->HasTLA();
219     }
220 
221     const ir::ScriptFunction *func = rootNode_->AsScriptFunction();
222 
223     return func->IsAsync() || func->IsGenerator();
224 }
225 
IsAsyncFunction() const226 bool PandaGen::IsAsyncFunction() const
227 {
228     if (rootNode_->IsProgram() && context_->Binder()->Program()->HasTLA()) {
229         return true;
230     }
231     const ir::ScriptFunction *func = rootNode_->AsScriptFunction();
232     return func->IsAsync() && !func->IsGenerator();
233 }
234 
FunctionEnter()235 void PandaGen::FunctionEnter()
236 {
237     if (rootNode_->IsProgram() && context_->Binder()->Program()->HasTLA()) {
238         builder_->Prepare(nullptr);
239         return;
240     }
241     builder_->Prepare(rootNode_->AsScriptFunction());
242 }
243 
FunctionExit()244 void PandaGen::FunctionExit()
245 {
246     if (rootNode_->IsProgram() && context_->Binder()->Program()->HasTLA()) {
247         builder_->CleanUp(nullptr);
248         return;
249     }
250     builder_->CleanUp(rootNode_->AsScriptFunction());
251 }
252 
InitializeLexEnv(const ir::AstNode * node)253 void PandaGen::InitializeLexEnv(const ir::AstNode *node)
254 {
255     FrontAllocator fa(this);
256 
257     if (topScope_->NeedLexEnv()) {
258         NewLexicalEnv(node, topScope_->LexicalSlots(), topScope_);
259     }
260 
261     if (topScope_->NeedSendableEnv()) {
262         NewSendableEnv(node, topScope_->SendableSlots());
263     }
264 }
265 
CopyFunctionArguments(const ir::AstNode * node)266 void PandaGen::CopyFunctionArguments(const ir::AstNode *node)
267 {
268     FrontAllocator fa(this);
269     VReg targetReg = totalRegs_;
270 
271     for (const auto *param : topScope_->ParamScope()->Params()) {
272         if (param->LexicalBound()) {
273             StoreLexicalVar(node, 0, param->LexIdx(), targetReg++);
274             continue;
275         }
276         MoveVreg(node, param->Vreg(), targetReg++);
277     }
278 }
279 
NewLiteralBuffer()280 LiteralBuffer *PandaGen::NewLiteralBuffer()
281 {
282     LiteralBuffer *buf = allocator_->New<LiteralBuffer>(allocator_);
283     CHECK_NOT_NULL(buf);
284     return buf;
285 }
286 
AddLiteralBuffer(LiteralBuffer * buf)287 int32_t PandaGen::AddLiteralBuffer(LiteralBuffer *buf)
288 {
289     CHECK_NOT_NULL(buf);
290     buffStorage_.push_back(buf);
291     buf->SetIndex(context_->NewLiteralIndex());
292     return buf->Index();
293 }
294 
AddLexicalVarNamesForDebugInfo(ArenaMap<uint32_t,std::pair<util::StringView,int>> & lexicalVars)295 int32_t PandaGen::AddLexicalVarNamesForDebugInfo(ArenaMap<uint32_t, std::pair<util::StringView, int>> &lexicalVars)
296 {
297     auto *buf = NewLiteralBuffer();
298     buf->Add(Allocator()->New<ir::NumberLiteral>(lexicalVars.size()));
299     for (auto &iter : lexicalVars) {
300         // The slot is set to UINT32_MAX when the variable is a patchvar while its value is not stored in the slot
301         // The patchvar info should not be added to the DebugInfo since its value cannot be found in slot UINT32_MAX
302         if (iter.first != UINT32_MAX) {
303             buf->Add(Allocator()->New<ir::StringLiteral>(iter.second.first));
304             buf->Add(Allocator()->New<ir::NumberLiteral>(iter.first));
305         }
306     }
307     return AddLiteralBuffer(buf);
308 }
309 
GetFunctionObject(const ir::AstNode * node)310 void PandaGen::GetFunctionObject(const ir::AstNode *node)
311 {
312     LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_FUNC));
313 }
314 
GetNewTarget(const ir::AstNode * node)315 void PandaGen::GetNewTarget(const ir::AstNode *node)
316 {
317     LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_NEW_TARGET));
318 }
319 
GetThis(const ir::AstNode * node)320 void PandaGen::GetThis(const ir::AstNode *node)
321 {
322     LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS));
323 }
324 
SetThis(const ir::AstNode * node)325 void PandaGen::SetThis(const ir::AstNode *node)
326 {
327     StoreAccToLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS), true);
328 }
329 
LoadVar(const ir::Identifier * node,const binder::ScopeFindResult & result)330 void PandaGen::LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result)
331 {
332     auto *var = result.variable;
333 
334     if (!var || var->Declaration()->IsDeclare()) {
335         TryLoadGlobalByName(node, result.name);
336         return;
337     }
338 
339     if (var->IsGlobalVariable()) {
340         LoadGlobalVar(node, var->Name());
341         return;
342     }
343 
344     if (var->IsModuleVariable()) {
345         var->HasFlag(binder::VariableFlags::LOCAL_EXPORT) ? LoadLocalModuleVariable(node, var->AsModuleVariable()) :
346                                                             LoadExternalModuleVariable(node, var->AsModuleVariable());
347         if (var->Declaration()->IsLetOrConstOrClassDecl()) {
348             ThrowUndefinedIfHole(node, var->Name());
349         }
350         return;
351     }
352 
353     ASSERT(var->IsLocalVariable());
354 
355     if (var->Declaration()->IsLetOrConstOrClassDecl() && result.scope->IsGlobalScope()) {
356         TryLoadGlobalByName(node, result.name);
357         return;
358     }
359 
360     LoadAccFromLexEnv(node, result);
361 }
362 
StoreVar(const ir::AstNode * node,const binder::ScopeFindResult & result,bool isDeclaration)363 void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration)
364 {
365     binder::Variable *var = result.variable;
366 
367     if (!var) {
368         TryStoreGlobalByName(node, result.name);
369         return;
370     }
371 
372     if (var->IsGlobalVariable()) {
373         StoreGlobalVar(node, var->Name());
374         return;
375     }
376 
377     if (var->IsModuleVariable()) {
378         if (!isDeclaration && var->Declaration()->IsConstDecl()) {
379             ThrowConstAssignment(node, var->Name());
380             return;
381         }
382 
383         if (!isDeclaration &&
384             (var->Declaration()->IsLetDecl() || var->Declaration()->IsClassDecl())) {
385             RegScope rs(this);
386             VReg valueReg = AllocReg();
387             StoreAccumulator(node, valueReg);
388             LoadLocalModuleVariable(node, var->AsModuleVariable());
389             ThrowUndefinedIfHole(node, var->Name());
390             LoadAccumulator(node, valueReg);
391         }
392 
393         StoreModuleVariable(node, var->AsModuleVariable());
394         return;
395     }
396 
397     ASSERT(var->IsLocalVariable());
398 
399     if (var->Declaration()->IsLetOrConstOrClassDecl() && result.scope->IsGlobalScope()) {
400         if (!isDeclaration) {
401             TryStoreGlobalByName(node, var->Name());
402         } else if (var->Declaration()->IsLetDecl() || var->Declaration()->IsClassDecl()) {
403             StLetOrClassToGlobalRecord(node, var->Name());
404         } else if (var->Declaration()->IsConstDecl()) {
405             StConstToGlobalRecord(node, var->Name());
406         }
407 
408         return;
409     }
410 
411     StoreAccToLexEnv(node, result, isDeclaration);
412 }
413 
StoreAccumulator(const ir::AstNode * node,VReg vreg)414 void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg)
415 {
416     ra_.Emit<Sta>(node, vreg);
417 }
418 
LoadAccFromArgs(const ir::AstNode * node)419 void PandaGen::LoadAccFromArgs(const ir::AstNode *node)
420 {
421     const auto *varScope = scope_->AsVariableScope();
422 
423     if (!varScope->HasFlag(binder::VariableScopeFlags::USE_ARGS)) {
424         return;
425     }
426 
427     binder::ScopeFindResult res = scope_->Find(binder::Binder::FUNCTION_ARGUMENTS);
428     ASSERT(res.scope);
429 
430     GetUnmappedArgs(node);
431     StoreAccToLexEnv(node, res, true);
432 }
433 
LoadObjProperty(const ir::AstNode * node,VReg obj,const Operand & prop)434 void PandaGen::LoadObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
435 {
436     if (std::holds_alternative<VReg>(prop)) {
437         LoadAccumulator(node, std::get<VReg>(prop));
438         LoadObjByValue(node, obj);
439         return;
440     }
441 
442     if (std::holds_alternative<int64_t>(prop)) {
443         LoadObjByIndex(node, obj, std::get<int64_t>(prop));
444         return;
445     }
446 
447     ASSERT(std::holds_alternative<util::StringView>(prop));
448     LoadObjByName(node, obj, std::get<util::StringView>(prop));
449 }
450 
StoreObjProperty(const ir::AstNode * node,VReg obj,const Operand & prop)451 void PandaGen::StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
452 {
453     if (std::holds_alternative<VReg>(prop)) {
454         StoreObjByValue(node, obj, std::get<VReg>(prop));
455         return;
456     }
457 
458     if (std::holds_alternative<int64_t>(prop)) {
459         StoreObjByIndex(node, obj, std::get<int64_t>(prop));
460         return;
461     }
462 
463     ASSERT(std::holds_alternative<util::StringView>(prop));
464     StoreObjByName(node, obj, std::get<util::StringView>(prop));
465 }
466 
DefineOwnProperty(const ir::AstNode * node,VReg obj,const Operand & prop)467 void PandaGen::DefineOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
468 {
469     if (std::holds_alternative<VReg>(prop)) {
470         DefineFieldByValue(node, obj, std::get<VReg>(prop));
471         return;
472     }
473 
474     if (std::holds_alternative<int64_t>(prop)) {
475         DefineFieldByIndex(node, obj, std::get<int64_t>(prop));
476         return;
477     }
478 
479     ASSERT(std::holds_alternative<util::StringView>(prop));
480     DefineFieldByName(node, obj, std::get<util::StringView>(prop));
481 }
482 
DefineClassPrivateField(const ir::AstNode * node,uint32_t level,uint32_t slot,VReg obj)483 void PandaGen::DefineClassPrivateField(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg obj)
484 {
485     ra_.Emit<CallruntimeDefineprivateproperty>(node, 0, level, slot, obj);
486 }
487 
StoreOwnProperty(const ir::AstNode * node,VReg obj,const Operand & prop,bool nameSetting)488 void PandaGen::StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop, bool nameSetting)
489 {
490     if (std::holds_alternative<VReg>(prop)) {
491         StOwnByValue(node, obj, std::get<VReg>(prop), nameSetting);
492         return;
493     }
494 
495     if (std::holds_alternative<int64_t>(prop)) {
496         StOwnByIndex(node, obj, std::get<int64_t>(prop));
497         return;
498     }
499 
500     ASSERT(std::holds_alternative<util::StringView>(prop));
501     StOwnByName(node, obj, std::get<util::StringView>(prop), nameSetting);
502 }
503 
504 constexpr size_t DEBUGGER_GET_SET_ARGS_NUM = 2;
505 
LoadObjByNameViaDebugger(const ir::AstNode * node,const util::StringView & name,bool throwUndefinedIfHole)506 void PandaGen::LoadObjByNameViaDebugger(const ir::AstNode *node, const util::StringView &name,
507                                         bool throwUndefinedIfHole)
508 {
509     RegScope rs(this);
510     VReg global = AllocReg();
511     LoadConst(node, compiler::Constant::JS_GLOBAL);
512     StoreAccumulator(node, global);
513     LoadObjByName(node, global, "debuggerGetValue");
514     VReg debuggerGetValueReg = AllocReg();
515     StoreAccumulator(node, debuggerGetValueReg);
516     VReg variableReg = AllocReg();
517     LoadAccumulatorString(node, name);
518     StoreAccumulator(node, variableReg);
519     VReg boolFlag = AllocReg();
520     if (throwUndefinedIfHole) {
521         LoadConst(node, compiler::Constant::JS_TRUE);
522     } else {
523         LoadConst(node, compiler::Constant::JS_FALSE);
524     }
525     StoreAccumulator(node, boolFlag);
526     Call(node, debuggerGetValueReg, DEBUGGER_GET_SET_ARGS_NUM);
527 }
528 
TryLoadGlobalByName(const ir::AstNode * node,const util::StringView & name)529 void PandaGen::TryLoadGlobalByName(const ir::AstNode *node, const util::StringView &name)
530 {
531     if (isDebuggerEvaluateExpressionMode()) {
532         LoadObjByNameViaDebugger(node, name, true);
533     } else {
534         ra_.Emit<Tryldglobalbyname>(node, 0, name);
535     }
536     strings_.insert(name);
537 }
538 
StoreObjByNameViaDebugger(const ir::AstNode * node,const util::StringView & name)539 void PandaGen::StoreObjByNameViaDebugger(const ir::AstNode *node, const util::StringView &name)
540 {
541     RegScope rs(this);
542     VReg valueReg = AllocReg();
543     StoreAccumulator(node, valueReg);
544     VReg global = AllocReg();
545     LoadConst(node, compiler::Constant::JS_GLOBAL);
546     StoreAccumulator(node, global);
547     LoadObjByName(node, global, "debuggerSetValue");
548     VReg debuggerSetValueReg = AllocReg();
549     StoreAccumulator(node, debuggerSetValueReg);
550     VReg variableReg = AllocReg();
551     LoadAccumulatorString(node, name);
552     StoreAccumulator(node, variableReg);
553     MoveVreg(node, AllocReg(), valueReg);
554     Call(node, debuggerSetValueReg, DEBUGGER_GET_SET_ARGS_NUM);
555 }
556 
TryStoreGlobalByName(const ir::AstNode * node,const util::StringView & name)557 void PandaGen::TryStoreGlobalByName(const ir::AstNode *node, const util::StringView &name)
558 {
559     if (isDebuggerEvaluateExpressionMode()) {
560         StoreObjByNameViaDebugger(node, name);
561     } else {
562         ra_.Emit<Trystglobalbyname>(node, 0, name);
563     }
564     strings_.insert(name);
565 }
566 
LoadObjByName(const ir::AstNode * node,VReg obj,const util::StringView & prop)567 void PandaGen::LoadObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop)
568 {
569     LoadAccumulator(node, obj); // object is load to acc
570     ra_.Emit<Ldobjbyname>(node, 0, prop);
571     strings_.insert(prop);
572 }
573 
StoreObjByName(const ir::AstNode * node,VReg obj,const util::StringView & prop)574 void PandaGen::StoreObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop)
575 {
576     ra_.Emit<Stobjbyname>(node, 0, prop, obj);
577     strings_.insert(prop);
578 }
579 
DefineFieldByName(const ir::AstNode * node,VReg obj,const util::StringView & prop)580 void PandaGen::DefineFieldByName(const ir::AstNode *node, VReg obj, const util::StringView &prop)
581 {
582     if (util::Helpers::IsDefaultApiVersion(Binder()->Program()->TargetApiVersion(),
583         Binder()->Program()->GetTargetApiSubVersion())) {
584         ra_.Emit<Definefieldbyname>(node, 0, prop, obj);
585         strings_.insert(prop);
586         return;
587     }
588 
589     ra_.Emit<Definepropertybyname>(node, 0, prop, obj);
590     strings_.insert(prop);
591 }
592 
LoadObjByIndex(const ir::AstNode * node,VReg obj,int64_t index)593 void PandaGen::LoadObjByIndex(const ir::AstNode *node, VReg obj, int64_t index)
594 {
595     LoadAccumulator(node, obj); // object is load to acc
596     if (index <= util::Helpers::MAX_INT16) {
597         ra_.Emit<Ldobjbyindex>(node, 0, index);
598         return;
599     }
600 
601     ra_.Emit<WideLdobjbyindex>(node, index);
602 }
603 
LoadObjByValue(const ir::AstNode * node,VReg obj)604 void PandaGen::LoadObjByValue(const ir::AstNode *node, VReg obj)
605 {
606     ra_.Emit<Ldobjbyvalue>(node, 0, obj); // prop is in acc
607 }
608 
StoreObjByValue(const ir::AstNode * node,VReg obj,VReg prop)609 void PandaGen::StoreObjByValue(const ir::AstNode *node, VReg obj, VReg prop)
610 {
611     ra_.Emit<Stobjbyvalue>(node, 0, obj, prop);
612 }
613 
StoreObjByIndex(const ir::AstNode * node,VReg obj,int64_t index)614 void PandaGen::StoreObjByIndex(const ir::AstNode *node, VReg obj, int64_t index)
615 {
616     if (index <= util::Helpers::MAX_INT16) {
617         ra_.Emit<Stobjbyindex>(node, 0, obj, index);
618         return;
619     }
620 
621     ra_.Emit<WideStobjbyindex>(node, obj, index);
622 }
623 
DefineFieldByValue(const ir::AstNode * node,VReg obj,VReg prop)624 void PandaGen::DefineFieldByValue(const ir::AstNode *node, VReg obj, VReg prop)
625 {
626     ra_.Emit<CallruntimeDefinefieldbyvalue>(node, 0, prop, obj);
627 }
628 
DefineFieldByIndex(const ir::AstNode * node,VReg obj,int64_t index)629 void PandaGen::DefineFieldByIndex(const ir::AstNode *node, VReg obj, int64_t index)
630 {
631     ra_.Emit<CallruntimeDefinefieldbyindex>(node, 0, index, obj);
632 }
633 
StOwnByName(const ir::AstNode * node,VReg obj,const util::StringView & prop,bool nameSetting)634 void PandaGen::StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop, bool nameSetting)
635 {
636     nameSetting ? ra_.Emit<Stownbynamewithnameset>(node, 0, prop, obj) :
637                   ra_.Emit<Stownbyname>(node, 0, prop, obj);
638     strings_.insert(prop);
639 }
640 
StOwnByValue(const ir::AstNode * node,VReg obj,VReg prop,bool nameSetting)641 void PandaGen::StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop, bool nameSetting)
642 {
643     nameSetting ? ra_.Emit<Stownbyvaluewithnameset>(node, 0, obj, prop) :
644                   ra_.Emit<Stownbyvalue>(node, 0, obj, prop);
645 }
646 
StOwnByIndex(const ir::AstNode * node,VReg obj,int64_t index)647 void PandaGen::StOwnByIndex(const ir::AstNode *node, VReg obj, int64_t index)
648 {
649     if (index <= util::Helpers::MAX_INT16) {
650         ra_.Emit<Stownbyindex>(node, 0, obj, index);
651         return;
652     }
653 
654     ra_.Emit<WideStownbyindex>(node, obj, index);
655 }
656 
DeleteObjProperty(const ir::AstNode * node,VReg obj,const Operand & prop)657 void PandaGen::DeleteObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
658 {
659     if (std::holds_alternative<VReg>(prop)) {
660         LoadAccumulator(node, std::get<VReg>(prop));
661     } else if (std::holds_alternative<int64_t>(prop)) {
662         LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop)));
663     } else {
664         ASSERT(std::holds_alternative<util::StringView>(prop));
665         LoadAccumulatorString(node, std::get<util::StringView>(prop));
666     }
667 
668     ra_.Emit<Delobjprop>(node, obj); // property is load to acc
669 }
670 
LoadAccumulator(const ir::AstNode * node,VReg reg)671 void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg)
672 {
673     ra_.Emit<Lda>(node, reg);
674 }
675 
LoadGlobalVar(const ir::AstNode * node,const util::StringView & name)676 void PandaGen::LoadGlobalVar(const ir::AstNode *node, const util::StringView &name)
677 {
678     ra_.Emit<Ldglobalvar>(node, 0, name);
679     strings_.insert(name);
680 }
681 
StoreGlobalVar(const ir::AstNode * node,const util::StringView & name)682 void PandaGen::StoreGlobalVar(const ir::AstNode *node, const util::StringView &name)
683 {
684     ra_.Emit<Stglobalvar>(node, 0, name);
685     strings_.insert(name);
686 }
687 
LoadAccFromLexEnv(const ir::AstNode * node,const binder::ScopeFindResult & result)688 void PandaGen::LoadAccFromLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result)
689 {
690     VirtualLoadVar::Expand(this, node, result);
691 }
692 
StoreAccToLexEnv(const ir::AstNode * node,const binder::ScopeFindResult & result,bool isDeclaration)693 void PandaGen::StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration)
694 {
695     VirtualStoreVar::Expand(this, node, result, isDeclaration);
696 }
697 
LoadAccumulatorString(const ir::AstNode * node,const util::StringView & str)698 void PandaGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str)
699 {
700     ra_.Emit<LdaStr>(node, str);
701     strings_.insert(str);
702 }
703 
LoadAccumulatorFloat(const ir::AstNode * node,double num)704 void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num)
705 {
706     ra_.Emit<Fldai>(node, num);
707 }
708 
LoadAccumulatorInt(const ir::AstNode * node,int32_t num)709 void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num)
710 {
711     ra_.Emit<Ldai>(node, num);
712 }
713 
LoadAccumulatorInt(const ir::AstNode * node,size_t num)714 void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num)
715 {
716     ra_.Emit<Ldai>(node, static_cast<int64_t>(num));
717 }
718 
LoadAccumulatorBigInt(const ir::AstNode * node,const util::StringView & num)719 void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &num)
720 {
721     ra_.Emit<Ldbigint>(node, num);
722     strings_.insert(num);
723 }
724 
StoreConst(const ir::AstNode * node,VReg reg,Constant id)725 void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id)
726 {
727     LoadConst(node, id);
728     StoreAccumulator(node, reg);
729 }
730 
LoadConst(const ir::AstNode * node,Constant id)731 void PandaGen::LoadConst(const ir::AstNode *node, Constant id)
732 {
733     switch (id) {
734         case Constant::JS_HOLE: {
735             ra_.Emit<Ldhole>(node);
736             break;
737         }
738         case Constant::JS_NAN: {
739             ra_.Emit<Ldnan>(node);
740             break;
741         }
742         case Constant::JS_INFINITY: {
743             ra_.Emit<Ldinfinity>(node);
744             break;
745         }
746         case Constant::JS_GLOBAL: {
747             ra_.Emit<Ldglobal>(node);
748             break;
749         }
750         case Constant::JS_UNDEFINED: {
751             ra_.Emit<Ldundefined>(node);
752             break;
753         }
754         case Constant::JS_SYMBOL: {
755             ra_.Emit<Ldsymbol>(node);
756             break;
757         }
758         case Constant::JS_NULL: {
759             ra_.Emit<Ldnull>(node);
760             break;
761         }
762         case Constant::JS_TRUE: {
763             ra_.Emit<Ldtrue>(node);
764             break;
765         }
766         case Constant::JS_FALSE: {
767             ra_.Emit<Ldfalse>(node);
768             break;
769         }
770         default: {
771             UNREACHABLE();
772         }
773     }
774 }
775 
MoveVreg(const ir::AstNode * node,VReg vd,VReg vs)776 void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs)
777 {
778     ra_.Emit<Mov>(node, vd, vs);
779 }
780 
SetLabel(const ir::AstNode * node,Label * label)781 void PandaGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label)
782 {
783     ra_.AddLabel(label);
784 }
785 
Branch(const ir::AstNode * node,Label * label)786 void PandaGen::Branch(const ir::AstNode *node, Label *label)
787 {
788     ra_.Emit<Jmp>(node, label);
789 }
790 
CheckControlFlowChange() const791 bool PandaGen::CheckControlFlowChange() const
792 {
793     const auto *iter = dynamicContext_;
794 
795     while (iter) {
796         if (iter->HasFinalizer()) {
797             return true;
798         }
799 
800         iter = iter->Prev();
801     }
802 
803     return false;
804 }
805 
ControlFlowChangeBreak(const ir::Identifier * label)806 Label *PandaGen::ControlFlowChangeBreak(const ir::Identifier *label)
807 {
808     auto *iter = dynamicContext_;
809 
810     util::StringView labelName = label ? label->Name() : LabelTarget::BREAK_LABEL;
811     Label *breakTarget = nullptr;
812 
813     while (iter) {
814         iter->AbortContext(ControlFlowChange::BREAK, labelName);
815 
816         const auto &labelTargetName = iter->Target().BreakLabel();
817 
818         if (iter->Target().BreakTarget()) {
819             breakTarget = iter->Target().BreakTarget();
820         }
821 
822         if (labelTargetName == labelName) {
823             break;
824         }
825 
826         iter = iter->Prev();
827     }
828 
829     return breakTarget;
830 }
831 
ControlFlowChangeContinue(const ir::Identifier * label)832 Label *PandaGen::ControlFlowChangeContinue(const ir::Identifier *label)
833 {
834     auto *iter = dynamicContext_;
835     util::StringView labelName = label ? label->Name() : LabelTarget::CONTINUE_LABEL;
836     Label *continueTarget = nullptr;
837 
838     while (iter) {
839         iter->AbortContext(ControlFlowChange::CONTINUE, labelName);
840 
841         const auto &labelTargetName = iter->Target().ContinueLabel();
842 
843         if (iter->Target().ContinueTarget()) {
844             continueTarget = iter->Target().ContinueTarget();
845         }
846 
847         if (labelTargetName == labelName) {
848             break;
849         }
850 
851         iter = iter->Prev();
852     }
853 
854     return continueTarget;
855 }
856 
ControlFlowChangeReturn()857 void PandaGen::ControlFlowChangeReturn()
858 {
859     auto *iter = dynamicContext_;
860     while (iter) {
861         iter->AbortContext(ControlFlowChange::BREAK, LabelTarget::RETURN_LABEL);
862         iter = iter->Prev();
863     }
864 }
865 
Condition(const ir::AstNode * node,lexer::TokenType op,VReg lhs,Label * ifFalse)866 void PandaGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse)
867 {
868     switch (op) {
869         case lexer::TokenType::PUNCTUATOR_EQUAL: {
870             Equal(node, lhs);
871             break;
872         }
873         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
874             NotEqual(node, lhs);
875             break;
876         }
877         case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: {
878             StrictEqual(node, lhs);
879             break;
880         }
881         case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
882             StrictNotEqual(node, lhs);
883             break;
884         }
885         case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
886             LessThan(node, lhs);
887             break;
888         }
889         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: {
890             LessEqual(node, lhs);
891             break;
892         }
893         case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
894             GreaterThan(node, lhs);
895             break;
896         }
897         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
898             GreaterEqual(node, lhs);
899             break;
900         }
901         default: {
902             UNREACHABLE();
903         }
904     }
905 
906     ra_.Emit<Jeqz>(node, ifFalse);
907 }
908 
Unary(const ir::AstNode * node,lexer::TokenType op,VReg operand)909 void PandaGen::Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand)
910 {
911     switch (op) {
912         case lexer::TokenType::PUNCTUATOR_PLUS: {
913             ToNumber(node, operand);
914             break;
915         }
916         case lexer::TokenType::PUNCTUATOR_MINUS: {
917             LoadAccumulator(node, operand);
918             ra_.Emit<Neg>(node, 0);
919             break;
920         }
921         case lexer::TokenType::PUNCTUATOR_TILDE: {
922             LoadAccumulator(node, operand);
923             ra_.Emit<Not>(node, 0);
924             break;
925         }
926         case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
927             Negate(node);
928             break;
929         }
930         case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: {
931             LoadAccumulator(node, operand);
932             ra_.Emit<Inc>(node, 0);
933             break;
934         }
935         case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: {
936             LoadAccumulator(node, operand);
937             ra_.Emit<Dec>(node, 0);
938             break;
939         }
940         case lexer::TokenType::KEYW_VOID:
941         case lexer::TokenType::KEYW_DELETE: {
942             LoadConst(node, Constant::JS_UNDEFINED);
943             break;
944         }
945         default: {
946             UNREACHABLE();
947         }
948     }
949 }
950 
Binary(const ir::AstNode * node,lexer::TokenType op,VReg lhs)951 void PandaGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs)
952 {
953     switch (op) {
954         case lexer::TokenType::PUNCTUATOR_EQUAL: {
955             Equal(node, lhs);
956             break;
957         }
958         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
959             NotEqual(node, lhs);
960             break;
961         }
962         case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: {
963             StrictEqual(node, lhs);
964             break;
965         }
966         case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
967             StrictNotEqual(node, lhs);
968             break;
969         }
970         case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
971             LessThan(node, lhs);
972             break;
973         }
974         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: {
975             LessEqual(node, lhs);
976             break;
977         }
978         case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
979             GreaterThan(node, lhs);
980             break;
981         }
982         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
983             GreaterEqual(node, lhs);
984             break;
985         }
986         case lexer::TokenType::PUNCTUATOR_PLUS:
987         case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
988             ra_.Emit<Add2>(node, 0, lhs);
989             break;
990         }
991         case lexer::TokenType::PUNCTUATOR_MINUS:
992         case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: {
993             ra_.Emit<Sub2>(node, 0, lhs);
994             break;
995         }
996         case lexer::TokenType::PUNCTUATOR_MULTIPLY:
997         case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: {
998             ra_.Emit<Mul2>(node, 0, lhs);
999             break;
1000         }
1001         case lexer::TokenType::PUNCTUATOR_DIVIDE:
1002         case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: {
1003             ra_.Emit<Div2>(node, 0, lhs);
1004             break;
1005         }
1006         case lexer::TokenType::PUNCTUATOR_MOD:
1007         case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: {
1008             ra_.Emit<Mod2>(node, 0, lhs);
1009             break;
1010         }
1011         case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
1012         case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: {
1013             ra_.Emit<Exp>(node, 0, lhs);
1014             break;
1015         }
1016         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
1017         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: {
1018             ra_.Emit<Shl2>(node, 0, lhs);
1019             break;
1020         }
1021         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
1022         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: {
1023             ra_.Emit<Ashr2>(node, 0, lhs);
1024             break;
1025         }
1026         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
1027         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: {
1028             ra_.Emit<Shr2>(node, 0, lhs);
1029             break;
1030         }
1031         case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
1032         case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: {
1033             ra_.Emit<And2>(node, 0, lhs);
1034             break;
1035         }
1036         case lexer::TokenType::PUNCTUATOR_BITWISE_OR:
1037         case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
1038             ra_.Emit<Or2>(node, 0, lhs);
1039             break;
1040         }
1041         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
1042         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: {
1043             ra_.Emit<Xor2>(node, 0, lhs);
1044             break;
1045         }
1046         case lexer::TokenType::KEYW_IN: {
1047             ra_.Emit<Isin>(node, 0, lhs);
1048             break;
1049         }
1050         case lexer::TokenType::KEYW_INSTANCEOF: {
1051             ra_.Emit<Instanceof>(node, 0, lhs);
1052             break;
1053         }
1054         default: {
1055             UNREACHABLE();
1056         }
1057     }
1058 }
1059 
Equal(const ir::AstNode * node,VReg lhs)1060 void PandaGen::Equal(const ir::AstNode *node, VReg lhs)
1061 {
1062     ra_.Emit<Eq>(node, 0, lhs);
1063 }
1064 
NotEqual(const ir::AstNode * node,VReg lhs)1065 void PandaGen::NotEqual(const ir::AstNode *node, VReg lhs)
1066 {
1067     ra_.Emit<Noteq>(node, 0, lhs);
1068 }
1069 
StrictEqual(const ir::AstNode * node,VReg lhs)1070 void PandaGen::StrictEqual(const ir::AstNode *node, VReg lhs)
1071 {
1072     ra_.Emit<Stricteq>(node, 0, lhs);
1073 }
1074 
StrictNotEqual(const ir::AstNode * node,VReg lhs)1075 void PandaGen::StrictNotEqual(const ir::AstNode *node, VReg lhs)
1076 {
1077     ra_.Emit<Strictnoteq>(node, 0, lhs);
1078 }
1079 
LessThan(const ir::AstNode * node,VReg lhs)1080 void PandaGen::LessThan(const ir::AstNode *node, VReg lhs)
1081 {
1082     ra_.Emit<Less>(node, 0, lhs);
1083 }
1084 
LessEqual(const ir::AstNode * node,VReg lhs)1085 void PandaGen::LessEqual(const ir::AstNode *node, VReg lhs)
1086 {
1087     ra_.Emit<Lesseq>(node, 0, lhs);
1088 }
1089 
GreaterThan(const ir::AstNode * node,VReg lhs)1090 void PandaGen::GreaterThan(const ir::AstNode *node, VReg lhs)
1091 {
1092     ra_.Emit<Greater>(node, 0, lhs);
1093 }
1094 
GreaterEqual(const ir::AstNode * node,VReg lhs)1095 void PandaGen::GreaterEqual(const ir::AstNode *node, VReg lhs)
1096 {
1097     ra_.Emit<Greatereq>(node, 0, lhs);
1098 }
1099 
IsTrue(const ir::AstNode * node)1100 void PandaGen::IsTrue(const ir::AstNode *node)
1101 {
1102     if (util::Helpers::IsDefaultApiVersion(Binder()->Program()->TargetApiVersion(),
1103         Binder()->Program()->GetTargetApiSubVersion())) {
1104         ra_.Emit<Istrue>(node);
1105         return;
1106     }
1107 
1108     ra_.Emit<CallruntimeIstrue>(node, 0);
1109 }
1110 
BranchIfUndefined(const ir::AstNode * node,Label * target)1111 void PandaGen::BranchIfUndefined(const ir::AstNode *node, Label *target)
1112 {
1113     RegScope rs(this);
1114     VReg tmp = AllocReg();
1115     StoreAccumulator(node, tmp);
1116     LoadConst(node, Constant::JS_UNDEFINED);
1117     Equal(node, tmp);
1118     ra_.Emit<Jnez>(node, target);
1119 }
1120 
BranchIfStrictUndefined(const ir::AstNode * node,class Label * target)1121 void PandaGen::BranchIfStrictUndefined(const ir::AstNode *node, class Label *target)
1122 {
1123     RegScope rs(this);
1124     VReg tmp = AllocReg();
1125     StoreAccumulator(node, tmp);
1126     LoadConst(node, Constant::JS_UNDEFINED);
1127     StrictEqual(node, tmp);
1128     ra_.Emit<Jnez>(node, target);
1129 }
1130 
BranchIfNotUndefined(const ir::AstNode * node,Label * target)1131 void PandaGen::BranchIfNotUndefined(const ir::AstNode *node, Label *target)
1132 {
1133     RegScope rs(this);
1134     VReg tmp = AllocReg();
1135     StoreAccumulator(node, tmp);
1136     LoadConst(node, Constant::JS_UNDEFINED);
1137     Equal(node, tmp);
1138     ra_.Emit<Jeqz>(node, target);
1139 }
1140 
BranchIfStrictNotUndefined(const ir::AstNode * node,class Label * target)1141 void PandaGen::BranchIfStrictNotUndefined(const ir::AstNode *node, class Label *target)
1142 {
1143     RegScope rs(this);
1144     VReg tmp = AllocReg();
1145     StoreAccumulator(node, tmp);
1146     LoadConst(node, Constant::JS_UNDEFINED);
1147     StrictEqual(node, tmp);
1148     ra_.Emit<Jeqz>(node, target);
1149 }
1150 
BranchIfTrue(const ir::AstNode * node,Label * target)1151 void PandaGen::BranchIfTrue(const ir::AstNode *node, Label *target)
1152 {
1153     IsTrue(node);
1154     ra_.Emit<Jnez>(node, target);
1155 }
1156 
BranchIfNotTrue(const ir::AstNode * node,Label * target)1157 void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target)
1158 {
1159     IsTrue(node);
1160     BranchIfFalse(node, target);
1161 }
1162 
BranchIfFalse(const ir::AstNode * node,Label * target)1163 void PandaGen::BranchIfFalse(const ir::AstNode *node, Label *target)
1164 {
1165     if (util::Helpers::IsDefaultApiVersion(Binder()->Program()->TargetApiVersion(),
1166         Binder()->Program()->GetTargetApiSubVersion())) {
1167         ra_.Emit<Isfalse>(node);
1168         ra_.Emit<Jnez>(node, target);
1169         return;
1170     }
1171 
1172     ra_.Emit<CallruntimeIsfalse>(node, 0);
1173     ra_.Emit<Jnez>(node, target);
1174 }
1175 
BranchIfStrictNull(const ir::AstNode * node,class Label * target)1176 void PandaGen::BranchIfStrictNull(const ir::AstNode *node, class Label *target)
1177 {
1178     RegScope rs(this);
1179     VReg tmp = AllocReg();
1180     StoreAccumulator(node, tmp);
1181     LoadConst(node, Constant::JS_NULL);
1182     ra_.Emit<Stricteq>(node, 0, tmp);
1183     ra_.Emit<Jnez>(node, target);
1184 }
1185 
EmitThrow(const ir::AstNode * node)1186 void PandaGen::EmitThrow(const ir::AstNode *node)
1187 {
1188     ra_.Emit<Throw>(node);
1189 }
1190 
EmitRethrow(const ir::AstNode * node)1191 void PandaGen::EmitRethrow(const ir::AstNode *node)
1192 {
1193     RegScope rs(this);
1194     auto *skipThrow = AllocLabel();
1195     auto *doThrow = AllocLabel();
1196 
1197     VReg exception = AllocReg();
1198     StoreAccumulator(node, exception);
1199 
1200     VReg hole = AllocReg();
1201     StoreConst(node, hole, Constant::JS_HOLE);
1202 
1203     LoadAccumulator(node, exception);
1204     NotEqual(node, hole);
1205     ra_.Emit<Jeqz>(node, skipThrow);
1206 
1207     SetLabel(node, doThrow);
1208     LoadAccumulator(node, exception);
1209     EmitThrow(node);
1210 
1211     SetLabel(node, skipThrow);
1212 }
1213 
EmitReturn(const ir::AstNode * node)1214 void PandaGen::EmitReturn(const ir::AstNode *node)
1215 {
1216     ra_.Emit<Return>(node);
1217 }
1218 
EmitReturnUndefined(const ir::AstNode * node)1219 void PandaGen::EmitReturnUndefined(const ir::AstNode *node)
1220 {
1221     ra_.Emit<Returnundefined>(node);
1222 }
1223 
ImplicitReturn(const ir::AstNode * node)1224 void PandaGen::ImplicitReturn(const ir::AstNode *node)
1225 {
1226     builder_->ImplicitReturn(node);
1227 }
1228 
DirectReturn(const ir::AstNode * node)1229 void PandaGen::DirectReturn(const ir::AstNode *node)
1230 {
1231     builder_->DirectReturn(node);
1232 }
1233 
ExplicitReturn(const ir::AstNode * node)1234 void PandaGen::ExplicitReturn(const ir::AstNode *node)
1235 {
1236     builder_->ExplicitReturn(node);
1237 }
1238 
ValidateClassDirectReturn(const ir::AstNode * node)1239 void PandaGen::ValidateClassDirectReturn(const ir::AstNode *node)
1240 {
1241     const ir::ScriptFunction *func = util::Helpers::GetContainingFunction(node);
1242 
1243     if (!func || !func->IsConstructor()) {
1244         return;
1245     }
1246 
1247     RegScope rs(this);
1248     VReg value = AllocReg();
1249     StoreAccumulator(node, value);
1250 
1251     auto *notUndefined = AllocLabel();
1252     auto *condEnd = AllocLabel();
1253 
1254     BranchIfStrictNotUndefined(node, notUndefined);
1255     GetThis(func);
1256     ThrowIfSuperNotCorrectCall(func, 0);
1257     Branch(node, condEnd);
1258 
1259     SetLabel(node, notUndefined);
1260     LoadAccumulator(node, value);
1261 
1262     SetLabel(node, condEnd);
1263 }
1264 
EmitAwait(const ir::AstNode * node)1265 void PandaGen::EmitAwait(const ir::AstNode *node)
1266 {
1267     builder_->Await(node);
1268 }
1269 
CallThis(const ir::AstNode * node,VReg startReg,size_t argCount)1270 void PandaGen::CallThis(const ir::AstNode *node, VReg startReg, size_t argCount)
1271 {
1272     LoadAccumulator(node, startReg); // callee is load to acc
1273     VReg thisReg = startReg + 1; // This dependency is used in other places, do not modify.
1274     switch (argCount) {
1275         case 1: { // no args
1276             ra_.Emit<Callthis0>(node, 0, thisReg);
1277             break;
1278         }
1279         case 2: { // 1 arg
1280             VReg arg0 = thisReg + 1;
1281             ra_.Emit<Callthis1>(node, 0, thisReg, arg0);
1282             break;
1283         }
1284         case 3: { // 2 args
1285             VReg arg0 = thisReg + 1;
1286             VReg arg1 = arg0 + 1;
1287             ra_.Emit<Callthis2>(node, 0, thisReg, arg0, arg1);
1288             break;
1289         }
1290         case 4: { // 3 args
1291             VReg arg0 = thisReg + 1;
1292             VReg arg1 = arg0 + 1;
1293             VReg arg2 = arg1 + 1;
1294             ra_.Emit<Callthis3>(node, 0, thisReg, arg0, arg1, arg2);
1295             break;
1296         }
1297         default: {
1298             int64_t actualArgs = static_cast<int64_t>(argCount) - 1;
1299             if (actualArgs <= util::Helpers::MAX_INT8) {
1300                 ra_.EmitRange<Callthisrange>(node, argCount, 0, actualArgs, thisReg);
1301                 break;
1302             }
1303 
1304             ra_.EmitRange<WideCallthisrange>(node, argCount, actualArgs, thisReg);
1305             break;
1306         }
1307     }
1308 }
1309 
Call(const ir::AstNode * node,VReg startReg,size_t argCount)1310 void PandaGen::Call(const ir::AstNode *node, VReg startReg, size_t argCount)
1311 {
1312     LoadAccumulator(node, startReg); // callee is load to acc
1313     switch (argCount) {
1314         case 0: { // 0 args
1315             ra_.Emit<Callarg0>(node, 0);
1316             break;
1317         }
1318         case 1: { // 1 arg
1319             VReg arg0 = startReg + 1;
1320             ra_.Emit<Callarg1>(node, 0, arg0);
1321             break;
1322         }
1323         case 2: { // 2 args
1324             VReg arg0 = startReg + 1;
1325             VReg arg1 = arg0 + 1;
1326             ra_.Emit<Callargs2>(node, 0, arg0, arg1);
1327             break;
1328         }
1329         case 3: { // 3 args
1330             VReg arg0 = startReg + 1;
1331             VReg arg1 = arg0 + 1;
1332             VReg arg2 = arg1 + 1;
1333             ra_.Emit<Callargs3>(node, 0, arg0, arg1, arg2);
1334             break;
1335         }
1336         default: {
1337             VReg arg0 = startReg + 1;
1338             if (argCount <= util::Helpers::MAX_INT8) {
1339                 ra_.EmitRange<Callrange>(node, argCount, 0, argCount, arg0);
1340                 break;
1341             }
1342 
1343             ra_.EmitRange<WideCallrange>(node, argCount, argCount, arg0);
1344             break;
1345         }
1346     }
1347 }
1348 
SuperCall(const ir::AstNode * node,VReg startReg,size_t argCount)1349 void PandaGen::SuperCall(const ir::AstNode *node, VReg startReg, size_t argCount)
1350 {
1351     if (RootNode()->AsScriptFunction()->IsArrow()) {
1352         GetFunctionObject(node); // load funcobj to acc for super call in arrow function
1353         if (argCount <= util::Helpers::MAX_INT8) {
1354             ra_.EmitRange<Supercallarrowrange>(node, argCount, 0, static_cast<int64_t>(argCount), startReg);
1355         } else {
1356             ra_.EmitRange<WideSupercallarrowrange>(node, argCount, static_cast<int64_t>(argCount), startReg);
1357         }
1358         return;
1359     }
1360 
1361     if (argCount <= util::Helpers::MAX_INT8) {
1362         // no need to load funcobj to acc for super call in other kinds of functions
1363         ra_.EmitRange<Supercallthisrange>(node, argCount, 0, static_cast<int64_t>(argCount), startReg);
1364         return;
1365     }
1366 
1367     ra_.EmitRange<WideSupercallthisrange>(node, argCount, static_cast<int64_t>(argCount), startReg);
1368 }
1369 
SuperCallSpread(const ir::AstNode * node,VReg vs)1370 void PandaGen::SuperCallSpread(const ir::AstNode *node, VReg vs)
1371 {
1372     ra_.Emit<Supercallspread>(node, 0, vs);
1373 }
1374 
NotifyConcurrentResult(const ir::AstNode * node)1375 void PandaGen::NotifyConcurrentResult(const ir::AstNode *node)
1376 {
1377     if (IsConcurrent()) {
1378         ra_.Emit<CallruntimeNotifyconcurrentresult>(node);
1379     }
1380 }
1381 
CallInit(const ir::AstNode * node,VReg thisReg)1382 void PandaGen::CallInit(const ir::AstNode *node, VReg thisReg)
1383 {
1384     // callee is in acc
1385     ra_.Emit<CallruntimeCallinit>(node, 0, thisReg);
1386 }
1387 
NewObject(const ir::AstNode * node,VReg startReg,size_t argCount)1388 void PandaGen::NewObject(const ir::AstNode *node, VReg startReg, size_t argCount)
1389 {
1390     if (argCount <= util::Helpers::MAX_INT8) {
1391         ra_.EmitRange<Newobjrange>(node, argCount, 0, static_cast<int64_t>(argCount), startReg);
1392         return;
1393     }
1394 
1395     ra_.EmitRange<WideNewobjrange>(node, argCount, static_cast<int64_t>(argCount), startReg);
1396 }
1397 
DefineFunction(const ir::AstNode * node,const ir::ScriptFunction * realNode,const util::StringView & name)1398 void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name)
1399 {
1400     if (realNode->IsOverload() || realNode->Declare()) {
1401         return;
1402     }
1403 
1404     auto formalParamCnt = realNode->FormalParamsLength();
1405     if (realNode->IsMethod()) {
1406         ra_.Emit<Definemethod>(node, 0, name, static_cast<int64_t>(formalParamCnt));
1407     } else  {
1408         ra_.Emit<Definefunc>(node, 0, name, static_cast<int64_t>(formalParamCnt));
1409     }
1410 
1411     strings_.insert(name);
1412 }
1413 
TypeOf(const ir::AstNode * node)1414 void PandaGen::TypeOf(const ir::AstNode *node)
1415 {
1416     ra_.Emit<Typeof>(node, 0);
1417 }
1418 
CallSpread(const ir::AstNode * node,VReg func,VReg thisReg,VReg args)1419 void PandaGen::CallSpread(const ir::AstNode *node, VReg func, VReg thisReg, VReg args)
1420 {
1421     LoadAccumulator(node, func); // callee is load to acc
1422     ra_.Emit<Apply>(node, 0, thisReg, args);
1423 }
1424 
NewObjSpread(const ir::AstNode * node,VReg obj)1425 void PandaGen::NewObjSpread(const ir::AstNode *node, VReg obj)
1426 {
1427     ra_.Emit<Newobjapply>(node, 0, obj);
1428 }
1429 
GetUnmappedArgs(const ir::AstNode * node)1430 void PandaGen::GetUnmappedArgs(const ir::AstNode *node)
1431 {
1432     ra_.Emit<Getunmappedargs>(node);
1433 }
1434 
Negate(const ir::AstNode * node)1435 void PandaGen::Negate(const ir::AstNode *node)
1436 {
1437     auto *falseLabel = AllocLabel();
1438     auto *endLabel = AllocLabel();
1439     BranchIfTrue(node, falseLabel);
1440     LoadConst(node, Constant::JS_TRUE);
1441     Branch(node, endLabel);
1442     SetLabel(node, falseLabel);
1443     LoadConst(node, Constant::JS_FALSE);
1444     SetLabel(node, endLabel);
1445 }
1446 
ToNumber(const ir::AstNode * node,VReg arg)1447 void PandaGen::ToNumber(const ir::AstNode *node, VReg arg)
1448 {
1449     LoadAccumulator(node, arg);
1450     ra_.Emit<Tonumber>(node, 0);
1451 }
1452 
ToNumeric(const ir::AstNode * node,VReg arg)1453 void PandaGen::ToNumeric(const ir::AstNode *node, VReg arg)
1454 {
1455     LoadAccumulator(node, arg);
1456     ra_.Emit<Tonumeric>(node, 0);
1457 }
1458 
CreateGeneratorObj(const ir::AstNode * node,VReg funcObj)1459 void PandaGen::CreateGeneratorObj(const ir::AstNode *node, VReg funcObj)
1460 {
1461     ra_.Emit<Creategeneratorobj>(node, funcObj);
1462 }
1463 
CreateAsyncGeneratorObj(const ir::AstNode * node,VReg funcObj)1464 void PandaGen::CreateAsyncGeneratorObj(const ir::AstNode *node, VReg funcObj)
1465 {
1466     ra_.Emit<Createasyncgeneratorobj>(node, funcObj);
1467 }
1468 
CreateIterResultObject(const ir::AstNode * node,VReg value,VReg done)1469 void PandaGen::CreateIterResultObject(const ir::AstNode *node, VReg value, VReg done)
1470 {
1471     ra_.Emit<Createiterresultobj>(node, value, done);
1472 }
1473 
SuspendGenerator(const ir::AstNode * node,VReg genObj)1474 void PandaGen::SuspendGenerator(const ir::AstNode *node, VReg genObj)
1475 {
1476     ra_.Emit<Suspendgenerator>(node, genObj); // iterResult is in acc
1477 }
1478 
GeneratorYield(const ir::AstNode * node,VReg genObj)1479 void PandaGen::GeneratorYield(const ir::AstNode *node, VReg genObj)
1480 {
1481     LoadAccumulator(node, genObj);
1482     ra_.Emit<Setgeneratorstate>(node, static_cast<int32_t>(GeneratorState::SUSPENDED_YIELD));
1483 }
1484 
GeneratorComplete(const ir::AstNode * node,VReg genObj)1485 void PandaGen::GeneratorComplete(const ir::AstNode *node, VReg genObj)
1486 {
1487     LoadAccumulator(node, genObj);
1488     ra_.Emit<Setgeneratorstate>(node, static_cast<int32_t>(GeneratorState::COMPLETED));
1489 }
1490 
ResumeGenerator(const ir::AstNode * node,VReg genObj)1491 void PandaGen::ResumeGenerator(const ir::AstNode *node, VReg genObj)
1492 {
1493     LoadAccumulator(node, genObj);
1494     ra_.Emit<Resumegenerator>(node);
1495 }
1496 
GetResumeMode(const ir::AstNode * node,VReg genObj)1497 void PandaGen::GetResumeMode(const ir::AstNode *node, VReg genObj)
1498 {
1499     LoadAccumulator(node, genObj);
1500     ra_.Emit<Getresumemode>(node);
1501 }
1502 
AsyncFunctionEnter(const ir::AstNode * node)1503 void PandaGen::AsyncFunctionEnter(const ir::AstNode *node)
1504 {
1505     ra_.Emit<Asyncfunctionenter>(node);
1506 }
1507 
AsyncFunctionAwait(const ir::AstNode * node,VReg asyncFuncObj)1508 void PandaGen::AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj)
1509 {
1510     ra_.Emit<Asyncfunctionawaituncaught>(node, asyncFuncObj); // receivedValue is in acc
1511 }
1512 
AsyncFunctionResolve(const ir::AstNode * node,VReg asyncFuncObj)1513 void PandaGen::AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj)
1514 {
1515     ra_.Emit<Asyncfunctionresolve>(node, asyncFuncObj); // use retVal in acc
1516 }
1517 
AsyncFunctionReject(const ir::AstNode * node,VReg asyncFuncObj)1518 void PandaGen::AsyncFunctionReject(const ir::AstNode *node, VReg asyncFuncObj)
1519 {
1520     ra_.Emit<Asyncfunctionreject>(node, asyncFuncObj); // exception is in acc
1521 }
1522 
AsyncGeneratorResolve(const ir::AstNode * node,VReg asyncGenObj,VReg value,VReg canSuspend)1523 void PandaGen::AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj, VReg value, VReg canSuspend)
1524 {
1525     ra_.Emit<Asyncgeneratorresolve>(node, asyncGenObj, value, canSuspend);
1526 }
1527 
AsyncGeneratorReject(const ir::AstNode * node,VReg asyncGenObj)1528 void PandaGen::AsyncGeneratorReject(const ir::AstNode *node, VReg asyncGenObj)
1529 {
1530     ra_.Emit<Asyncgeneratorreject>(node, asyncGenObj); // value is in acc
1531 }
1532 
GetTemplateObject(const ir::AstNode * node,VReg value)1533 void PandaGen::GetTemplateObject(const ir::AstNode *node, VReg value)
1534 {
1535     LoadAccumulator(node, value);
1536     ra_.Emit<Gettemplateobject>(node, 0);
1537 }
1538 
CopyRestArgs(const ir::AstNode * node,uint32_t index)1539 void PandaGen::CopyRestArgs(const ir::AstNode *node, uint32_t index)
1540 {
1541     index <= util::Helpers::MAX_INT8 ? ra_.Emit<Copyrestargs>(node, index) : ra_.Emit<WideCopyrestargs>(node, index);
1542 }
1543 
GetPropIterator(const ir::AstNode * node)1544 void PandaGen::GetPropIterator(const ir::AstNode *node)
1545 {
1546     ra_.Emit<Getpropiterator>(node);
1547 }
1548 
GetNextPropName(const ir::AstNode * node,VReg iter)1549 void PandaGen::GetNextPropName(const ir::AstNode *node, VReg iter)
1550 {
1551     ra_.Emit<Getnextpropname>(node, iter);
1552 }
1553 
CreateEmptyObject(const ir::AstNode * node)1554 void PandaGen::CreateEmptyObject(const ir::AstNode *node)
1555 {
1556     ra_.Emit<Createemptyobject>(node);
1557 }
1558 
CreateObjectWithBuffer(const ir::AstNode * node,uint32_t idx)1559 void PandaGen::CreateObjectWithBuffer(const ir::AstNode *node, uint32_t idx)
1560 {
1561     ASSERT(util::Helpers::IsInteger<uint32_t>(idx));
1562     std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
1563     util::UString litId(idxStr, allocator_);
1564     ra_.Emit<Createobjectwithbuffer>(node, 0, litId.View());
1565 }
1566 
SetObjectWithProto(const ir::AstNode * node,VReg proto,VReg obj)1567 void PandaGen::SetObjectWithProto(const ir::AstNode *node, VReg proto, VReg obj)
1568 {
1569     LoadAccumulator(node, obj);
1570     ra_.Emit<Setobjectwithproto>(node, 0, proto);
1571 }
1572 
CopyDataProperties(const ir::AstNode * node,VReg dst)1573 void PandaGen::CopyDataProperties(const ir::AstNode *node, VReg dst)
1574 {
1575     ra_.Emit<Copydataproperties>(node, dst); // use acc as srcObj
1576 }
1577 
DefineGetterSetterByValue(const ir::AstNode * node,VReg obj,VReg name,VReg getter,VReg setter,bool setName)1578 void PandaGen::DefineGetterSetterByValue(const ir::AstNode *node, VReg obj, VReg name, VReg getter, VReg setter,
1579                                          bool setName)
1580 {
1581     LoadConst(node, setName ? Constant::JS_TRUE : Constant::JS_FALSE);
1582     ra_.Emit<Definegettersetterbyvalue>(node, obj, name, getter, setter);
1583 }
1584 
CreateEmptyArray(const ir::AstNode * node)1585 void PandaGen::CreateEmptyArray(const ir::AstNode *node)
1586 {
1587     ra_.Emit<Createemptyarray>(node, 0);
1588 }
1589 
CreateArrayWithBuffer(const ir::AstNode * node,uint32_t idx)1590 void PandaGen::CreateArrayWithBuffer(const ir::AstNode *node, uint32_t idx)
1591 {
1592     ASSERT(util::Helpers::IsInteger<uint32_t>(idx));
1593     std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
1594     util::UString litId(idxStr, allocator_);
1595     ra_.Emit<Createarraywithbuffer>(node, 0, litId.View());
1596 }
1597 
CreateArray(const ir::AstNode * node,const ArenaVector<ir::Expression * > & elements,VReg obj)1598 void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVector<ir::Expression *> &elements, VReg obj)
1599 {
1600     if (elements.empty()) {
1601         CreateEmptyArray(node);
1602         StoreAccumulator(node, obj);
1603         return;
1604     }
1605 
1606     auto *buf = NewLiteralBuffer();
1607 
1608     size_t i = 0;
1609     // This loop handles constant literal data by collecting it into a literal buffer
1610     // until a non-constant element is encountered.
1611     while (i < elements.size() && util::Helpers::IsConstantExpr(elements[i])) {
1612         buf->Add(elements[i]->AsLiteral());
1613         i++;
1614     }
1615 
1616     if (buf->IsEmpty()) {
1617         CreateEmptyArray(node);
1618     } else {
1619         uint32_t bufIdx = static_cast<uint32_t>(AddLiteralBuffer(buf));
1620         CreateArrayWithBuffer(node, bufIdx);
1621     }
1622 
1623     StoreAccumulator(node, obj);
1624 
1625     if (i == elements.size()) {
1626         return;
1627     }
1628 
1629     bool hasSpread = false;
1630 
1631     // This loop handles array elements until a spread element is encountered
1632     for (; i < elements.size(); i++) {
1633         const ir::Expression *elem = elements[i];
1634 
1635         if (elem->IsOmittedExpression()) {
1636             continue;
1637         }
1638 
1639         if (elem->IsSpreadElement()) {
1640             // The next loop will handle arrays that have a spread element
1641             hasSpread = true;
1642             break;
1643         }
1644 
1645         elem->Compile(this);
1646         StOwnByIndex(elem, obj, i);
1647     }
1648 
1649     RegScope rs(this);
1650     VReg idxReg {};
1651 
1652     if (hasSpread) {
1653         idxReg = AllocReg();
1654         LoadAccumulatorInt(node, i);
1655         StoreAccumulator(node, idxReg);
1656     }
1657 
1658     // This loop handles arrays that contain spread elements
1659     for (; i < elements.size(); i++) {
1660         const ir::Expression *elem = elements[i];
1661 
1662         if (elem->IsSpreadElement()) {
1663             elem->AsSpreadElement()->Argument()->Compile(this);
1664 
1665             StoreArraySpread(elem, obj, idxReg);
1666 
1667             LoadObjByName(node, obj, "length");
1668             StoreAccumulator(elem, idxReg);
1669             continue;
1670         }
1671 
1672         if (!elem->IsOmittedExpression()) {
1673             elem->Compile(this);
1674             StOwnByValue(elem, obj, idxReg);
1675         }
1676 
1677         Unary(elem, lexer::TokenType::PUNCTUATOR_PLUS_PLUS, idxReg);
1678         StoreAccumulator(elem, idxReg);
1679     }
1680 
1681     // If the last element is omitted, we also have to update the length property
1682     if (elements.back()->IsOmittedExpression()) {
1683         // if there was a spread value then acc already contains the length
1684         if (!hasSpread) {
1685             LoadAccumulatorInt(node, i);
1686         }
1687 
1688         StOwnByName(node, obj, "length");
1689     }
1690 
1691     LoadAccumulator(node, obj);
1692 }
1693 
StoreArraySpread(const ir::AstNode * node,VReg array,VReg index)1694 void PandaGen::StoreArraySpread(const ir::AstNode *node, VReg array, VReg index)
1695 {
1696     ra_.Emit<Starrayspread>(node, array, index);
1697 }
1698 
ThrowIfNotObject(const ir::AstNode * node,VReg obj)1699 void PandaGen::ThrowIfNotObject(const ir::AstNode *node, VReg obj)
1700 {
1701     ra_.Emit<ThrowIfnotobject>(node, obj);
1702 }
1703 
ThrowThrowNotExist(const ir::AstNode * node)1704 void PandaGen::ThrowThrowNotExist(const ir::AstNode *node)
1705 {
1706     ra_.Emit<ThrowNotexists>(node);
1707 }
1708 
GetIterator(const ir::AstNode * node)1709 void PandaGen::GetIterator(const ir::AstNode *node)
1710 {
1711     ra_.Emit<Getiterator>(node, 0);
1712 }
1713 
GetAsyncIterator(const ir::AstNode * node)1714 void PandaGen::GetAsyncIterator(const ir::AstNode *node)
1715 {
1716     ra_.Emit<Getasynciterator>(node, 0);
1717 }
1718 
CreateObjectWithExcludedKeys(const ir::AstNode * node,VReg obj,VReg argStart,size_t argCount)1719 void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount)
1720 {
1721     ASSERT(argStart == obj + 1);
1722     if (argCount == 0) {
1723         LoadConst(node, Constant::JS_UNDEFINED);
1724         StoreAccumulator(node, argStart);
1725     }
1726 
1727     size_t argRegCnt = (argCount == 0 ? argCount : argCount - 1);
1728 
1729     if (argRegCnt <= util::Helpers::MAX_INT8) {
1730         ra_.EmitRange<Createobjectwithexcludedkeys>(node, argCount, static_cast<int64_t>(argRegCnt), obj, argStart);
1731         return;
1732     }
1733 
1734     ra_.EmitRange<WideCreateobjectwithexcludedkeys>(node, argCount, static_cast<int64_t>(argRegCnt), obj, argStart);
1735 }
1736 
ThrowObjectNonCoercible(const ir::AstNode * node)1737 void PandaGen::ThrowObjectNonCoercible(const ir::AstNode *node)
1738 {
1739     ra_.Emit<ThrowPatternnoncoercible>(node);
1740 }
1741 
CloseIterator(const ir::AstNode * node,VReg iter)1742 void PandaGen::CloseIterator(const ir::AstNode *node, VReg iter)
1743 {
1744     ra_.Emit<Closeiterator>(node, 0, iter);
1745 }
1746 
DefineClassWithBuffer(const ir::AstNode * node,const util::StringView & ctorId,int32_t litIdx,VReg base)1747 void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg base)
1748 {
1749     auto formalParamCnt = node->AsClassDefinition()->Ctor()->Function()->FormalParamsLength();
1750     std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(litIdx);
1751     util::UString litId(idxStr, allocator_);
1752     ra_.Emit<Defineclasswithbuffer>(node, 0, ctorId, litId.View(), static_cast<int64_t>(formalParamCnt), base);
1753     strings_.insert(ctorId);
1754 }
1755 
DefineSendableClass(const ir::AstNode * node,const util::StringView & ctorId,int32_t litIdx,VReg base)1756 void PandaGen::DefineSendableClass(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg base)
1757 {
1758     auto formalParamCnt = node->AsClassDefinition()->Ctor()->Function()->FormalParamsLength();
1759     std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(litIdx);
1760     util::UString litId(idxStr, allocator_);
1761     ra_.Emit<CallruntimeDefinesendableclass>(node, 0, ctorId, litId.View(), static_cast<int64_t>(formalParamCnt), base);
1762     strings_.insert(ctorId);
1763 }
1764 
LoadSendableClass(const ir::AstNode * node,int32_t level)1765 void PandaGen::LoadSendableClass(const ir::AstNode *node, int32_t level)
1766 {
1767     ra_.Emit<CallruntimeLdsendableclass>(node, level);
1768 }
1769 
LoadLocalModuleVariable(const ir::AstNode * node,const binder::ModuleVariable * variable)1770 void PandaGen::LoadLocalModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable)
1771 {
1772     auto index = variable->Index();
1773     index <= util::Helpers::MAX_INT8 ? ra_.Emit<Ldlocalmodulevar>(node, index) :
1774                                        ra_.Emit<WideLdlocalmodulevar>(node, index);
1775 }
1776 
LoadExternalModuleVariable(const ir::AstNode * node,const binder::ModuleVariable * variable)1777 void PandaGen::LoadExternalModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable)
1778 {
1779     auto index = variable->Index();
1780 
1781     auto targetApiVersion = Binder()->Program()->TargetApiVersion();
1782     bool isLazy = variable->Declaration()->Node()->IsImportSpecifier() ?
1783         variable->Declaration()->Node()->AsImportSpecifier()->IsLazy() : false;
1784     if (isLazy) {
1785         // Change the behavior of using imported object in sendable class since api12
1786         if (inSendable_ && targetApiVersion >= util::Helpers::SENDABLE_LAZY_LOADING_MIN_SUPPORTED_API_VERSION) {
1787             index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdlazysendablemodulevar>(node, index) :
1788                                                ra_.Emit<CallruntimeWideldlazysendablemodulevar>(node, index);
1789             return;
1790         }
1791 
1792         index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdlazymodulevar>(node, index) :
1793                                            ra_.Emit<CallruntimeWideldlazymodulevar>(node, index);
1794         return;
1795     }
1796 
1797     // Change the behavior of using imported object in sendable class since api12
1798     if (inSendable_ && targetApiVersion >= util::Helpers::SENDABLE_LAZY_LOADING_MIN_SUPPORTED_API_VERSION) {
1799         index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdsendableexternalmodulevar>(node, index) :
1800                                            ra_.Emit<CallruntimeWideldsendableexternalmodulevar>(node, index);
1801         return;
1802     }
1803 
1804     index <= util::Helpers::MAX_INT8 ? ra_.Emit<Ldexternalmodulevar>(node, index) :
1805                                        ra_.Emit<WideLdexternalmodulevar>(node, index);
1806 }
1807 
StoreModuleVariable(const ir::AstNode * node,const binder::ModuleVariable * variable)1808 void PandaGen::StoreModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable)
1809 {
1810     auto index = variable->Index();
1811     index <= util::Helpers::MAX_INT8 ? ra_.Emit<Stmodulevar>(node, index) :
1812                                        ra_.Emit<WideStmodulevar>(node, index);
1813 }
1814 
GetModuleNamespace(const ir::AstNode * node,uint32_t index)1815 void PandaGen::GetModuleNamespace(const ir::AstNode *node, uint32_t index)
1816 {
1817     index <= util::Helpers::MAX_INT8 ? ra_.Emit<Getmodulenamespace>(node, index) :
1818                                        ra_.Emit<WideGetmodulenamespace>(node, index);
1819 }
1820 
DynamicImportCall(const ir::AstNode * node)1821 void PandaGen::DynamicImportCall(const ir::AstNode *node)
1822 {
1823     ra_.Emit<Dynamicimport>(node);
1824 }
1825 
StSuperByName(const ir::AstNode * node,VReg obj,const util::StringView & key)1826 void PandaGen::StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key)
1827 {
1828     ra_.Emit<Stsuperbyname>(node, 0, key, obj);
1829     strings_.insert(key);
1830 }
1831 
LdSuperByName(const ir::AstNode * node,VReg obj,const util::StringView & key)1832 void PandaGen::LdSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key)
1833 {
1834     LoadAccumulator(node, obj); // object is load to acc
1835     ra_.Emit<Ldsuperbyname>(node, 0, key);
1836     strings_.insert(key);
1837 }
1838 
StSuperByValue(const ir::AstNode * node,VReg obj,VReg prop)1839 void PandaGen::StSuperByValue(const ir::AstNode *node, VReg obj, VReg prop)
1840 {
1841     ra_.Emit<Stsuperbyvalue>(node, 0, obj, prop);
1842 }
1843 
LdSuperByValue(const ir::AstNode * node,VReg obj)1844 void PandaGen::LdSuperByValue(const ir::AstNode *node, VReg obj)
1845 {
1846     ra_.Emit<Ldsuperbyvalue>(node, 0, obj); // prop is in acc
1847 }
1848 
StoreSuperProperty(const ir::AstNode * node,VReg obj,const Operand & prop)1849 void PandaGen::StoreSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
1850 {
1851     if (std::holds_alternative<util::StringView>(prop)) {
1852         StSuperByName(node, obj, std::get<util::StringView>(prop));
1853         return;
1854     }
1855 
1856     if (std::holds_alternative<VReg>(prop)) {
1857         StSuperByValue(node, obj, std::get<VReg>(prop));
1858         return;
1859     }
1860 
1861     ASSERT(std::holds_alternative<int64_t>(prop));
1862     RegScope rs(this);
1863     VReg property = AllocReg();
1864     VReg value = AllocReg();
1865 
1866     StoreAccumulator(node, value);
1867     LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop)));
1868     StoreAccumulator(node, property);
1869     LoadAccumulator(node, value);
1870     StSuperByValue(node, obj, property);
1871 }
1872 
LoadSuperProperty(const ir::AstNode * node,VReg obj,const Operand & prop)1873 void PandaGen::LoadSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
1874 {
1875     if (std::holds_alternative<util::StringView>(prop)) {
1876         LdSuperByName(node, obj, std::get<util::StringView>(prop));
1877         return;
1878     }
1879 
1880     if (std::holds_alternative<VReg>(prop)) {
1881         LoadAccumulator(node, std::get<VReg>(prop));
1882         LdSuperByValue(node, obj);
1883         return;
1884     }
1885 
1886     ASSERT(std::holds_alternative<int64_t>(prop));
1887 
1888     LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop)));
1889     LdSuperByValue(node, obj);
1890 }
1891 
LoadLexicalVar(const ir::AstNode * node,uint32_t level,uint32_t slot)1892 void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1893 {
1894     if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1895         ra_.Emit<WideLdlexvar>(node, level, slot);
1896         return;
1897     }
1898 
1899     ra_.Emit<Ldlexvar>(node, level, slot);
1900 }
1901 
LoadSendableVar(const ir::AstNode * node,uint32_t level,uint32_t slot)1902 void PandaGen::LoadSendableVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1903 {
1904     if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1905         ra_.Emit<CallruntimeWideldsendablevar>(node, level, slot);
1906         return;
1907     }
1908 
1909     ra_.Emit<CallruntimeLdsendablevar>(node, level, slot);
1910 }
1911 
LoadLexicalVar(const ir::AstNode * node,uint32_t level,uint32_t slot,const util::StringView & name)1912 void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, const util::StringView &name)
1913 {
1914     if (context_->PatchFixHelper() && context_->PatchFixHelper()->IsAdditionalVarInPatch(slot)) {
1915         uint32_t patchSlot = context_->PatchFixHelper()->GetPatchLexicalIdx(std::string(name));
1916         ra_.Emit<WideLdpatchvar>(node, patchSlot);
1917         return;
1918     }
1919 
1920     if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1921         ra_.Emit<WideLdlexvar>(node, level, slot);
1922         return;
1923     }
1924 
1925     ra_.Emit<Ldlexvar>(node, level, slot);
1926 }
1927 
StoreLexicalVar(const ir::AstNode * node,uint32_t level,uint32_t slot)1928 void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1929 {
1930     if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1931         ra_.Emit<WideStlexvar>(node, level, slot);
1932         return;
1933     }
1934 
1935     ra_.Emit<Stlexvar>(node, level, slot);
1936 }
1937 
StoreLexicalVar(const ir::AstNode * node,uint32_t level,uint32_t slot,VReg value)1938 void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg value)
1939 {
1940     LoadAccumulator(node, value);
1941     if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1942         ra_.Emit<WideStlexvar>(node, level, slot);
1943         return;
1944     }
1945 
1946     ra_.Emit<Stlexvar>(node, level, slot);
1947 }
1948 
StoreSendableVar(const ir::AstNode * node,uint32_t level,uint32_t slot)1949 void PandaGen::StoreSendableVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1950 {
1951     if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1952         ra_.Emit<CallruntimeWidestsendablevar>(node, level, slot);
1953         return;
1954     }
1955 
1956     ra_.Emit<CallruntimeStsendablevar>(node, level, slot);
1957 }
1958 
StoreLexicalVar(const ir::AstNode * node,uint32_t level,uint32_t slot,const binder::LocalVariable * local)1959 void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot,
1960     const binder::LocalVariable *local)
1961 {
1962     if (context_->PatchFixHelper() && context_->PatchFixHelper()->IsAdditionalVarInPatch(slot)) {
1963         uint32_t patchSlot = context_->PatchFixHelper()->GetPatchLexicalIdx(std::string(local->Name()));
1964         ra_.Emit<WideStpatchvar>(node, patchSlot);
1965         return;
1966     }
1967     RegScope rs(this);
1968     VReg value = AllocReg();
1969     StoreAccumulator(node, value);
1970     StoreLexicalVar(node, level, slot, value);
1971 }
1972 
ThrowIfSuperNotCorrectCall(const ir::AstNode * node,int64_t num)1973 void PandaGen::ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num)
1974 {
1975     ra_.Emit<ThrowIfsupernotcorrectcall>(node, num);
1976 }
1977 
ThrowUndefinedIfHole(const ir::AstNode * node,const util::StringView & name)1978 void PandaGen::ThrowUndefinedIfHole(const ir::AstNode *node, const util::StringView &name)
1979 {
1980     ra_.Emit<ThrowUndefinedifholewithname>(node, name);
1981     strings_.insert(name);
1982 }
1983 
ThrowConstAssignment(const ir::AstNode * node,const util::StringView & name)1984 void PandaGen::ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name)
1985 {
1986     RegScope rs(this);
1987     LoadAccumulatorString(node, name);
1988     VReg nameReg = AllocReg();
1989     StoreAccumulator(node, nameReg);
1990     ra_.Emit<ThrowConstassignment>(node, nameReg);
1991     strings_.insert(name);
1992 }
1993 
PopLexEnv(const ir::AstNode * node)1994 void PandaGen::PopLexEnv(const ir::AstNode *node)
1995 {
1996     ra_.Emit<Poplexenv>(node);
1997 }
1998 
GenDebugger(const ir::AstNode * node)1999 void PandaGen::GenDebugger(const ir::AstNode *node)
2000 {
2001     if (IsDebug()) {
2002         ra_.Emit<Debugger>(node);
2003     }
2004 }
2005 
NewLexicalEnv(const ir::AstNode * node,uint32_t num,binder::VariableScope * scope)2006 void PandaGen::NewLexicalEnv(const ir::AstNode *node, uint32_t num, binder::VariableScope *scope)
2007 {
2008     if (IsDebug()) {
2009         int32_t scopeInfoIdx = AddLexicalVarNamesForDebugInfo(scope->GetLexicalVarNameAndTypes());
2010         NewLexEnvWithScopeInfo(node, num, scopeInfoIdx);
2011         return;
2012     }
2013 
2014     NewLexEnv(node, num);
2015 }
2016 
NewLexEnv(const ir::AstNode * node,uint32_t num)2017 void PandaGen::NewLexEnv(const ir::AstNode *node, uint32_t num)
2018 {
2019     num <= util::Helpers::MAX_INT8 ? ra_.Emit<Newlexenv>(node, num) : ra_.Emit<WideNewlexenv>(node, num);
2020 }
2021 
NewSendableEnv(const ir::AstNode * node,uint32_t num)2022 void PandaGen::NewSendableEnv(const ir::AstNode * node, uint32_t num)
2023 {
2024     num <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeNewsendableenv>(node, num) :
2025         ra_.Emit<CallruntimeWidenewsendableenv>(node, num);
2026 }
2027 
NewLexEnvWithScopeInfo(const ir::AstNode * node,uint32_t num,int32_t scopeInfoIdx)2028 void PandaGen::NewLexEnvWithScopeInfo(const ir::AstNode *node, uint32_t num, int32_t scopeInfoIdx)
2029 {
2030     std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(scopeInfoIdx);
2031     util::UString litId(idxStr, allocator_);
2032     num <= util::Helpers::MAX_INT8 ? ra_.Emit<Newlexenvwithname>(node, num, litId.View()) :
2033                                      ra_.Emit<WideNewlexenvwithname>(node, num, litId.View());
2034 }
2035 
TryDepth() const2036 uint32_t PandaGen::TryDepth() const
2037 {
2038     const auto *iter = dynamicContext_;
2039     uint32_t depth = 0;
2040 
2041     while (iter) {
2042         if (iter->HasTryCatch()) {
2043             depth++;
2044         }
2045 
2046         iter = iter->Prev();
2047     }
2048 
2049     return depth;
2050 }
2051 
CreateCatchTable()2052 CatchTable *PandaGen::CreateCatchTable()
2053 {
2054     auto *catchTable = allocator_->New<CatchTable>(this, TryDepth());
2055     CHECK_NOT_NULL(catchTable);
2056     catchList_.push_back(catchTable);
2057     return catchTable;
2058 }
2059 
SortCatchTables()2060 void PandaGen::SortCatchTables()
2061 {
2062     std::sort(catchList_.begin(), catchList_.end(),
2063               [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); });
2064 }
2065 
ToNamedPropertyKey(const ir::Expression * prop,bool isComputed)2066 Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed)
2067 {
2068     VReg res {0};
2069 
2070     if (isComputed) {
2071         return res;
2072     }
2073 
2074     if (prop->IsIdentifier()) {
2075         return prop->AsIdentifier()->Name();
2076     }
2077 
2078     if (prop->IsStringLiteral()) {
2079         const util::StringView &str = prop->AsStringLiteral()->Str();
2080 
2081         // remove this when runtime handles __proto__ as property name correctly
2082         if (str.Is("__proto__")) {
2083             return res;
2084         }
2085 
2086         int64_t index = util::Helpers::GetIndex(str);
2087         if (index != util::Helpers::INVALID_INDEX) {
2088             return index;
2089         }
2090 
2091         return str;
2092     }
2093 
2094     if (prop->IsNumberLiteral()) {
2095         auto num = prop->AsNumberLiteral()->Number<double>();
2096         if (util::Helpers::IsIndex(num)) {
2097             return static_cast<int64_t>(num);
2098         }
2099 
2100         return util::Helpers::ToStringView(allocator_, num);
2101     }
2102 
2103     return res;
2104 }
2105 
ToPropertyKey(const ir::Expression * prop,bool isComputed)2106 Operand PandaGen::ToPropertyKey(const ir::Expression *prop, bool isComputed)
2107 {
2108     Operand op = ToNamedPropertyKey(prop, isComputed);
2109     if (std::holds_alternative<util::StringView>(op) || (std::holds_alternative<int64_t>(op) &&
2110         (std::get<int64_t>(op) <= util::Helpers::MAX_INT32))) {
2111         return op;
2112     }
2113 
2114     VReg propReg = AllocReg();
2115 
2116     /**
2117      * Store index to vreg when index > MAX_INT32 to simplify ASM interpreter If byindex-related instructions support
2118      * index > MAX_INT32, ASM interpreter will have to add a judgment whether index needs more than 32 bits which will
2119      * cause inefficiency of it since cases when index > MAX_INT32 can be quite rare
2120      **/
2121     if (std::holds_alternative<int64_t>(op) && (std::get<int64_t>(op) > util::Helpers::MAX_INT32)) {
2122         LoadAccumulatorFloat(prop, std::get<int64_t>(op));
2123         StoreAccumulator(prop, propReg);
2124         return propReg;
2125     }
2126 
2127     ASSERT(std::holds_alternative<VReg>(op));
2128     prop->Compile(this);
2129     StoreAccumulator(prop, propReg);
2130 
2131     return propReg;
2132 }
2133 
LoadPropertyKey(const ir::Expression * prop,bool isComputed)2134 VReg PandaGen::LoadPropertyKey(const ir::Expression *prop, bool isComputed)
2135 {
2136     Operand op = ToNamedPropertyKey(prop, isComputed);
2137     if (std::holds_alternative<util::StringView>(op)) {
2138         LoadAccumulatorString(prop, std::get<util::StringView>(op));
2139     } else if (std::holds_alternative<int64_t>(op)) {
2140         LoadAccumulatorInt(prop, static_cast<size_t>(std::get<int64_t>(op)));
2141     } else {
2142         prop->Compile(this);
2143     }
2144 
2145     VReg propReg = AllocReg();
2146     StoreAccumulator(prop, propReg);
2147 
2148     return propReg;
2149 }
2150 
ToComputedPropertyKey(const ir::AstNode * node)2151 void PandaGen::ToComputedPropertyKey(const ir::AstNode *node)
2152 {
2153     ra_.Emit<CallruntimeTopropertykey>(node);
2154 }
2155 
StLetOrClassToGlobalRecord(const ir::AstNode * node,const util::StringView & name)2156 void PandaGen::StLetOrClassToGlobalRecord(const ir::AstNode *node, const util::StringView &name)
2157 {
2158     ra_.Emit<Sttoglobalrecord>(node, 0, name);
2159     strings_.insert(name);
2160 }
2161 
StConstToGlobalRecord(const ir::AstNode * node,const util::StringView & name)2162 void PandaGen::StConstToGlobalRecord(const ir::AstNode *node, const util::StringView &name)
2163 {
2164     ra_.Emit<Stconsttoglobalrecord>(node, 0, name);
2165     strings_.insert(name);
2166 }
2167 
TryCompileFunctionCallOrNewExpression(const ir::Expression * expr)2168 bool PandaGen::TryCompileFunctionCallOrNewExpression(const ir::Expression *expr)
2169 {
2170     ASSERT(expr->IsCallExpression() || expr->IsNewExpression());
2171     const auto *callee = expr->IsCallExpression() ? expr->AsCallExpression()->Callee() :
2172                          expr->AsNewExpression()->Callee();
2173 
2174     if (!callee->IsIdentifier()) {
2175         return false;
2176     }
2177 
2178     if (callee->AsIdentifier()->Name().Is("Function")) {
2179         auto arguments = expr->IsCallExpression() ? expr->AsCallExpression()->Arguments() :
2180                          expr->AsNewExpression()->Arguments();
2181         if (arguments.empty()) {
2182             return false;
2183         }
2184 
2185         auto *arg = arguments[arguments.size() - 1];
2186         if (!arg->IsStringLiteral()) {
2187             return false;
2188         }
2189 
2190         if (std::regex_match(arg->AsStringLiteral()->Str().Mutf8(), std::regex(" *return +this[;]? *$"))) {
2191             LoadConst(arg, Constant::JS_GLOBAL);
2192             return true;
2193         }
2194     }
2195 
2196     return false;
2197 }
2198 
ReArrangeIc()2199 void PandaGen::ReArrangeIc()
2200 {
2201     if (!IsIcOverFlow()) {
2202         return;
2203     }
2204 
2205     ResetCurrentSlot(0);
2206 
2207     for (auto *ins: Insns()) {
2208         if (!ins->InlineCacheEnabled()) {
2209             continue;
2210         }
2211 
2212         if (ins->oneByteSlotOnly()) {
2213             auto inc = ins->SetIcSlot(GetCurrentSlot());
2214             IncreaseCurrentSlot(inc);
2215         }
2216     }
2217 
2218     for (auto *ins: Insns()) {
2219         if (!ins->InlineCacheEnabled()) {
2220             continue;
2221         }
2222 
2223         if (ins->oneByteSlotOnly()) {
2224             continue;
2225         }
2226 
2227         auto inc = ins->SetIcSlot(GetCurrentSlot());
2228         IncreaseCurrentSlot(inc);
2229     }
2230 }
2231 
CreatePrivateProperty(const ir::AstNode * node,uint32_t num,int32_t bufIdx)2232 void PandaGen::CreatePrivateProperty(const ir::AstNode *node, uint32_t num, int32_t bufIdx)
2233 {
2234     std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(bufIdx);
2235     util::UString litId(idxStr, allocator_);
2236     ra_.Emit<CallruntimeCreateprivateproperty>(node, num, litId.View());
2237 }
2238 
TestIn(const ir::AstNode * node,uint32_t level,uint32_t slot)2239 void PandaGen::TestIn(const ir::AstNode *node, uint32_t level, uint32_t slot)
2240 {
2241     ra_.Emit<Testin>(node, 0, level, slot);
2242 }
2243 
LoadPrivateProperty(const ir::AstNode * node,uint32_t level,uint32_t slot)2244 void PandaGen::LoadPrivateProperty(const ir::AstNode *node, uint32_t level, uint32_t slot)
2245 {
2246     ra_.Emit<Ldprivateproperty>(node, 0, level, slot);
2247 }
2248 
StorePrivateProperty(const ir::AstNode * node,uint32_t level,uint32_t slot,VReg obj)2249 void PandaGen::StorePrivateProperty(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg obj)
2250 {
2251     ra_.Emit<Stprivateproperty>(node, 0, level, slot, obj);
2252 }
ThrowTypeErrorIfFalse(const ir::AstNode * node,util::StringView str)2253 void PandaGen::ThrowTypeErrorIfFalse(const ir::AstNode *node, util::StringView str)
2254 {
2255     auto *trueLabel = AllocLabel();
2256     BranchIfTrue(node, trueLabel);
2257     ThrowTypeError(node, str);
2258     SetLabel(node, trueLabel);
2259 }
2260 
ThrowTypeError(const ir::AstNode * node,util::StringView str)2261 void PandaGen::ThrowTypeError(const ir::AstNode *node, util::StringView str)
2262 {
2263     LoadAccumulatorString(node, str);
2264     VReg reg = AllocReg();
2265     StoreAccumulator(node, reg);
2266     TryLoadGlobalByName(node, "TypeError");
2267     ra_.Emit<Callarg1>(node, 0, reg);
2268     EmitThrow(node);
2269 }
2270 
2271 }  // namespace panda::es2panda::compiler
2272