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