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