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
49namespace panda::es2panda::compiler {
50
51// PandaGen
52
53void 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
110void PandaGen::SetInSendable()
111{
112    if (rootNode_->IsProgram()) {
113        return;
114    }
115
116    auto *func = rootNode_->AsScriptFunction();
117    inSendable_ = func->InSendable();
118}
119
120Label *PandaGen::AllocLabel()
121{
122    std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++);
123    return ra_.AllocLabel(std::move(id));
124}
125
126bool PandaGen::IsDebug() const
127{
128    return context_->IsDebug();
129}
130
131bool PandaGen::isDebuggerEvaluateExpressionMode() const
132{
133    return context_->isDebuggerEvaluateExpressionMode();
134}
135
136std::string PandaGen::SourceFile() const
137{
138    return context_->SourceFile();
139}
140
141uint32_t PandaGen::ParamCount() const
142{
143    if (rootNode_->IsProgram()) {
144        return 0;
145    }
146
147    return rootNode_->AsScriptFunction()->Params().size();
148}
149
150uint32_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
161uint32_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
169const util::StringView &PandaGen::InternalName() const
170{
171    return topScope_->InternalName();
172}
173
174const util::StringView &PandaGen::FunctionName() const
175{
176    return topScope_->Name();
177}
178
179binder::Binder *PandaGen::Binder() const
180{
181    return context_->Binder();
182}
183
184void 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
215bool 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
226bool 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
235void 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
244void 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
253void 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
266void 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
280LiteralBuffer *PandaGen::NewLiteralBuffer()
281{
282    LiteralBuffer *buf = allocator_->New<LiteralBuffer>(allocator_);
283    CHECK_NOT_NULL(buf);
284    return buf;
285}
286
287int32_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
295int32_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
310void PandaGen::GetFunctionObject(const ir::AstNode *node)
311{
312    LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_FUNC));
313}
314
315void PandaGen::GetNewTarget(const ir::AstNode *node)
316{
317    LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_NEW_TARGET));
318}
319
320void PandaGen::GetThis(const ir::AstNode *node)
321{
322    LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS));
323}
324
325void PandaGen::SetThis(const ir::AstNode *node)
326{
327    StoreAccToLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_THIS), true);
328}
329
330void 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
363void 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
414void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg)
415{
416    ra_.Emit<Sta>(node, vreg);
417}
418
419void 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
434void 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
451void 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
467void 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
483void 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
488void 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
504constexpr size_t DEBUGGER_GET_SET_ARGS_NUM = 2;
505
506void 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
529void 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
539void 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
557void 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
567void 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
574void 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
580void 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
593void 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
604void PandaGen::LoadObjByValue(const ir::AstNode *node, VReg obj)
605{
606    ra_.Emit<Ldobjbyvalue>(node, 0, obj); // prop is in acc
607}
608
609void PandaGen::StoreObjByValue(const ir::AstNode *node, VReg obj, VReg prop)
610{
611    ra_.Emit<Stobjbyvalue>(node, 0, obj, prop);
612}
613
614void 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
624void PandaGen::DefineFieldByValue(const ir::AstNode *node, VReg obj, VReg prop)
625{
626    ra_.Emit<CallruntimeDefinefieldbyvalue>(node, 0, prop, obj);
627}
628
629void PandaGen::DefineFieldByIndex(const ir::AstNode *node, VReg obj, int64_t index)
630{
631    ra_.Emit<CallruntimeDefinefieldbyindex>(node, 0, index, obj);
632}
633
634void 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
641void 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
647void 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
657void 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
671void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg)
672{
673    ra_.Emit<Lda>(node, reg);
674}
675
676void PandaGen::LoadGlobalVar(const ir::AstNode *node, const util::StringView &name)
677{
678    ra_.Emit<Ldglobalvar>(node, 0, name);
679    strings_.insert(name);
680}
681
682void PandaGen::StoreGlobalVar(const ir::AstNode *node, const util::StringView &name)
683{
684    ra_.Emit<Stglobalvar>(node, 0, name);
685    strings_.insert(name);
686}
687
688void PandaGen::LoadAccFromLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result)
689{
690    VirtualLoadVar::Expand(this, node, result);
691}
692
693void PandaGen::StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration)
694{
695    VirtualStoreVar::Expand(this, node, result, isDeclaration);
696}
697
698void PandaGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str)
699{
700    ra_.Emit<LdaStr>(node, str);
701    strings_.insert(str);
702}
703
704void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num)
705{
706    ra_.Emit<Fldai>(node, num);
707}
708
709void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num)
710{
711    ra_.Emit<Ldai>(node, num);
712}
713
714void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num)
715{
716    ra_.Emit<Ldai>(node, static_cast<int64_t>(num));
717}
718
719void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &num)
720{
721    ra_.Emit<Ldbigint>(node, num);
722    strings_.insert(num);
723}
724
725void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id)
726{
727    LoadConst(node, id);
728    StoreAccumulator(node, reg);
729}
730
731void 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
776void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs)
777{
778    ra_.Emit<Mov>(node, vd, vs);
779}
780
781void PandaGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label)
782{
783    ra_.AddLabel(label);
784}
785
786void PandaGen::Branch(const ir::AstNode *node, Label *label)
787{
788    ra_.Emit<Jmp>(node, label);
789}
790
791bool 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
806Label *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
832Label *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
857void 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
866void 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
909void 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
951void 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
1060void PandaGen::Equal(const ir::AstNode *node, VReg lhs)
1061{
1062    ra_.Emit<Eq>(node, 0, lhs);
1063}
1064
1065void PandaGen::NotEqual(const ir::AstNode *node, VReg lhs)
1066{
1067    ra_.Emit<Noteq>(node, 0, lhs);
1068}
1069
1070void PandaGen::StrictEqual(const ir::AstNode *node, VReg lhs)
1071{
1072    ra_.Emit<Stricteq>(node, 0, lhs);
1073}
1074
1075void PandaGen::StrictNotEqual(const ir::AstNode *node, VReg lhs)
1076{
1077    ra_.Emit<Strictnoteq>(node, 0, lhs);
1078}
1079
1080void PandaGen::LessThan(const ir::AstNode *node, VReg lhs)
1081{
1082    ra_.Emit<Less>(node, 0, lhs);
1083}
1084
1085void PandaGen::LessEqual(const ir::AstNode *node, VReg lhs)
1086{
1087    ra_.Emit<Lesseq>(node, 0, lhs);
1088}
1089
1090void PandaGen::GreaterThan(const ir::AstNode *node, VReg lhs)
1091{
1092    ra_.Emit<Greater>(node, 0, lhs);
1093}
1094
1095void PandaGen::GreaterEqual(const ir::AstNode *node, VReg lhs)
1096{
1097    ra_.Emit<Greatereq>(node, 0, lhs);
1098}
1099
1100void 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
1111void 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
1121void 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
1131void 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
1141void 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
1151void PandaGen::BranchIfTrue(const ir::AstNode *node, Label *target)
1152{
1153    IsTrue(node);
1154    ra_.Emit<Jnez>(node, target);
1155}
1156
1157void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target)
1158{
1159    IsTrue(node);
1160    BranchIfFalse(node, target);
1161}
1162
1163void 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
1176void 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
1186void PandaGen::EmitThrow(const ir::AstNode *node)
1187{
1188    ra_.Emit<Throw>(node);
1189}
1190
1191void 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
1214void PandaGen::EmitReturn(const ir::AstNode *node)
1215{
1216    ra_.Emit<Return>(node);
1217}
1218
1219void PandaGen::EmitReturnUndefined(const ir::AstNode *node)
1220{
1221    ra_.Emit<Returnundefined>(node);
1222}
1223
1224void PandaGen::ImplicitReturn(const ir::AstNode *node)
1225{
1226    builder_->ImplicitReturn(node);
1227}
1228
1229void PandaGen::DirectReturn(const ir::AstNode *node)
1230{
1231    builder_->DirectReturn(node);
1232}
1233
1234void PandaGen::ExplicitReturn(const ir::AstNode *node)
1235{
1236    builder_->ExplicitReturn(node);
1237}
1238
1239void 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
1265void PandaGen::EmitAwait(const ir::AstNode *node)
1266{
1267    builder_->Await(node);
1268}
1269
1270void 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
1310void 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
1349void 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
1370void PandaGen::SuperCallSpread(const ir::AstNode *node, VReg vs)
1371{
1372    ra_.Emit<Supercallspread>(node, 0, vs);
1373}
1374
1375void PandaGen::SuperCallForwardAllArgs(const ir::AstNode *node, VReg funcObj)
1376{
1377    ra_.Emit<CallruntimeSupercallforwardallargs>(node, funcObj);
1378}
1379
1380void PandaGen::NotifyConcurrentResult(const ir::AstNode *node)
1381{
1382    if (IsConcurrent()) {
1383        ra_.Emit<CallruntimeNotifyconcurrentresult>(node);
1384    }
1385}
1386
1387void PandaGen::CallInit(const ir::AstNode *node, VReg thisReg)
1388{
1389    // callee is in acc
1390    ra_.Emit<CallruntimeCallinit>(node, 0, thisReg);
1391}
1392
1393void PandaGen::NewObject(const ir::AstNode *node, VReg startReg, size_t argCount)
1394{
1395    if (argCount <= util::Helpers::MAX_INT8) {
1396        ra_.EmitRange<Newobjrange>(node, argCount, 0, static_cast<int64_t>(argCount), startReg);
1397        return;
1398    }
1399
1400    ra_.EmitRange<WideNewobjrange>(node, argCount, static_cast<int64_t>(argCount), startReg);
1401}
1402
1403void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name)
1404{
1405    if (realNode->IsOverload() || realNode->Declare()) {
1406        return;
1407    }
1408
1409    auto formalParamCnt = realNode->FormalParamsLength();
1410    if (realNode->IsMethod()) {
1411        ra_.Emit<Definemethod>(node, 0, name, static_cast<int64_t>(formalParamCnt));
1412    } else  {
1413        ra_.Emit<Definefunc>(node, 0, name, static_cast<int64_t>(formalParamCnt));
1414    }
1415
1416    strings_.insert(name);
1417}
1418
1419void PandaGen::TypeOf(const ir::AstNode *node)
1420{
1421    ra_.Emit<Typeof>(node, 0);
1422}
1423
1424void PandaGen::CallSpread(const ir::AstNode *node, VReg func, VReg thisReg, VReg args)
1425{
1426    LoadAccumulator(node, func); // callee is load to acc
1427    ra_.Emit<Apply>(node, 0, thisReg, args);
1428}
1429
1430void PandaGen::NewObjSpread(const ir::AstNode *node, VReg obj)
1431{
1432    ra_.Emit<Newobjapply>(node, 0, obj);
1433}
1434
1435void PandaGen::GetUnmappedArgs(const ir::AstNode *node)
1436{
1437    ra_.Emit<Getunmappedargs>(node);
1438}
1439
1440void PandaGen::Negate(const ir::AstNode *node)
1441{
1442    auto *falseLabel = AllocLabel();
1443    auto *endLabel = AllocLabel();
1444    BranchIfTrue(node, falseLabel);
1445    LoadConst(node, Constant::JS_TRUE);
1446    Branch(node, endLabel);
1447    SetLabel(node, falseLabel);
1448    LoadConst(node, Constant::JS_FALSE);
1449    SetLabel(node, endLabel);
1450}
1451
1452void PandaGen::ToNumber(const ir::AstNode *node, VReg arg)
1453{
1454    LoadAccumulator(node, arg);
1455    ra_.Emit<Tonumber>(node, 0);
1456}
1457
1458void PandaGen::ToNumeric(const ir::AstNode *node, VReg arg)
1459{
1460    LoadAccumulator(node, arg);
1461    ra_.Emit<Tonumeric>(node, 0);
1462}
1463
1464void PandaGen::CreateGeneratorObj(const ir::AstNode *node, VReg funcObj)
1465{
1466    ra_.Emit<Creategeneratorobj>(node, funcObj);
1467}
1468
1469void PandaGen::CreateAsyncGeneratorObj(const ir::AstNode *node, VReg funcObj)
1470{
1471    ra_.Emit<Createasyncgeneratorobj>(node, funcObj);
1472}
1473
1474void PandaGen::CreateIterResultObject(const ir::AstNode *node, VReg value, VReg done)
1475{
1476    ra_.Emit<Createiterresultobj>(node, value, done);
1477}
1478
1479void PandaGen::SuspendGenerator(const ir::AstNode *node, VReg genObj)
1480{
1481    ra_.Emit<Suspendgenerator>(node, genObj); // iterResult is in acc
1482}
1483
1484void PandaGen::GeneratorYield(const ir::AstNode *node, VReg genObj)
1485{
1486    LoadAccumulator(node, genObj);
1487    ra_.Emit<Setgeneratorstate>(node, static_cast<int32_t>(GeneratorState::SUSPENDED_YIELD));
1488}
1489
1490void PandaGen::GeneratorComplete(const ir::AstNode *node, VReg genObj)
1491{
1492    LoadAccumulator(node, genObj);
1493    ra_.Emit<Setgeneratorstate>(node, static_cast<int32_t>(GeneratorState::COMPLETED));
1494}
1495
1496void PandaGen::ResumeGenerator(const ir::AstNode *node, VReg genObj)
1497{
1498    LoadAccumulator(node, genObj);
1499    ra_.Emit<Resumegenerator>(node);
1500}
1501
1502void PandaGen::GetResumeMode(const ir::AstNode *node, VReg genObj)
1503{
1504    LoadAccumulator(node, genObj);
1505    ra_.Emit<Getresumemode>(node);
1506}
1507
1508void PandaGen::AsyncFunctionEnter(const ir::AstNode *node)
1509{
1510    ra_.Emit<Asyncfunctionenter>(node);
1511}
1512
1513void PandaGen::AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj)
1514{
1515    ra_.Emit<Asyncfunctionawaituncaught>(node, asyncFuncObj); // receivedValue is in acc
1516}
1517
1518void PandaGen::AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj)
1519{
1520    ra_.Emit<Asyncfunctionresolve>(node, asyncFuncObj); // use retVal in acc
1521}
1522
1523void PandaGen::AsyncFunctionReject(const ir::AstNode *node, VReg asyncFuncObj)
1524{
1525    ra_.Emit<Asyncfunctionreject>(node, asyncFuncObj); // exception is in acc
1526}
1527
1528void PandaGen::AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj, VReg value, VReg canSuspend)
1529{
1530    ra_.Emit<Asyncgeneratorresolve>(node, asyncGenObj, value, canSuspend);
1531}
1532
1533void PandaGen::AsyncGeneratorReject(const ir::AstNode *node, VReg asyncGenObj)
1534{
1535    ra_.Emit<Asyncgeneratorreject>(node, asyncGenObj); // value is in acc
1536}
1537
1538void PandaGen::GetTemplateObject(const ir::AstNode *node, VReg value)
1539{
1540    LoadAccumulator(node, value);
1541    ra_.Emit<Gettemplateobject>(node, 0);
1542}
1543
1544void PandaGen::CopyRestArgs(const ir::AstNode *node, uint32_t index)
1545{
1546    index <= util::Helpers::MAX_INT8 ? ra_.Emit<Copyrestargs>(node, index) : ra_.Emit<WideCopyrestargs>(node, index);
1547}
1548
1549void PandaGen::GetPropIterator(const ir::AstNode *node)
1550{
1551    ra_.Emit<Getpropiterator>(node);
1552}
1553
1554void PandaGen::GetNextPropName(const ir::AstNode *node, VReg iter)
1555{
1556    ra_.Emit<Getnextpropname>(node, iter);
1557}
1558
1559void PandaGen::CreateEmptyObject(const ir::AstNode *node)
1560{
1561    ra_.Emit<Createemptyobject>(node);
1562}
1563
1564void PandaGen::CreateObjectWithBuffer(const ir::AstNode *node, uint32_t idx)
1565{
1566    ASSERT(util::Helpers::IsInteger<uint32_t>(idx));
1567    std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
1568    util::UString litId(idxStr, allocator_);
1569    ra_.Emit<Createobjectwithbuffer>(node, 0, litId.View());
1570}
1571
1572void PandaGen::SetObjectWithProto(const ir::AstNode *node, VReg proto, VReg obj)
1573{
1574    LoadAccumulator(node, obj);
1575    ra_.Emit<Setobjectwithproto>(node, 0, proto);
1576}
1577
1578void PandaGen::CopyDataProperties(const ir::AstNode *node, VReg dst)
1579{
1580    ra_.Emit<Copydataproperties>(node, dst); // use acc as srcObj
1581}
1582
1583void PandaGen::DefineGetterSetterByValue(const ir::AstNode *node, VReg obj, VReg name, VReg getter, VReg setter,
1584                                         bool setName)
1585{
1586    LoadConst(node, setName ? Constant::JS_TRUE : Constant::JS_FALSE);
1587    ra_.Emit<Definegettersetterbyvalue>(node, obj, name, getter, setter);
1588}
1589
1590void PandaGen::CreateEmptyArray(const ir::AstNode *node)
1591{
1592    ra_.Emit<Createemptyarray>(node, 0);
1593}
1594
1595void PandaGen::CreateArrayWithBuffer(const ir::AstNode *node, uint32_t idx)
1596{
1597    ASSERT(util::Helpers::IsInteger<uint32_t>(idx));
1598    std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(idx);
1599    util::UString litId(idxStr, allocator_);
1600    ra_.Emit<Createarraywithbuffer>(node, 0, litId.View());
1601}
1602
1603void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVector<ir::Expression *> &elements, VReg obj)
1604{
1605    if (elements.empty()) {
1606        CreateEmptyArray(node);
1607        StoreAccumulator(node, obj);
1608        return;
1609    }
1610
1611    auto *buf = NewLiteralBuffer();
1612
1613    size_t i = 0;
1614    // This loop handles constant literal data by collecting it into a literal buffer
1615    // until a non-constant element is encountered.
1616    while (i < elements.size() && util::Helpers::IsConstantExpr(elements[i])) {
1617        buf->Add(elements[i]->AsLiteral());
1618        i++;
1619    }
1620
1621    if (buf->IsEmpty()) {
1622        CreateEmptyArray(node);
1623    } else {
1624        uint32_t bufIdx = static_cast<uint32_t>(AddLiteralBuffer(buf));
1625        CreateArrayWithBuffer(node, bufIdx);
1626    }
1627
1628    StoreAccumulator(node, obj);
1629
1630    if (i == elements.size()) {
1631        return;
1632    }
1633
1634    bool hasSpread = false;
1635
1636    // This loop handles array elements until a spread element is encountered
1637    for (; i < elements.size(); i++) {
1638        const ir::Expression *elem = elements[i];
1639
1640        if (elem->IsOmittedExpression()) {
1641            continue;
1642        }
1643
1644        if (elem->IsSpreadElement()) {
1645            // The next loop will handle arrays that have a spread element
1646            hasSpread = true;
1647            break;
1648        }
1649
1650        elem->Compile(this);
1651        StOwnByIndex(elem, obj, i);
1652    }
1653
1654    RegScope rs(this);
1655    VReg idxReg {};
1656
1657    if (hasSpread) {
1658        idxReg = AllocReg();
1659        LoadAccumulatorInt(node, i);
1660        StoreAccumulator(node, idxReg);
1661    }
1662
1663    // This loop handles arrays that contain spread elements
1664    for (; i < elements.size(); i++) {
1665        const ir::Expression *elem = elements[i];
1666
1667        if (elem->IsSpreadElement()) {
1668            elem->AsSpreadElement()->Argument()->Compile(this);
1669
1670            StoreArraySpread(elem, obj, idxReg);
1671
1672            LoadObjByName(node, obj, "length");
1673            StoreAccumulator(elem, idxReg);
1674            continue;
1675        }
1676
1677        if (!elem->IsOmittedExpression()) {
1678            elem->Compile(this);
1679            StOwnByValue(elem, obj, idxReg);
1680        }
1681
1682        Unary(elem, lexer::TokenType::PUNCTUATOR_PLUS_PLUS, idxReg);
1683        StoreAccumulator(elem, idxReg);
1684    }
1685
1686    // If the last element is omitted, we also have to update the length property
1687    if (elements.back()->IsOmittedExpression()) {
1688        // if there was a spread value then acc already contains the length
1689        if (!hasSpread) {
1690            LoadAccumulatorInt(node, i);
1691        }
1692
1693        StOwnByName(node, obj, "length");
1694    }
1695
1696    LoadAccumulator(node, obj);
1697}
1698
1699void PandaGen::StoreArraySpread(const ir::AstNode *node, VReg array, VReg index)
1700{
1701    ra_.Emit<Starrayspread>(node, array, index);
1702}
1703
1704void PandaGen::ThrowIfNotObject(const ir::AstNode *node, VReg obj)
1705{
1706    ra_.Emit<ThrowIfnotobject>(node, obj);
1707}
1708
1709void PandaGen::ThrowThrowNotExist(const ir::AstNode *node)
1710{
1711    ra_.Emit<ThrowNotexists>(node);
1712}
1713
1714void PandaGen::GetIterator(const ir::AstNode *node)
1715{
1716    ra_.Emit<Getiterator>(node, 0);
1717}
1718
1719void PandaGen::GetAsyncIterator(const ir::AstNode *node)
1720{
1721    ra_.Emit<Getasynciterator>(node, 0);
1722}
1723
1724void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount)
1725{
1726    ASSERT(argStart == obj + 1);
1727    if (argCount == 0) {
1728        LoadConst(node, Constant::JS_UNDEFINED);
1729        StoreAccumulator(node, argStart);
1730    }
1731
1732    size_t argRegCnt = (argCount == 0 ? argCount : argCount - 1);
1733
1734    if (argRegCnt <= util::Helpers::MAX_INT8) {
1735        ra_.EmitRange<Createobjectwithexcludedkeys>(node, argCount, static_cast<int64_t>(argRegCnt), obj, argStart);
1736        return;
1737    }
1738
1739    ra_.EmitRange<WideCreateobjectwithexcludedkeys>(node, argCount, static_cast<int64_t>(argRegCnt), obj, argStart);
1740}
1741
1742void PandaGen::ThrowObjectNonCoercible(const ir::AstNode *node)
1743{
1744    ra_.Emit<ThrowPatternnoncoercible>(node);
1745}
1746
1747void PandaGen::CloseIterator(const ir::AstNode *node, VReg iter)
1748{
1749    ra_.Emit<Closeiterator>(node, 0, iter);
1750}
1751
1752void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg base)
1753{
1754    auto formalParamCnt = node->AsClassDefinition()->Ctor()->Function()->FormalParamsLength();
1755    std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(litIdx);
1756    util::UString litId(idxStr, allocator_);
1757    ra_.Emit<Defineclasswithbuffer>(node, 0, ctorId, litId.View(), static_cast<int64_t>(formalParamCnt), base);
1758    strings_.insert(ctorId);
1759}
1760
1761void PandaGen::DefineSendableClass(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg base)
1762{
1763    auto formalParamCnt = node->AsClassDefinition()->Ctor()->Function()->FormalParamsLength();
1764    std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(litIdx);
1765    util::UString litId(idxStr, allocator_);
1766    ra_.Emit<CallruntimeDefinesendableclass>(node, 0, ctorId, litId.View(), static_cast<int64_t>(formalParamCnt), base);
1767    strings_.insert(ctorId);
1768}
1769
1770void PandaGen::LoadSendableClass(const ir::AstNode *node, int32_t level)
1771{
1772    ra_.Emit<CallruntimeLdsendableclass>(node, level);
1773}
1774
1775void PandaGen::LoadLocalModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable)
1776{
1777    auto index = variable->Index();
1778    index <= util::Helpers::MAX_INT8 ? ra_.Emit<Ldlocalmodulevar>(node, index) :
1779                                       ra_.Emit<WideLdlocalmodulevar>(node, index);
1780}
1781
1782void PandaGen::LoadExternalModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable)
1783{
1784    auto index = variable->Index();
1785
1786    auto targetApiVersion = Binder()->Program()->TargetApiVersion();
1787    bool isLazy = variable->Declaration()->Node()->IsImportSpecifier() ?
1788        variable->Declaration()->Node()->AsImportSpecifier()->IsLazy() : false;
1789    if (isLazy) {
1790        // Change the behavior of using imported object in sendable class since api12
1791        if (inSendable_ && targetApiVersion >= util::Helpers::SENDABLE_LAZY_LOADING_MIN_SUPPORTED_API_VERSION) {
1792            index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdlazysendablemodulevar>(node, index) :
1793                                               ra_.Emit<CallruntimeWideldlazysendablemodulevar>(node, index);
1794            return;
1795        }
1796
1797        index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdlazymodulevar>(node, index) :
1798                                           ra_.Emit<CallruntimeWideldlazymodulevar>(node, index);
1799        return;
1800    }
1801
1802    // Change the behavior of using imported object in sendable class since api12
1803    if (inSendable_ && targetApiVersion >= util::Helpers::SENDABLE_LAZY_LOADING_MIN_SUPPORTED_API_VERSION) {
1804        index <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeLdsendableexternalmodulevar>(node, index) :
1805                                           ra_.Emit<CallruntimeWideldsendableexternalmodulevar>(node, index);
1806        return;
1807    }
1808
1809    index <= util::Helpers::MAX_INT8 ? ra_.Emit<Ldexternalmodulevar>(node, index) :
1810                                       ra_.Emit<WideLdexternalmodulevar>(node, index);
1811}
1812
1813void PandaGen::StoreModuleVariable(const ir::AstNode *node, const binder::ModuleVariable *variable)
1814{
1815    auto index = variable->Index();
1816    index <= util::Helpers::MAX_INT8 ? ra_.Emit<Stmodulevar>(node, index) :
1817                                       ra_.Emit<WideStmodulevar>(node, index);
1818}
1819
1820void PandaGen::GetModuleNamespace(const ir::AstNode *node, uint32_t index)
1821{
1822    index <= util::Helpers::MAX_INT8 ? ra_.Emit<Getmodulenamespace>(node, index) :
1823                                       ra_.Emit<WideGetmodulenamespace>(node, index);
1824}
1825
1826void PandaGen::DynamicImportCall(const ir::AstNode *node)
1827{
1828    ra_.Emit<Dynamicimport>(node);
1829}
1830
1831void PandaGen::StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key)
1832{
1833    ra_.Emit<Stsuperbyname>(node, 0, key, obj);
1834    strings_.insert(key);
1835}
1836
1837void PandaGen::LdSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key)
1838{
1839    LoadAccumulator(node, obj); // object is load to acc
1840    ra_.Emit<Ldsuperbyname>(node, 0, key);
1841    strings_.insert(key);
1842}
1843
1844void PandaGen::StSuperByValue(const ir::AstNode *node, VReg obj, VReg prop)
1845{
1846    ra_.Emit<Stsuperbyvalue>(node, 0, obj, prop);
1847}
1848
1849void PandaGen::LdSuperByValue(const ir::AstNode *node, VReg obj)
1850{
1851    ra_.Emit<Ldsuperbyvalue>(node, 0, obj); // prop is in acc
1852}
1853
1854void PandaGen::StoreSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
1855{
1856    if (std::holds_alternative<util::StringView>(prop)) {
1857        StSuperByName(node, obj, std::get<util::StringView>(prop));
1858        return;
1859    }
1860
1861    if (std::holds_alternative<VReg>(prop)) {
1862        StSuperByValue(node, obj, std::get<VReg>(prop));
1863        return;
1864    }
1865
1866    ASSERT(std::holds_alternative<int64_t>(prop));
1867    RegScope rs(this);
1868    VReg property = AllocReg();
1869    VReg value = AllocReg();
1870
1871    StoreAccumulator(node, value);
1872    LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop)));
1873    StoreAccumulator(node, property);
1874    LoadAccumulator(node, value);
1875    StSuperByValue(node, obj, property);
1876}
1877
1878void PandaGen::LoadSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop)
1879{
1880    if (std::holds_alternative<util::StringView>(prop)) {
1881        LdSuperByName(node, obj, std::get<util::StringView>(prop));
1882        return;
1883    }
1884
1885    if (std::holds_alternative<VReg>(prop)) {
1886        LoadAccumulator(node, std::get<VReg>(prop));
1887        LdSuperByValue(node, obj);
1888        return;
1889    }
1890
1891    ASSERT(std::holds_alternative<int64_t>(prop));
1892
1893    LoadAccumulatorInt(node, static_cast<size_t>(std::get<int64_t>(prop)));
1894    LdSuperByValue(node, obj);
1895}
1896
1897void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1898{
1899    if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1900        ra_.Emit<WideLdlexvar>(node, level, slot);
1901        return;
1902    }
1903
1904    ra_.Emit<Ldlexvar>(node, level, slot);
1905}
1906
1907void PandaGen::LoadSendableVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1908{
1909    if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1910        ra_.Emit<CallruntimeWideldsendablevar>(node, level, slot);
1911        return;
1912    }
1913
1914    ra_.Emit<CallruntimeLdsendablevar>(node, level, slot);
1915}
1916
1917void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, const util::StringView &name)
1918{
1919    if (context_->PatchFixHelper() && context_->PatchFixHelper()->IsAdditionalVarInPatch(slot)) {
1920        uint32_t patchSlot = context_->PatchFixHelper()->GetPatchLexicalIdx(std::string(name));
1921        ra_.Emit<WideLdpatchvar>(node, patchSlot);
1922        return;
1923    }
1924
1925    if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1926        ra_.Emit<WideLdlexvar>(node, level, slot);
1927        return;
1928    }
1929
1930    ra_.Emit<Ldlexvar>(node, level, slot);
1931}
1932
1933void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1934{
1935    if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1936        ra_.Emit<WideStlexvar>(node, level, slot);
1937        return;
1938    }
1939
1940    ra_.Emit<Stlexvar>(node, level, slot);
1941}
1942
1943void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg value)
1944{
1945    LoadAccumulator(node, value);
1946    if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1947        ra_.Emit<WideStlexvar>(node, level, slot);
1948        return;
1949    }
1950
1951    ra_.Emit<Stlexvar>(node, level, slot);
1952}
1953
1954void PandaGen::StoreSendableVar(const ir::AstNode *node, uint32_t level, uint32_t slot)
1955{
1956    if ((level > util::Helpers::MAX_INT8) || (slot > util::Helpers::MAX_INT8)) {
1957        ra_.Emit<CallruntimeWidestsendablevar>(node, level, slot);
1958        return;
1959    }
1960
1961    ra_.Emit<CallruntimeStsendablevar>(node, level, slot);
1962}
1963
1964void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot,
1965    const binder::LocalVariable *local)
1966{
1967    if (context_->PatchFixHelper() && context_->PatchFixHelper()->IsAdditionalVarInPatch(slot)) {
1968        uint32_t patchSlot = context_->PatchFixHelper()->GetPatchLexicalIdx(std::string(local->Name()));
1969        ra_.Emit<WideStpatchvar>(node, patchSlot);
1970        return;
1971    }
1972    RegScope rs(this);
1973    VReg value = AllocReg();
1974    StoreAccumulator(node, value);
1975    StoreLexicalVar(node, level, slot, value);
1976}
1977
1978void PandaGen::ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num)
1979{
1980    ra_.Emit<ThrowIfsupernotcorrectcall>(node, num);
1981}
1982
1983void PandaGen::ThrowUndefinedIfHole(const ir::AstNode *node, const util::StringView &name)
1984{
1985    ra_.Emit<ThrowUndefinedifholewithname>(node, name);
1986    strings_.insert(name);
1987}
1988
1989void PandaGen::ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name)
1990{
1991    RegScope rs(this);
1992    LoadAccumulatorString(node, name);
1993    VReg nameReg = AllocReg();
1994    StoreAccumulator(node, nameReg);
1995    ra_.Emit<ThrowConstassignment>(node, nameReg);
1996    strings_.insert(name);
1997}
1998
1999void PandaGen::PopLexEnv(const ir::AstNode *node)
2000{
2001    ra_.Emit<Poplexenv>(node);
2002}
2003
2004void PandaGen::GenDebugger(const ir::AstNode *node)
2005{
2006    if (IsDebug()) {
2007        ra_.Emit<Debugger>(node);
2008    }
2009}
2010
2011void PandaGen::NewLexicalEnv(const ir::AstNode *node, uint32_t num, binder::VariableScope *scope)
2012{
2013    if (IsDebug()) {
2014        int32_t scopeInfoIdx = AddLexicalVarNamesForDebugInfo(scope->GetLexicalVarNameAndTypes());
2015        NewLexEnvWithScopeInfo(node, num, scopeInfoIdx);
2016        return;
2017    }
2018
2019    NewLexEnv(node, num);
2020}
2021
2022void PandaGen::NewLexEnv(const ir::AstNode *node, uint32_t num)
2023{
2024    num <= util::Helpers::MAX_INT8 ? ra_.Emit<Newlexenv>(node, num) : ra_.Emit<WideNewlexenv>(node, num);
2025}
2026
2027void PandaGen::NewSendableEnv(const ir::AstNode * node, uint32_t num)
2028{
2029    num <= util::Helpers::MAX_INT8 ? ra_.Emit<CallruntimeNewsendableenv>(node, num) :
2030        ra_.Emit<CallruntimeWidenewsendableenv>(node, num);
2031}
2032
2033void PandaGen::NewLexEnvWithScopeInfo(const ir::AstNode *node, uint32_t num, int32_t scopeInfoIdx)
2034{
2035    std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(scopeInfoIdx);
2036    util::UString litId(idxStr, allocator_);
2037    num <= util::Helpers::MAX_INT8 ? ra_.Emit<Newlexenvwithname>(node, num, litId.View()) :
2038                                     ra_.Emit<WideNewlexenvwithname>(node, num, litId.View());
2039}
2040
2041uint32_t PandaGen::TryDepth() const
2042{
2043    const auto *iter = dynamicContext_;
2044    uint32_t depth = 0;
2045
2046    while (iter) {
2047        if (iter->HasTryCatch()) {
2048            depth++;
2049        }
2050
2051        iter = iter->Prev();
2052    }
2053
2054    return depth;
2055}
2056
2057CatchTable *PandaGen::CreateCatchTable()
2058{
2059    auto *catchTable = allocator_->New<CatchTable>(this, TryDepth());
2060    CHECK_NOT_NULL(catchTable);
2061    catchList_.push_back(catchTable);
2062    return catchTable;
2063}
2064
2065void PandaGen::SortCatchTables()
2066{
2067    std::sort(catchList_.begin(), catchList_.end(),
2068              [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); });
2069}
2070
2071Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed)
2072{
2073    VReg res {0};
2074
2075    if (isComputed) {
2076        return res;
2077    }
2078
2079    if (prop->IsIdentifier()) {
2080        return prop->AsIdentifier()->Name();
2081    }
2082
2083    if (prop->IsStringLiteral()) {
2084        const util::StringView &str = prop->AsStringLiteral()->Str();
2085
2086        // remove this when runtime handles __proto__ as property name correctly
2087        if (str.Is("__proto__")) {
2088            return res;
2089        }
2090
2091        int64_t index = util::Helpers::GetIndex(str);
2092        if (index != util::Helpers::INVALID_INDEX) {
2093            return index;
2094        }
2095
2096        return str;
2097    }
2098
2099    if (prop->IsNumberLiteral()) {
2100        auto num = prop->AsNumberLiteral()->Number<double>();
2101        if (util::Helpers::IsIndex(num)) {
2102            return static_cast<int64_t>(num);
2103        }
2104
2105        return util::Helpers::ToStringView(allocator_, num);
2106    }
2107
2108    return res;
2109}
2110
2111Operand PandaGen::ToPropertyKey(const ir::Expression *prop, bool isComputed)
2112{
2113    Operand op = ToNamedPropertyKey(prop, isComputed);
2114    if (std::holds_alternative<util::StringView>(op) || (std::holds_alternative<int64_t>(op) &&
2115        (std::get<int64_t>(op) <= util::Helpers::MAX_INT32))) {
2116        return op;
2117    }
2118
2119    VReg propReg = AllocReg();
2120
2121    /**
2122     * Store index to vreg when index > MAX_INT32 to simplify ASM interpreter If byindex-related instructions support
2123     * index > MAX_INT32, ASM interpreter will have to add a judgment whether index needs more than 32 bits which will
2124     * cause inefficiency of it since cases when index > MAX_INT32 can be quite rare
2125     **/
2126    if (std::holds_alternative<int64_t>(op) && (std::get<int64_t>(op) > util::Helpers::MAX_INT32)) {
2127        LoadAccumulatorFloat(prop, std::get<int64_t>(op));
2128        StoreAccumulator(prop, propReg);
2129        return propReg;
2130    }
2131
2132    ASSERT(std::holds_alternative<VReg>(op));
2133    prop->Compile(this);
2134    StoreAccumulator(prop, propReg);
2135
2136    return propReg;
2137}
2138
2139VReg PandaGen::LoadPropertyKey(const ir::Expression *prop, bool isComputed)
2140{
2141    Operand op = ToNamedPropertyKey(prop, isComputed);
2142    if (std::holds_alternative<util::StringView>(op)) {
2143        LoadAccumulatorString(prop, std::get<util::StringView>(op));
2144    } else if (std::holds_alternative<int64_t>(op)) {
2145        LoadAccumulatorInt(prop, static_cast<size_t>(std::get<int64_t>(op)));
2146    } else {
2147        prop->Compile(this);
2148    }
2149
2150    VReg propReg = AllocReg();
2151    StoreAccumulator(prop, propReg);
2152
2153    return propReg;
2154}
2155
2156void PandaGen::ToComputedPropertyKey(const ir::AstNode *node)
2157{
2158    ra_.Emit<CallruntimeTopropertykey>(node);
2159}
2160
2161void PandaGen::StLetOrClassToGlobalRecord(const ir::AstNode *node, const util::StringView &name)
2162{
2163    ra_.Emit<Sttoglobalrecord>(node, 0, name);
2164    strings_.insert(name);
2165}
2166
2167void PandaGen::StConstToGlobalRecord(const ir::AstNode *node, const util::StringView &name)
2168{
2169    ra_.Emit<Stconsttoglobalrecord>(node, 0, name);
2170    strings_.insert(name);
2171}
2172
2173bool PandaGen::TryCompileFunctionCallOrNewExpression(const ir::Expression *expr)
2174{
2175    ASSERT(expr->IsCallExpression() || expr->IsNewExpression());
2176    const auto *callee = expr->IsCallExpression() ? expr->AsCallExpression()->Callee() :
2177                         expr->AsNewExpression()->Callee();
2178
2179    if (!callee->IsIdentifier()) {
2180        return false;
2181    }
2182
2183    if (callee->AsIdentifier()->Name().Is("Function")) {
2184        auto arguments = expr->IsCallExpression() ? expr->AsCallExpression()->Arguments() :
2185                         expr->AsNewExpression()->Arguments();
2186        if (arguments.empty()) {
2187            return false;
2188        }
2189
2190        auto *arg = arguments[arguments.size() - 1];
2191        if (!arg->IsStringLiteral()) {
2192            return false;
2193        }
2194
2195        if (std::regex_match(arg->AsStringLiteral()->Str().Mutf8(), std::regex(" *return +this[;]? *$"))) {
2196            LoadConst(arg, Constant::JS_GLOBAL);
2197            return true;
2198        }
2199    }
2200
2201    return false;
2202}
2203
2204void PandaGen::ReArrangeIc()
2205{
2206    if (!IsIcOverFlow()) {
2207        return;
2208    }
2209
2210    ResetCurrentSlot(0);
2211
2212    for (auto *ins: Insns()) {
2213        if (!ins->InlineCacheEnabled()) {
2214            continue;
2215        }
2216
2217        if (ins->oneByteSlotOnly()) {
2218            auto inc = ins->SetIcSlot(GetCurrentSlot());
2219            IncreaseCurrentSlot(inc);
2220        }
2221    }
2222
2223    for (auto *ins: Insns()) {
2224        if (!ins->InlineCacheEnabled()) {
2225            continue;
2226        }
2227
2228        if (ins->oneByteSlotOnly()) {
2229            continue;
2230        }
2231
2232        auto inc = ins->SetIcSlot(GetCurrentSlot());
2233        IncreaseCurrentSlot(inc);
2234    }
2235}
2236
2237void PandaGen::CreatePrivateProperty(const ir::AstNode *node, uint32_t num, int32_t bufIdx)
2238{
2239    std::string idxStr = std::string(context_->Binder()->Program()->RecordName()) + "_" + std::to_string(bufIdx);
2240    util::UString litId(idxStr, allocator_);
2241    ra_.Emit<CallruntimeCreateprivateproperty>(node, num, litId.View());
2242}
2243
2244void PandaGen::TestIn(const ir::AstNode *node, uint32_t level, uint32_t slot)
2245{
2246    ra_.Emit<Testin>(node, 0, level, slot);
2247}
2248
2249void PandaGen::LoadPrivateProperty(const ir::AstNode *node, uint32_t level, uint32_t slot)
2250{
2251    ra_.Emit<Ldprivateproperty>(node, 0, level, slot);
2252}
2253
2254void PandaGen::StorePrivateProperty(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg obj)
2255{
2256    ra_.Emit<Stprivateproperty>(node, 0, level, slot, obj);
2257}
2258void PandaGen::ThrowTypeErrorIfFalse(const ir::AstNode *node, util::StringView str)
2259{
2260    auto *trueLabel = AllocLabel();
2261    BranchIfTrue(node, trueLabel);
2262    ThrowTypeError(node, str);
2263    SetLabel(node, trueLabel);
2264}
2265
2266void PandaGen::ThrowTypeError(const ir::AstNode *node, util::StringView str)
2267{
2268    LoadAccumulatorString(node, str);
2269    VReg reg = AllocReg();
2270    StoreAccumulator(node, reg);
2271    TryLoadGlobalByName(node, "TypeError");
2272    ra_.Emit<Callarg1>(node, 0, reg);
2273    EmitThrow(node);
2274}
2275
2276}  // namespace panda::es2panda::compiler
2277