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