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