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