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