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