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