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