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