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