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