• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "JSCompiler.h"
17 
18 #include "varbinder/varbinder.h"
19 #include "compiler/base/catchTable.h"
20 #include "compiler/base/condition.h"
21 #include "compiler/base/lreference.h"
22 #include "compiler/core/pandagen.h"
23 #include "compiler/core/switchBuilder.h"
24 #include "compiler/function/functionBuilder.h"
25 #include "util/bitset.h"
26 #include "util/helpers.h"
27 namespace ark::es2panda::compiler {
28 
GetPandaGen() const29 PandaGen *JSCompiler::GetPandaGen() const
30 {
31     return static_cast<PandaGen *>(GetCodeGen());
32 }
33 
34 // from base folder
Compile(const ir::CatchClause * st) const35 void JSCompiler::Compile(const ir::CatchClause *st) const
36 {
37     PandaGen *pg = GetPandaGen();
38     compiler::LocalRegScope lrs(pg, st->Scope()->ParamScope());
39 
40     if (st->Param() != nullptr) {
41         auto lref = compiler::JSLReference::Create(pg, st->Param(), true);
42         lref.SetValue();
43     }
44 
45     ES2PANDA_ASSERT(st->Scope() == st->Body()->Scope());
46     st->Body()->Compile(pg);
47 }
48 
CompileHeritageClause(compiler::PandaGen * pg,const ir::ClassDefinition * node)49 static compiler::VReg CompileHeritageClause(compiler::PandaGen *pg, const ir::ClassDefinition *node)
50 {
51     compiler::VReg baseReg = pg->AllocReg();
52 
53     if (node->Super() != nullptr) {
54         node->Super()->Compile(pg);
55     } else {
56         pg->LoadConst(node, compiler::Constant::JS_HOLE);
57     }
58 
59     pg->StoreAccumulator(node, baseReg);
60     return baseReg;
61 }
62 
CreatePrivateElement(const ir::ClassElement * prop,const ir::MethodDefinition * propMethod,compiler::LiteralBuffer & privateBuf,util::StringView name)63 static void CreatePrivateElement(const ir::ClassElement *prop, const ir::MethodDefinition *propMethod,
64                                  compiler::LiteralBuffer &privateBuf, util::StringView name)
65 {
66     privateBuf.emplace_back(static_cast<uint32_t>(prop->ToPrivateFieldKind(propMethod->IsStatic())));
67     privateBuf.emplace_back(name);
68 
69     const ir::ScriptFunction *func = propMethod->Value()->AsFunctionExpression()->Function();
70     compiler::LiteralTag tag = compiler::LiteralTag::METHOD;
71     bool isAsyncFunc = func->IsAsyncFunc();
72     if (isAsyncFunc && func->IsGenerator()) {
73         tag = compiler::LiteralTag::ASYNC_GENERATOR_METHOD;
74     } else if (isAsyncFunc && !func->IsGenerator()) {
75         tag = compiler::LiteralTag::ASYNC_METHOD;
76     } else if (!isAsyncFunc && func->IsGenerator()) {
77         tag = compiler::LiteralTag::GENERATOR_METHOD;
78     }
79 
80     privateBuf.emplace_back(tag, func->Scope()->InternalName());
81 }
82 
PropertyMethodKind(const ir::MethodDefinition * propMethod,util::BitSet & compiled,size_t i)83 compiler::Literal PropertyMethodKind(const ir::MethodDefinition *propMethod, util::BitSet &compiled, size_t i)
84 {
85     compiler::Literal value {};
86     switch (propMethod->Kind()) {
87         case ir::MethodDefinitionKind::METHOD: {
88             const ir::FunctionExpression *func = propMethod->Value()->AsFunctionExpression();
89             const util::StringView &internalName = func->Function()->Scope()->InternalName();
90 
91             value = compiler::Literal(compiler::LiteralTag::METHOD, internalName);
92             compiled.Set(i);
93             break;
94         }
95         case ir::MethodDefinitionKind::GET:
96         case ir::MethodDefinitionKind::SET: {
97             value = compiler::Literal::NullLiteral();
98             break;
99         }
100         default: {
101             ES2PANDA_UNREACHABLE();
102         }
103     }
104     return value;
105 }
106 
CreateClassStaticPropertiesBuf(compiler::LiteralBuffer & buf,compiler::LiteralBuffer & privateBuf,compiler::LiteralBuffer & staticBuf,compiler::PandaGen * pg)107 static std::tuple<int32_t, compiler::LiteralBuffer> CreateClassStaticPropertiesBuf(compiler::LiteralBuffer &buf,
108                                                                                    compiler::LiteralBuffer &privateBuf,
109                                                                                    compiler::LiteralBuffer &staticBuf,
110                                                                                    compiler::PandaGen *pg)
111 {
112     uint32_t litPairs = buf.size() / 2;
113 
114     /* Static items are stored at the end of the buffer */
115     buf.insert(buf.end(), staticBuf.begin(), staticBuf.end());
116 
117     /* The last literal item represents the offset of the first static property. The regular property literal count
118      * is divided by 2 as key/value pairs count as one. */
119     buf.emplace_back(litPairs);
120 
121     return {pg->AddLiteralBuffer(std::move(buf)), privateBuf};
122 }
123 
124 // NOLINTNEXTLINE(google-runtime-references)
CreateClassStaticPropertiesHelper(compiler::LiteralBuffer & literalBuf,std::unordered_map<util::StringView,size_t> & nameMap,util::StringView name,bool seenComputed)125 static std::tuple<size_t, compiler::LiteralBuffer, bool> CreateClassStaticPropertiesHelper(
126     compiler::LiteralBuffer &literalBuf, std::unordered_map<util::StringView, size_t> &nameMap, util::StringView name,
127     bool seenComputed)
128 {
129     size_t bufferPos = literalBuf.size();
130     auto res = nameMap.insert({name, bufferPos});
131     if (res.second) {
132         if (seenComputed) {
133             return {bufferPos, literalBuf, true};
134         }
135 
136         literalBuf.emplace_back(name);
137         literalBuf.emplace_back();
138     } else {
139         bufferPos = res.first->second;
140     }
141     return {bufferPos, literalBuf, false};
142 }
143 
144 // NOLINTNEXTLINE(google-runtime-references)
CreateClassStaticProperties(compiler::PandaGen * pg,util::BitSet & compiled,const ArenaVector<ir::AstNode * > & properties)145 static std::tuple<int32_t, compiler::LiteralBuffer> CreateClassStaticProperties(
146     compiler::PandaGen *pg, util::BitSet &compiled, const ArenaVector<ir::AstNode *> &properties)
147 {
148     compiler::LiteralBuffer buf {};
149     compiler::LiteralBuffer privateBuf {};
150     compiler::LiteralBuffer staticBuf {};
151     bool seenComputed = false;
152     std::unordered_map<util::StringView, size_t> propNameMap;
153     std::unordered_map<util::StringView, size_t> staticPropNameMap;
154 
155     for (size_t i = 0; i < properties.size(); i++) {
156         const ir::ClassElement *prop = properties[i]->AsClassElement();
157 
158         if (prop->IsClassStaticBlock()) {
159             continue;
160         }
161 
162         if (prop->IsClassProperty() && prop->IsPrivateElement()) {
163             bool isStatic = prop->IsStatic();
164             privateBuf.emplace_back(static_cast<uint32_t>(prop->ToPrivateFieldKind(isStatic)));
165             privateBuf.emplace_back(prop->Id()->Name());
166             continue;
167         }
168         if (prop->IsClassProperty() && !prop->IsPrivateElement()) {
169             continue;
170         }
171 
172         ES2PANDA_ASSERT(prop->IsMethodDefinition());
173         const ir::MethodDefinition *propMethod = prop->AsMethodDefinition();
174 
175         if (!util::Helpers::IsConstantPropertyKey(propMethod->Key(), propMethod->IsComputed()) ||
176             (propMethod->IsComputed() && util::Helpers::IsSpecialPropertyKey(propMethod->Key()))) {
177             seenComputed = true;
178             continue;
179         }
180 
181         util::StringView name = util::Helpers::LiteralToPropName(prop->Key());
182         compiler::LiteralBuffer &literalBuf = prop->IsStatic() ? staticBuf : buf;
183         auto &nameMap = prop->IsStatic() ? staticPropNameMap : propNameMap;
184 
185         if (prop->IsPrivateElement()) {
186             CreatePrivateElement(prop, propMethod, privateBuf, name);
187             compiled.Set(i);
188             continue;
189         }
190 
191         size_t bufferPos = literalBuf.size();
192         bool stop = false;
193         std::tie(bufferPos, literalBuf, stop) =
194             CreateClassStaticPropertiesHelper(literalBuf, nameMap, name, seenComputed);
195         if (stop) {
196             break;
197         }
198 
199         compiler::Literal value = PropertyMethodKind(propMethod, compiled, i);
200 
201         literalBuf[bufferPos + 1] = std::move(value);
202     }
203 
204     return CreateClassStaticPropertiesBuf(buf, privateBuf, staticBuf, pg);
205 }
206 
CompileStaticFieldInitializers(compiler::PandaGen * pg,compiler::VReg classReg,const std::vector<compiler::VReg> & staticComputedFieldKeys,const ir::ClassDefinition * node)207 static void CompileStaticFieldInitializers(compiler::PandaGen *pg, compiler::VReg classReg,
208                                            const std::vector<compiler::VReg> &staticComputedFieldKeys,
209                                            const ir::ClassDefinition *node)
210 {
211     const auto &properties = node->Body();
212     auto iter = staticComputedFieldKeys.begin();
213 
214     if (node->HasPrivateMethod()) {
215         pg->ClassPrivateMethodOrAccessorAdd(node, classReg, classReg);
216     }
217 
218     for (const auto *it : properties) {
219         compiler::RegScope rs(pg);
220 
221         if (it->IsClassStaticBlock()) {
222             const auto *func = it->AsClassStaticBlock()->Value()->AsFunctionExpression()->Function();
223 
224             compiler::VReg funcReg = pg->AllocReg();
225             compiler::VReg thisReg = pg->AllocReg();
226 
227             pg->LoadAccumulator(it, classReg);
228             pg->StoreAccumulator(it, thisReg);
229             pg->DefineMethod(it, func->Scope()->InternalName());
230             pg->StoreAccumulator(it, funcReg);
231 
232             pg->Call0This(node, funcReg, thisReg);
233             continue;
234         }
235 
236         if (it->IsMethodDefinition()) {
237             continue;
238         }
239 
240         ES2PANDA_ASSERT(it->IsClassProperty());
241         const ir::ClassProperty *prop = it->AsClassProperty();
242 
243         if (!prop->IsStatic()) {
244             continue;
245         }
246 
247         compiler::VReg keyReg {};
248 
249         if (prop->IsComputed()) {
250             ES2PANDA_ASSERT(iter != staticComputedFieldKeys.end());
251             keyReg = *iter++;
252         } else if (!prop->IsPrivateElement()) {
253             keyReg = pg->LoadPropertyKey(prop->Key(), false);
254         }
255 
256         if (prop->Value() == nullptr) {
257             pg->LoadConst(prop, compiler::Constant::JS_UNDEFINED);
258         } else {
259             compiler::RegScope vrs(pg);
260             prop->Value()->Compile(pg);
261         }
262 
263         if (prop->IsPrivateElement()) {
264             ES2PANDA_ASSERT(prop->Id() != nullptr);
265             pg->ClassPrivateFieldAdd(prop, classReg, classReg, prop->Id()->Name());
266             continue;
267         }
268 
269         pg->ClassFieldAdd(prop, classReg, keyReg);
270     }
271 }
272 
CompilePropertyKind(const ir::MethodDefinition * prop,compiler::VReg dest,compiler::PandaGen * pg,const ir::ClassDefinition * node)273 static void CompilePropertyKind(const ir::MethodDefinition *prop, compiler::VReg dest, compiler::PandaGen *pg,
274                                 const ir::ClassDefinition *node)
275 {
276     switch (prop->Kind()) {
277         case ir::MethodDefinitionKind::METHOD: {
278             compiler::Operand key = pg->ToOwnPropertyKey(prop->Key(), prop->IsComputed());
279 
280             pg->LoadAccumulator(node, dest);
281             const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
282             func->Compile(pg);
283 
284             pg->StoreOwnProperty(prop->Value()->Parent(), dest, key);
285             break;
286         }
287         case ir::MethodDefinitionKind::GET:
288         case ir::MethodDefinitionKind::SET: {
289             compiler::VReg keyReg = pg->LoadPropertyKey(prop->Key(), prop->IsComputed());
290 
291             compiler::VReg undef = pg->AllocReg();
292             pg->LoadConst(node, compiler::Constant::JS_UNDEFINED);
293             pg->StoreAccumulator(node, undef);
294 
295             compiler::VReg getter = undef;
296             compiler::VReg setter = undef;
297 
298             pg->LoadAccumulator(node, dest);
299 
300             compiler::VReg accessor = pg->AllocReg();
301             prop->Value()->Compile(pg);
302             pg->StoreAccumulator(prop->Value(), accessor);
303 
304             if (prop->Kind() == ir::MethodDefinitionKind::GET) {
305                 getter = accessor;
306             } else {
307                 setter = accessor;
308             }
309 
310             pg->DefineGetterSetterByValue(node, std::make_tuple(dest, keyReg, getter, setter), prop->IsComputed());
311             break;
312         }
313         default: {
314             ES2PANDA_UNREACHABLE();
315         }
316     }
317 }
318 
CompileMissingProperties(compiler::PandaGen * pg,const util::BitSet & compiled,compiler::VReg classReg,const ir::ClassDefinition * node)319 static void CompileMissingProperties(compiler::PandaGen *pg, const util::BitSet &compiled, compiler::VReg classReg,
320                                      const ir::ClassDefinition *node)
321 {
322     const auto &properties = node->Body();
323     std::vector<compiler::VReg> staticComputedFieldKeys;
324     compiler::VReg protoReg = pg->AllocReg();
325     compiler::VReg computedInstanceFieldsArray {};
326     uint32_t computedInstanceFieldsIndex = 0;
327 
328     pg->LoadObjByName(node, "prototype");
329     pg->StoreAccumulator(node, protoReg);
330 
331     if (node->HasComputedInstanceField()) {
332         pg->CreateEmptyArray(node);
333         computedInstanceFieldsArray = pg->AllocReg();
334         pg->StoreAccumulator(node, computedInstanceFieldsArray);
335     }
336 
337     for (size_t i = 0; i < properties.size(); i++) {
338         if (compiled.Test(i)) {
339             continue;
340         }
341 
342         if (properties[i]->IsClassStaticBlock()) {
343             continue;
344         }
345 
346         if (properties[i]->IsMethodDefinition()) {
347             const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
348             compiler::VReg dest = prop->IsStatic() ? classReg : protoReg;
349             compiler::RegScope rs(pg);
350             CompilePropertyKind(prop, dest, pg, node);
351 
352             continue;
353         }
354 
355         ES2PANDA_ASSERT(properties[i]->IsClassProperty());
356         const ir::ClassProperty *prop = properties[i]->AsClassProperty();
357 
358         if (!prop->IsComputed()) {
359             continue;
360         }
361 
362         if (prop->IsStatic()) {
363             compiler::VReg keyReg = pg->LoadPropertyKey(prop->Key(), prop->IsComputed());
364             staticComputedFieldKeys.push_back(keyReg);
365             continue;
366         }
367 
368         pg->LoadPropertyKeyAcc(prop->Key(), prop->IsComputed());
369         pg->StOwnByIndex(node, computedInstanceFieldsArray, computedInstanceFieldsIndex++);
370     }
371 
372     if (computedInstanceFieldsIndex != 0) {
373         pg->SetClassComputedFields(node, classReg, computedInstanceFieldsArray);
374     }
375 
376     CompileStaticFieldInitializers(pg, classReg, staticComputedFieldKeys, node);
377 }
378 
InitializeClassName(compiler::PandaGen * pg,const ir::ClassDefinition * node)379 static void InitializeClassName(compiler::PandaGen *pg, const ir::ClassDefinition *node)
380 {
381     if (node->Ident() == nullptr) {
382         return;
383     }
384 
385     auto lref = compiler::JSLReference::Create(pg, node->Ident(), true);
386     lref.SetValue();
387 }
388 
Compile(const ir::ClassDefinition * node) const389 void JSCompiler::Compile(const ir::ClassDefinition *node) const
390 {
391     PandaGen *pg = GetPandaGen();
392     compiler::RegScope rs(pg);
393     compiler::VReg classReg = pg->AllocReg();
394     compiler::VReg lexenv = pg->LexEnv();
395 
396     compiler::LocalRegScope lrs(pg, node->Scope());
397 
398     compiler::VReg baseReg = CompileHeritageClause(pg, node);
399     ES2PANDA_ASSERT(node->Ctor() != nullptr);
400     util::StringView ctorId = node->Ctor()->Function()->Scope()->InternalName();
401     util::BitSet compiled(node->Body().size());
402 
403     auto [bufIdx, privateBuf] = CreateClassStaticProperties(pg, compiled, node->Body());
404 
405     pg->DefineClassWithBuffer(node, ctorId, bufIdx, lexenv, baseReg);
406     pg->StoreAccumulator(node, classReg);
407 
408     if (!privateBuf.empty()) {
409         pg->DefineClassPrivateFields(node, pg->AddLiteralBuffer(std::move(privateBuf)));
410     }
411 
412     auto res = pg->Scope()->Find(node->InternalName());
413     ES2PANDA_ASSERT(res.variable);
414 
415     if (res.variable->AsLocalVariable()->LexicalBound()) {
416         pg->StoreLexicalVar(node, res.lexLevel, res.variable->AsLocalVariable()->LexIdx());
417     }
418 
419     InitializeClassName(pg, node);
420 
421     CompileMissingProperties(pg, compiled, classReg, node);
422 
423     pg->LoadAccumulator(node, classReg);
424 }
425 
Compile(const ir::MetaProperty * expr) const426 void JSCompiler::Compile(const ir::MetaProperty *expr) const
427 {
428     PandaGen *pg = GetPandaGen();
429     if (expr->Kind() == ir::MetaProperty::MetaPropertyKind::NEW_TARGET) {
430         pg->GetNewTarget(expr);
431         return;
432     }
433 
434     if (expr->Kind() == ir::MetaProperty::MetaPropertyKind::IMPORT_META) {
435         // NOTE
436         pg->Unimplemented();
437     }
438 }
439 
440 // JSCompiler::compile methods for EXPRESSIONS in alphabetical order
Compile(const ir::ArrayExpression * expr) const441 void JSCompiler::Compile(const ir::ArrayExpression *expr) const
442 {
443     PandaGen *pg = GetPandaGen();
444     compiler::RegScope rs(pg);
445     compiler::VReg arrayObj = pg->AllocReg();
446 
447     pg->CreateArray(expr, expr->Elements(), arrayObj);
448 }
449 
Compile(const ir::ArrowFunctionExpression * expr) const450 void JSCompiler::Compile(const ir::ArrowFunctionExpression *expr) const
451 {
452     PandaGen *pg = GetPandaGen();
453     pg->DefineFunction(expr->Function(), expr->Function(), expr->Function()->Scope()->InternalName());
454 }
455 
Compile(const ir::AssignmentExpression * expr) const456 void JSCompiler::Compile(const ir::AssignmentExpression *expr) const
457 {
458     PandaGen *pg = GetPandaGen();
459     compiler::RegScope rs(pg);
460     auto lref = compiler::JSLReference::Create(pg, expr->Left(), false);
461 
462     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL ||
463         expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL) {
464         compiler::PandaGen::Unimplemented();
465     }
466 
467     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
468         expr->Right()->Compile(pg);
469         lref.SetValue();
470         return;
471     }
472 
473     compiler::VReg lhsReg = pg->AllocReg();
474 
475     lref.GetValue();
476     pg->StoreAccumulator(expr->Left(), lhsReg);
477     expr->Right()->Compile(pg);
478     pg->Binary(expr, expr->OperatorType(), lhsReg);
479 
480     lref.SetValue();
481 }
482 
Compile(const ir::AwaitExpression * expr) const483 void JSCompiler::Compile(const ir::AwaitExpression *expr) const
484 {
485     PandaGen *pg = GetPandaGen();
486     compiler::RegScope rs(pg);
487 
488     if (expr->Argument() != nullptr) {
489         expr->Argument()->Compile(pg);
490     } else {
491         pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED);
492     }
493 
494     pg->EmitAwait(expr);
495 }
496 
CompileLogical(compiler::PandaGen * pg,const ir::BinaryExpression * expr)497 static void CompileLogical(compiler::PandaGen *pg, const ir::BinaryExpression *expr)
498 {
499     compiler::RegScope rs(pg);
500     compiler::VReg lhs = pg->AllocReg();
501 
502     ES2PANDA_ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND ||
503                     expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR ||
504                     expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING);
505 
506     auto *skipRight = pg->AllocLabel();
507     auto *endLabel = pg->AllocLabel();
508 
509     // left -> acc -> lhs -> toboolean -> acc -> bool_lhs
510     expr->Left()->Compile(pg);
511     pg->StoreAccumulator(expr, lhs);
512 
513     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) {
514         pg->ToBoolean(expr);
515         pg->BranchIfFalse(expr, skipRight);
516     } else if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) {
517         pg->ToBoolean(expr);
518         pg->BranchIfTrue(expr, skipRight);
519     } else if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING) {
520         pg->BranchIfCoercible(expr, skipRight);
521     }
522 
523     // left is true/false(and/or) then right -> acc
524     expr->Right()->Compile(pg);
525     pg->Branch(expr, endLabel);
526 
527     // left is false/true(and/or) then lhs -> acc
528     pg->SetLabel(expr, skipRight);
529     pg->LoadAccumulator(expr, lhs);
530     pg->SetLabel(expr, endLabel);
531 }
532 
Compile(const ir::BinaryExpression * expr) const533 void JSCompiler::Compile(const ir::BinaryExpression *expr) const
534 {
535     PandaGen *pg = GetPandaGen();
536     if (expr->IsLogical()) {
537         CompileLogical(pg, expr);
538         return;
539     }
540 
541     if (expr->OperatorType() == lexer::TokenType::KEYW_IN && expr->Left()->IsIdentifier() &&
542         expr->Left()->AsIdentifier()->IsPrivateIdent()) {
543         compiler::RegScope rs(pg);
544         compiler::VReg ctor = pg->AllocReg();
545         const auto &name = expr->Left()->AsIdentifier()->Name();
546         compiler::Function::LoadClassContexts(expr, pg, ctor, name);
547         expr->Right()->Compile(pg);
548         pg->ClassPrivateFieldIn(expr, ctor, name);
549         return;
550     }
551 
552     compiler::RegScope rs(pg);
553     compiler::VReg lhs = pg->AllocReg();
554 
555     expr->Left()->Compile(pg);
556     pg->StoreAccumulator(expr, lhs);
557     expr->Right()->Compile(pg);
558 
559     pg->Binary(expr, expr->OperatorType(), lhs);
560 }
561 
CreateSpreadArguments(compiler::PandaGen * pg,const ir::CallExpression * expr)562 static compiler::VReg CreateSpreadArguments(compiler::PandaGen *pg, const ir::CallExpression *expr)
563 {
564     compiler::VReg argsObj = pg->AllocReg();
565     pg->CreateArray(expr, expr->Arguments(), argsObj);
566 
567     return argsObj;
568 }
569 
CompileSuperExprWithoutSpread(PandaGen * pg,const ir::CallExpression * expr)570 void CompileSuperExprWithoutSpread(PandaGen *pg, const ir::CallExpression *expr)
571 {
572     compiler::RegScope paramScope(pg);
573     compiler::VReg argStart {};
574 
575     if (expr->Arguments().empty()) {
576         argStart = pg->AllocReg();
577         pg->StoreConst(expr, argStart, compiler::Constant::JS_UNDEFINED);
578     } else {
579         argStart = pg->NextReg();
580     }
581 
582     for (const auto *it : expr->Arguments()) {
583         compiler::VReg arg = pg->AllocReg();
584         it->Compile(pg);
585         pg->StoreAccumulator(it, arg);
586     }
587 
588     pg->GetFunctionObject(expr);
589     pg->SuperCall(expr, argStart, expr->Arguments().size());
590 }
591 
Compile(const ir::CallExpression * expr) const592 void JSCompiler::Compile(const ir::CallExpression *expr) const
593 {
594     PandaGen *pg = GetPandaGen();
595     compiler::RegScope rs(pg);
596     bool containsSpread = util::Helpers::ContainSpreadElement(expr->Arguments());
597 
598     if (expr->Callee()->IsSuperExpression()) {
599         if (containsSpread) {
600             compiler::RegScope paramScope(pg);
601             compiler::VReg argsObj = CreateSpreadArguments(pg, expr);
602 
603             pg->GetFunctionObject(expr);
604             pg->SuperCallSpread(expr, argsObj);
605         } else {
606             CompileSuperExprWithoutSpread(pg, expr);
607         }
608 
609         compiler::VReg newThis = pg->AllocReg();
610         pg->StoreAccumulator(expr, newThis);
611 
612         pg->GetThis(expr);
613         pg->ThrowIfSuperNotCorrectCall(expr, 1);
614 
615         pg->LoadAccumulator(expr, newThis);
616         pg->SetThis(expr);
617 
618         compiler::Function::CompileInstanceFields(pg, pg->RootNode()->AsScriptFunction());
619         return;
620     }
621 
622     compiler::VReg callee = pg->AllocReg();
623     compiler::VReg thisReg = compiler::VReg::Invalid();
624 
625     if (expr->Callee()->IsMemberExpression()) {
626         thisReg = pg->AllocReg();
627 
628         compiler::RegScope mrs(pg);
629         expr->Callee()->AsMemberExpression()->CompileToReg(pg, thisReg);
630     } else if (expr->Callee()->IsChainExpression()) {
631         thisReg = pg->AllocReg();
632 
633         compiler::RegScope mrs(pg);
634         expr->Callee()->AsChainExpression()->CompileToReg(pg, thisReg);
635     } else {
636         expr->Callee()->Compile(pg);
637     }
638 
639     pg->StoreAccumulator(expr, callee);
640     pg->OptionalChainCheck(expr->IsOptional(), callee);
641 
642     if (containsSpread || expr->Arguments().size() >= compiler::PandaGen::MAX_RANGE_CALL_ARG) {
643         if (thisReg.IsInvalid()) {
644             thisReg = pg->AllocReg();
645             pg->StoreConst(expr, thisReg, compiler::Constant::JS_UNDEFINED);
646         }
647 
648         compiler::VReg argsObj = CreateSpreadArguments(pg, expr);
649         pg->CallSpread(expr, callee, thisReg, argsObj);
650     } else {
651         pg->Call(expr, callee, thisReg, expr->Arguments());
652     }
653 }
654 
Compile(const ir::ChainExpression * expr) const655 void JSCompiler::Compile(const ir::ChainExpression *expr) const
656 {
657     PandaGen *pg = GetPandaGen();
658     compiler::OptionalChain chain(pg, expr);
659     expr->GetExpression()->Compile(pg);
660 }
661 
Compile(const ir::ClassExpression * expr) const662 void JSCompiler::Compile(const ir::ClassExpression *expr) const
663 {
664     PandaGen *pg = GetPandaGen();
665     expr->Definition()->Compile(pg);
666 }
667 
668 template <typename CodeGen>
CompileImpl(const ir::ConditionalExpression * self,CodeGen * cg)669 static void CompileImpl(const ir::ConditionalExpression *self, CodeGen *cg)
670 {
671     auto *falseLabel = cg->AllocLabel();
672     auto *endLabel = cg->AllocLabel();
673 
674     compiler::Condition::Compile(cg, self->Test(), falseLabel);
675     self->Consequent()->Compile(cg);
676     cg->Branch(self, endLabel);
677     cg->SetLabel(self, falseLabel);
678     self->Alternate()->Compile(cg);
679     cg->SetLabel(self, endLabel);
680 }
681 
Compile(const ir::ConditionalExpression * expr) const682 void JSCompiler::Compile(const ir::ConditionalExpression *expr) const
683 {
684     PandaGen *pg = GetPandaGen();
685     CompileImpl(expr, pg);
686 }
687 
Compile(const ir::DirectEvalExpression * expr) const688 void JSCompiler::Compile(const ir::DirectEvalExpression *expr) const
689 {
690     PandaGen *pg = GetPandaGen();
691     if (expr->Arguments().empty()) {
692         pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED);
693         return;
694     }
695 
696     compiler::RegScope rs(pg);
697     bool containsSpread = util::Helpers::ContainSpreadElement(expr->Arguments());
698     if (containsSpread) {
699         [[maybe_unused]] compiler::VReg argsObj = CreateSpreadArguments(pg, expr);
700         pg->LoadObjByIndex(expr, 0);
701     } else {
702         compiler::VReg arg0 = pg->AllocReg();
703         auto iter = expr->Arguments().cbegin();
704         (*iter++)->Compile(pg);
705         pg->StoreAccumulator(expr, arg0);
706 
707         while (iter != expr->Arguments().cend()) {
708             (*iter++)->Compile(pg);
709         }
710 
711         pg->LoadAccumulator(expr, arg0);
712     }
713 
714     pg->DirectEval(expr, expr->parserStatus_);
715 }
716 
Compile(const ir::FunctionExpression * expr) const717 void JSCompiler::Compile(const ir::FunctionExpression *expr) const
718 {
719     PandaGen *pg = GetPandaGen();
720     pg->DefineFunction(expr->Function(), expr->Function(), expr->Function()->Scope()->InternalName());
721 }
722 
Compile(const ir::Identifier * expr) const723 void JSCompiler::Compile(const ir::Identifier *expr) const
724 {
725     PandaGen *pg = GetPandaGen();
726     auto res = pg->Scope()->Find(expr->Name());
727     if (res.variable != nullptr) {
728         pg->LoadVar(expr, res);
729         return;
730     }
731 
732     if (pg->IsDirectEval()) {
733         pg->LoadEvalVariable(expr, expr->Name());
734         return;
735     }
736 
737     if (expr->Name().Is("NaN")) {
738         pg->LoadConst(expr, compiler::Constant::JS_NAN);
739         return;
740     }
741 
742     if (expr->Name().Is("Infinity")) {
743         pg->LoadConst(expr, compiler::Constant::JS_INFINITY);
744         return;
745     }
746 
747     if (expr->Name().Is("globalThis")) {
748         pg->LoadConst(expr, compiler::Constant::JS_GLOBAL);
749         return;
750     }
751 
752     if (expr->Name().Is("undefined")) {
753         pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED);
754         return;
755     }
756 
757     pg->TryLoadGlobalByName(expr, expr->Name());
758 }
759 
Compile(const ir::ImportExpression * expr) const760 void JSCompiler::Compile([[maybe_unused]] const ir::ImportExpression *expr) const
761 {
762     PandaGen *pg = GetPandaGen();
763     pg->Unimplemented();
764 }
765 
Compile(const ir::MemberExpression * expr) const766 void JSCompiler::Compile(const ir::MemberExpression *expr) const
767 {
768     PandaGen *pg = GetPandaGen();
769     expr->Object()->Compile(pg);
770     pg->OptionalChainCheck(expr->IsOptional(), compiler::VReg::Invalid());
771     expr->LoadRhs(pg);
772 }
773 
Compile(const ir::NewExpression * expr) const774 void JSCompiler::Compile(const ir::NewExpression *expr) const
775 {
776     PandaGen *pg = GetPandaGen();
777     compiler::RegScope rs(pg);
778     compiler::VReg ctor = pg->AllocReg();
779     compiler::VReg newTarget = pg->AllocReg();
780 
781     expr->Callee()->Compile(pg);
782     pg->StoreAccumulator(expr, ctor);
783 
784     // new.Target will be the same as ctor
785     pg->StoreAccumulator(expr, newTarget);
786 
787     if (!util::Helpers::ContainSpreadElement(expr->Arguments()) &&
788         expr->Arguments().size() < compiler::PandaGen::MAX_RANGE_CALL_ARG) {
789         for (const auto *it : expr->Arguments()) {
790             compiler::VReg arg = pg->AllocReg();
791             it->Compile(pg);
792             pg->StoreAccumulator(expr, arg);
793         }
794 
795         pg->NewObject(expr, ctor, expr->Arguments().size() + 2U);
796     } else {
797         compiler::VReg argsObj = pg->AllocReg();
798 
799         pg->CreateArray(expr, expr->Arguments(), argsObj);
800         pg->NewObjSpread(expr, ctor, newTarget);
801     }
802 }
803 
Compile(const ir::ObjectExpression * expr) const804 void JSCompiler::Compile(const ir::ObjectExpression *expr) const
805 {
806     PandaGen *pg = GetPandaGen();
807     if (expr->Properties().empty()) {
808         pg->CreateEmptyObject(expr);
809         return;
810     }
811 
812     util::BitSet compiled(expr->Properties().size());
813     CompileStaticProperties(pg, &compiled, expr);
814 
815     if (compiled.Any(false)) {
816         CompileRemainingProperties(pg, &compiled, expr);
817     }
818 }
819 
CreateLiteral(const ir::Property * prop,util::BitSet * compiled,size_t propIndex)820 static compiler::Literal CreateLiteral(const ir::Property *prop, util::BitSet *compiled, size_t propIndex)
821 {
822     compiler::Literal lit = util::Helpers::ToConstantLiteral(prop->Value());
823     if (!lit.IsInvalid()) {
824         compiled->Set(propIndex);
825         return lit;
826     }
827 
828     if (prop->Kind() != ir::PropertyKind::INIT) {
829         ES2PANDA_ASSERT(prop->IsAccessor());
830         return compiler::Literal::AccessorLiteral();
831     }
832 
833     if (!prop->Value()->IsFunctionExpression()) {
834         return compiler::Literal::NullLiteral();
835     }
836 
837     const ir::ScriptFunction *method = prop->Value()->AsFunctionExpression()->Function();
838 
839     compiler::LiteralTag tag = compiler::LiteralTag::METHOD;
840 
841     if (method->IsGenerator()) {
842         tag = compiler::LiteralTag::GENERATOR_METHOD;
843 
844         if (method->IsAsyncFunc()) {
845             tag = compiler::LiteralTag::ASYNC_GENERATOR_METHOD;
846         }
847     }
848 
849     compiled->Set(propIndex);
850     return compiler::Literal(tag, method->Scope()->InternalName());
851 }
852 
IsLiteralBufferCompatible(const ir::Expression * expr)853 static bool IsLiteralBufferCompatible(const ir::Expression *expr)
854 {
855     if (expr->IsSpreadElement()) {
856         return false;
857     }
858 
859     const ir::Property *prop = expr->AsProperty();
860     if (prop->Value()->IsFunctionExpression() && !prop->Value()->AsFunctionExpression()->Function()->IsMethod()) {
861         return false;
862     }
863 
864     return util::Helpers::IsConstantPropertyKey(prop->Key(), prop->IsComputed()) &&
865            prop->Kind() != ir::PropertyKind::PROTO;
866 }
867 
CompileStaticProperties(compiler::PandaGen * pg,util::BitSet * compiled,const ir::ObjectExpression * expr) const868 void JSCompiler::CompileStaticProperties(compiler::PandaGen *pg, util::BitSet *compiled,
869                                          const ir::ObjectExpression *expr) const
870 {
871     bool hasMethod = false;
872     bool seenComputed = false;
873     compiler::LiteralBuffer buf;
874     std::unordered_map<util::StringView, size_t> propNameMap;
875 
876     for (size_t i = 0; i < expr->Properties().size(); i++) {
877         if (!IsLiteralBufferCompatible(expr->Properties()[i])) {
878             seenComputed = true;
879             continue;
880         }
881 
882         const ir::Property *prop = expr->Properties()[i]->AsProperty();
883 
884         util::StringView name = util::Helpers::LiteralToPropName(prop->Key());
885         size_t bufferPos = buf.size();
886         auto res = propNameMap.insert({name, bufferPos});
887         if (res.second) {
888             if (seenComputed) {
889                 break;
890             }
891 
892             buf.emplace_back(name);
893             buf.emplace_back();
894         } else {
895             bufferPos = res.first->second;
896         }
897 
898         compiler::Literal lit = CreateLiteral(prop, compiled, i);
899         if (lit.IsTagMethod()) {
900             hasMethod = true;
901         }
902 
903         buf[bufferPos + 1] = std::move(lit);
904     }
905 
906     if (buf.empty()) {
907         pg->CreateEmptyObject(expr);
908         return;
909     }
910 
911     uint32_t bufIdx = pg->AddLiteralBuffer(std::move(buf));
912 
913     if (hasMethod) {
914         pg->CreateObjectHavingMethod(expr, bufIdx);
915     } else {
916         pg->CreateObjectWithBuffer(expr, bufIdx);
917     }
918 }
919 
CompileRemainingPropertyKind(const ir::Property * prop,compiler::VReg objReg,compiler::PandaGen * pg,const ir::ObjectExpression * expr)920 void CompileRemainingPropertyKind(const ir::Property *prop, compiler::VReg objReg, compiler::PandaGen *pg,
921                                   const ir::ObjectExpression *expr)
922 {
923     switch (prop->Kind()) {
924         case ir::PropertyKind::GET:
925         case ir::PropertyKind::SET: {
926             compiler::VReg key = pg->LoadPropertyKey(prop->Key(), prop->IsComputed());
927 
928             compiler::VReg undef = pg->AllocReg();
929             pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED);
930             pg->StoreAccumulator(expr, undef);
931 
932             compiler::VReg getter = undef;
933             compiler::VReg setter = undef;
934 
935             compiler::VReg accessor = pg->AllocReg();
936             pg->LoadAccumulator(prop->Value(), objReg);
937             prop->Value()->Compile(pg);
938             pg->StoreAccumulator(prop->Value(), accessor);
939 
940             if (prop->Kind() == ir::PropertyKind::GET) {
941                 getter = accessor;
942             } else {
943                 setter = accessor;
944             }
945 
946             pg->DefineGetterSetterByValue(expr, std::make_tuple(objReg, key, getter, setter), prop->IsComputed());
947             break;
948         }
949         case ir::PropertyKind::INIT: {
950             compiler::Operand key = pg->ToOwnPropertyKey(prop->Key(), prop->IsComputed());
951 
952             if (prop->IsMethod()) {
953                 pg->LoadAccumulator(prop->Value(), objReg);
954             }
955 
956             prop->Value()->Compile(pg);
957             pg->StoreOwnProperty(expr, objReg, key);
958             break;
959         }
960         case ir::PropertyKind::PROTO: {
961             prop->Value()->Compile(pg);
962             compiler::VReg proto = pg->AllocReg();
963             pg->StoreAccumulator(expr, proto);
964 
965             pg->SetObjectWithProto(expr, proto, objReg);
966             break;
967         }
968         default: {
969             ES2PANDA_UNREACHABLE();
970         }
971     }
972 }
973 
CompileRemainingProperties(compiler::PandaGen * pg,const util::BitSet * compiled,const ir::ObjectExpression * expr) const974 void JSCompiler::CompileRemainingProperties(compiler::PandaGen *pg, const util::BitSet *compiled,
975                                             const ir::ObjectExpression *expr) const
976 {
977     compiler::RegScope rs(pg);
978     compiler::VReg objReg = pg->AllocReg();
979 
980     pg->StoreAccumulator(expr, objReg);
981 
982     for (size_t i = 0; i < expr->Properties().size(); i++) {
983         if (compiled->Test(i)) {
984             continue;
985         }
986 
987         compiler::RegScope prs(pg);
988 
989         if (expr->Properties()[i]->IsSpreadElement()) {
990             compiler::VReg srcObj = pg->AllocReg();
991             auto const *const spread = expr->Properties()[i]->AsSpreadElement();
992 
993             spread->Argument()->Compile(pg);
994             pg->StoreAccumulator(spread, srcObj);
995 
996             pg->CopyDataProperties(spread, objReg, srcObj);
997             continue;
998         }
999 
1000         const ir::Property *prop = expr->Properties()[i]->AsProperty();
1001         CompileRemainingPropertyKind(prop, objReg, pg, expr);
1002     }
1003 
1004     pg->LoadAccumulator(expr, objReg);
1005 }
1006 
Compile(const ir::SequenceExpression * expr) const1007 void JSCompiler::Compile(const ir::SequenceExpression *expr) const
1008 {
1009     PandaGen *pg = GetPandaGen();
1010     for (const auto *it : expr->Sequence()) {
1011         it->Compile(pg);
1012     }
1013 }
1014 
Compile(const ir::SuperExpression * expr) const1015 void JSCompiler::Compile(const ir::SuperExpression *expr) const
1016 {
1017     PandaGen *pg = GetPandaGen();
1018     pg->GetThis(expr);
1019 
1020     const ir::ScriptFunction *func = util::Helpers::GetContainingConstructor(expr);
1021 
1022     if (func != nullptr) {
1023         pg->ThrowIfSuperNotCorrectCall(expr, 0);
1024     }
1025 }
1026 
Compile(const ir::TaggedTemplateExpression * expr) const1027 void JSCompiler::Compile(const ir::TaggedTemplateExpression *expr) const
1028 {
1029     PandaGen *pg = GetPandaGen();
1030     compiler::RegScope rs(pg);
1031     compiler::VReg callee = pg->AllocReg();
1032     compiler::VReg thisReg = compiler::VReg::Invalid();
1033 
1034     if (expr->Tag()->IsMemberExpression()) {
1035         thisReg = pg->AllocReg();
1036         compiler::RegScope mrs(pg);
1037         expr->Tag()->AsMemberExpression()->CompileToReg(pg, thisReg);
1038     } else {
1039         expr->Tag()->Compile(pg);
1040     }
1041 
1042     pg->CallTagged(expr, callee, thisReg, expr->Quasi()->Expressions());
1043 }
1044 
Compile(const ir::TemplateLiteral * expr) const1045 void JSCompiler::Compile(const ir::TemplateLiteral *expr) const
1046 {
1047     PandaGen *pg = GetPandaGen();
1048     auto quasisIt = expr->Quasis().begin();
1049     auto expressionIt = expr->Expressions().begin();
1050 
1051     pg->LoadAccumulatorString(expr, (*quasisIt)->Raw());
1052 
1053     quasisIt++;
1054 
1055     bool isQuais = false;
1056     size_t total = expr->Quasis().size() + expr->Expressions().size();
1057 
1058     compiler::RegScope rs(pg);
1059     compiler::VReg lhs = pg->AllocReg();
1060 
1061     while (total != 1) {
1062         const ir::AstNode *node = nullptr;
1063 
1064         if (isQuais) {
1065             pg->StoreAccumulator(*quasisIt, lhs);
1066             pg->LoadAccumulatorString(expr, (*quasisIt)->Raw());
1067 
1068             node = *quasisIt;
1069             quasisIt++;
1070         } else {
1071             const ir::Expression *element = *expressionIt;
1072             pg->StoreAccumulator(element, lhs);
1073 
1074             element->Compile(pg);
1075 
1076             node = element;
1077             expressionIt++;
1078         }
1079 
1080         pg->Binary(node, lexer::TokenType::PUNCTUATOR_PLUS, lhs);
1081 
1082         isQuais = !isQuais;
1083         total--;
1084     }
1085 }
1086 
Compile(const ir::ThisExpression * expr) const1087 void JSCompiler::Compile(const ir::ThisExpression *expr) const
1088 {
1089     PandaGen *pg = GetPandaGen();
1090     auto res = pg->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS);
1091 
1092     ES2PANDA_ASSERT(res.variable && res.variable->IsLocalVariable());
1093     pg->LoadAccFromLexEnv(expr, res);
1094 
1095     const ir::ScriptFunction *func = util::Helpers::GetContainingConstructor(expr);
1096 
1097     if (func != nullptr) {
1098         pg->ThrowIfSuperNotCorrectCall(expr, 0);
1099     }
1100 }
1101 
Compile(const ir::TypeofExpression * expr) const1102 void JSCompiler::Compile([[maybe_unused]] const ir::TypeofExpression *expr) const
1103 {
1104     PandaGen *pg = GetPandaGen();
1105 
1106     if (expr->Argument()->IsIdentifier()) {
1107         const auto *ident = expr->Argument()->AsIdentifier();
1108 
1109         auto res = pg->Scope()->Find(ident->Name());
1110         if (res.variable == nullptr) {
1111             pg->LoadConst(expr, compiler::Constant::JS_GLOBAL);
1112             pg->LoadObjByName(expr, ident->Name());
1113         } else {
1114             pg->LoadVar(ident, res);
1115         }
1116     } else {
1117         expr->Argument()->Compile(pg);
1118     }
1119 
1120     pg->TypeOf(expr);
1121 }
1122 
Compile(const ir::UnaryExpression * expr) const1123 void JSCompiler::Compile(const ir::UnaryExpression *expr) const
1124 {
1125     PandaGen *pg = GetPandaGen();
1126     switch (expr->OperatorType()) {
1127         case lexer::TokenType::KEYW_DELETE: {
1128             if (expr->Argument()->IsIdentifier()) {
1129                 auto result = pg->Scope()->Find(expr->Argument()->AsIdentifier()->Name());
1130                 if (result.variable == nullptr ||
1131                     (result.scope->IsGlobalScope() && result.variable->IsGlobalVariable())) {
1132                     compiler::RegScope rs(pg);
1133                     compiler::VReg variable = pg->AllocReg();
1134                     compiler::VReg global = pg->AllocReg();
1135 
1136                     pg->LoadConst(expr, compiler::Constant::JS_GLOBAL);
1137                     pg->StoreAccumulator(expr, global);
1138 
1139                     pg->LoadAccumulatorString(expr, expr->Argument()->AsIdentifier()->Name());
1140                     pg->StoreAccumulator(expr, variable);
1141 
1142                     pg->DeleteObjProperty(expr, global, variable);
1143                 } else {
1144                     // Otherwise it is a local variable which can't be deleted and we just
1145                     // return false.
1146                     pg->LoadConst(expr, compiler::Constant::JS_FALSE);
1147                 }
1148             } else if (expr->Argument()->IsMemberExpression()) {
1149                 compiler::RegScope rs(pg);
1150                 compiler::VReg object = pg->AllocReg();
1151                 compiler::VReg property = pg->AllocReg();
1152 
1153                 expr->Argument()->AsMemberExpression()->CompileToRegs(pg, object, property);
1154                 pg->DeleteObjProperty(expr, object, property);
1155             } else {
1156                 // compile the delete operand.
1157                 expr->Argument()->Compile(pg);
1158                 // Deleting any value or a result of an expression returns True.
1159                 pg->LoadConst(expr, compiler::Constant::JS_TRUE);
1160             }
1161             break;
1162         }
1163         case lexer::TokenType::KEYW_VOID: {
1164             expr->Argument()->Compile(pg);
1165             pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED);
1166             break;
1167         }
1168         default: {
1169             expr->Argument()->Compile(pg);
1170 
1171             compiler::RegScope rs(pg);
1172             compiler::VReg operandReg = pg->AllocReg();
1173             pg->StoreAccumulator(expr, operandReg);
1174             pg->Unary(expr, expr->OperatorType(), operandReg);
1175             break;
1176         }
1177     }
1178 }
1179 
Compile(const ir::UpdateExpression * expr) const1180 void JSCompiler::Compile(const ir::UpdateExpression *expr) const
1181 {
1182     PandaGen *pg = GetPandaGen();
1183     compiler::RegScope rs(pg);
1184     compiler::VReg operandReg = pg->AllocReg();
1185 
1186     auto lref = compiler::JSLReference::Create(pg, expr->Argument(), false);
1187     lref.GetValue();
1188 
1189     pg->StoreAccumulator(expr, operandReg);
1190     pg->Unary(expr, expr->OperatorType(), operandReg);
1191 
1192     lref.SetValue();
1193 
1194     if (!expr->IsPrefix()) {
1195         pg->ToNumber(expr, operandReg);
1196     }
1197 }
1198 
Compile(const ir::YieldExpression * expr) const1199 void JSCompiler::Compile(const ir::YieldExpression *expr) const
1200 {
1201     PandaGen *pg = GetPandaGen();
1202     compiler::RegScope rs(pg);
1203 
1204     if (expr->Argument() != nullptr) {
1205         expr->Argument()->Compile(pg);
1206     } else {
1207         pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED);
1208     }
1209 
1210     if (expr->HasDelegate()) {
1211         ES2PANDA_ASSERT(expr->Argument());
1212         pg->FuncBuilder()->YieldStar(expr);
1213     } else {
1214         pg->FuncBuilder()->Yield(expr);
1215     }
1216 }
1217 
1218 // Compile methods for LITERAL EXPRESSIONS in alphabetical order
Compile(const ir::BigIntLiteral * expr) const1219 void JSCompiler::Compile(const ir::BigIntLiteral *expr) const
1220 {
1221     PandaGen *pg = GetPandaGen();
1222     pg->LoadAccumulatorBigInt(expr, expr->Str());
1223 }
1224 
Compile(const ir::BooleanLiteral * expr) const1225 void JSCompiler::Compile(const ir::BooleanLiteral *expr) const
1226 {
1227     PandaGen *pg = GetPandaGen();
1228     pg->LoadConst(expr, expr->Value() ? compiler::Constant::JS_TRUE : compiler::Constant::JS_FALSE);
1229 }
1230 
Compile(const ir::NullLiteral * expr) const1231 void JSCompiler::Compile(const ir::NullLiteral *expr) const
1232 {
1233     PandaGen *pg = GetPandaGen();
1234     pg->LoadConst(expr, compiler::Constant::JS_NULL);
1235 }
1236 
Compile(const ir::NumberLiteral * expr) const1237 void JSCompiler::Compile(const ir::NumberLiteral *expr) const
1238 {
1239     PandaGen *pg = GetPandaGen();
1240     if (std::isnan(expr->Number().GetDouble())) {
1241         pg->LoadConst(expr, compiler::Constant::JS_NAN);
1242     } else if (!std::isfinite(expr->Number().GetDouble())) {
1243         pg->LoadConst(expr, compiler::Constant::JS_INFINITY);
1244     } else if (util::Helpers::IsInteger<int32_t>(expr->Number().GetDouble())) {
1245         pg->LoadAccumulatorInt(expr, static_cast<int32_t>(expr->Number().GetDouble()));
1246     } else {
1247         pg->LoadAccumulatorDouble(expr, expr->Number().GetDouble());
1248     }
1249 }
1250 
Compile(const ir::RegExpLiteral * expr) const1251 void JSCompiler::Compile(const ir::RegExpLiteral *expr) const
1252 {
1253     PandaGen *pg = GetPandaGen();
1254     pg->CreateRegExpWithLiteral(expr, expr->Pattern(), static_cast<uint8_t>(expr->Flags()));
1255 }
1256 
Compile(const ir::StringLiteral * expr) const1257 void JSCompiler::Compile(const ir::StringLiteral *expr) const
1258 {
1259     PandaGen *pg = GetPandaGen();
1260     pg->LoadAccumulatorString(expr, expr->Str());
1261 }
1262 
1263 // Compile methods for MODULE-related nodes in alphabetical order
Compile(const ir::ExportAllDeclaration * st) const1264 void JSCompiler::Compile([[maybe_unused]] const ir::ExportAllDeclaration *st) const {}
1265 
Compile(const ir::ExportDefaultDeclaration * st) const1266 void JSCompiler::Compile(const ir::ExportDefaultDeclaration *st) const
1267 {
1268     PandaGen *pg = GetPandaGen();
1269     st->Decl()->Compile(pg);
1270     pg->StoreModuleVar(st, "default");
1271 }
1272 
Compile(const ir::ExportNamedDeclaration * st) const1273 void JSCompiler::Compile(const ir::ExportNamedDeclaration *st) const
1274 {
1275     PandaGen *pg = GetPandaGen();
1276     if (st->Decl() == nullptr) {
1277         return;
1278     }
1279 
1280     st->Decl()->Compile(pg);
1281 }
1282 
Compile(const ir::ImportDeclaration * st) const1283 void JSCompiler::Compile([[maybe_unused]] const ir::ImportDeclaration *st) const {}
1284 
Compile(const ir::BlockStatement * st) const1285 void JSCompiler::Compile(const ir::BlockStatement *st) const
1286 {
1287     PandaGen *pg = GetPandaGen();
1288     compiler::LocalRegScope lrs(pg, st->Scope());
1289 
1290     for (const auto *it : st->Statements()) {
1291         it->Compile(pg);
1292     }
1293 }
1294 
1295 template <typename CodeGen>
CompileImpl(const ir::BreakStatement * self,CodeGen * cg)1296 static void CompileImpl(const ir::BreakStatement *self, [[maybe_unused]] CodeGen *cg)
1297 {
1298     compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident());
1299     cg->Branch(self, target);
1300 }
Compile(const ir::BreakStatement * st) const1301 void JSCompiler::Compile(const ir::BreakStatement *st) const
1302 {
1303     PandaGen *pg = GetPandaGen();
1304     CompileImpl(st, pg);
1305 }
1306 
Compile(const ir::ClassDeclaration * st) const1307 void JSCompiler::Compile(const ir::ClassDeclaration *st) const
1308 {
1309     PandaGen *pg = GetPandaGen();
1310     auto lref = compiler::JSLReference::Create(pg, st->Definition()->Ident(), true);
1311     st->Definition()->Compile(pg);
1312     lref.SetValue();
1313 }
1314 
CompileImpl(const ir::ContinueStatement * self,PandaGen * cg)1315 static void CompileImpl(const ir::ContinueStatement *self, PandaGen *cg)
1316 {
1317     compiler::Label *target = cg->ControlFlowChangeContinue(self->Ident());
1318     cg->Branch(self, target);
1319 }
1320 
Compile(const ir::ContinueStatement * st) const1321 void JSCompiler::Compile(const ir::ContinueStatement *st) const
1322 {
1323     PandaGen *pg = GetPandaGen();
1324     CompileImpl(st, pg);
1325 }
1326 
Compile(const ir::DebuggerStatement * st) const1327 void JSCompiler::Compile([[maybe_unused]] const ir::DebuggerStatement *st) const {}
1328 
CompileImpl(const ir::DoWhileStatement * self,PandaGen * cg)1329 static void CompileImpl(const ir::DoWhileStatement *self, PandaGen *cg)
1330 {
1331     auto *startLabel = cg->AllocLabel();
1332     compiler::LabelTarget labelTarget(cg);
1333 
1334     cg->SetLabel(self, startLabel);
1335 
1336     {
1337         compiler::LocalRegScope regScope(cg, self->Scope());
1338         compiler::LabelContext labelCtx(cg, labelTarget);
1339         self->Body()->Compile(cg);
1340     }
1341 
1342     cg->SetLabel(self, labelTarget.ContinueTarget());
1343     compiler::Condition::Compile(cg, self->Test(), labelTarget.BreakTarget());
1344 
1345     cg->Branch(self, startLabel);
1346     cg->SetLabel(self, labelTarget.BreakTarget());
1347 }
1348 
Compile(const ir::DoWhileStatement * st) const1349 void JSCompiler::Compile(const ir::DoWhileStatement *st) const
1350 {
1351     PandaGen *pg = GetPandaGen();
1352     CompileImpl(st, pg);
1353 }
1354 
Compile(const ir::EmptyStatement * st) const1355 void JSCompiler::Compile([[maybe_unused]] const ir::EmptyStatement *st) const {}
1356 
Compile(const ir::ExpressionStatement * st) const1357 void JSCompiler::Compile(const ir::ExpressionStatement *st) const
1358 {
1359     PandaGen *pg = GetPandaGen();
1360     st->GetExpression()->Compile(pg);
1361 }
1362 
Compile(const ir::ForInStatement * st) const1363 void JSCompiler::Compile(const ir::ForInStatement *st) const
1364 {
1365     PandaGen *pg = GetPandaGen();
1366     compiler::LabelTarget labelTarget(pg);
1367 
1368     compiler::RegScope rs(pg);
1369     compiler::VReg iter = pg->AllocReg();
1370     compiler::VReg propName = pg->AllocReg();
1371 
1372     // create enumerator
1373     st->Right()->Compile(pg);
1374     pg->GetPropIterator(st);
1375     pg->StoreAccumulator(st, iter);
1376 
1377     pg->SetLabel(st, labelTarget.ContinueTarget());
1378 
1379     // get next prop of enumerator
1380     pg->GetNextPropName(st, iter);
1381     pg->StoreAccumulator(st, propName);
1382     pg->BranchIfUndefined(st, labelTarget.BreakTarget());
1383 
1384     compiler::LocalRegScope declRegScope(pg, st->Scope()->DeclScope()->InitScope());
1385     auto lref = compiler::JSLReference::Create(pg, st->Left(), false);
1386     pg->LoadAccumulator(st, propName);
1387     lref.SetValue();
1388 
1389     compiler::LoopEnvScope declEnvScope(pg, st->Scope()->DeclScope());
1390 
1391     {
1392         compiler::LoopEnvScope envScope(pg, st->Scope(), labelTarget);
1393         st->Body()->Compile(pg);
1394     }
1395 
1396     pg->Branch(st, labelTarget.ContinueTarget());
1397     pg->SetLabel(st, labelTarget.BreakTarget());
1398 }
1399 
Compile(const ir::ForOfStatement * st) const1400 void JSCompiler::Compile(const ir::ForOfStatement *st) const
1401 {
1402     PandaGen *pg = GetPandaGen();
1403     compiler::LocalRegScope declRegScope(pg, st->Scope()->DeclScope()->InitScope());
1404 
1405     st->Right()->Compile(pg);
1406 
1407     compiler::LabelTarget labelTarget(pg);
1408     auto iteratorType = st->IsAwait() ? compiler::IteratorType::ASYNC : compiler::IteratorType::SYNC;
1409     compiler::Iterator iterator(pg, st, iteratorType);
1410 
1411     pg->SetLabel(st, labelTarget.ContinueTarget());
1412 
1413     iterator.Next();
1414     iterator.Complete();
1415     pg->BranchIfTrue(st, labelTarget.BreakTarget());
1416 
1417     iterator.Value();
1418     pg->StoreAccumulator(st, iterator.NextResult());
1419 
1420     auto lref = compiler::JSLReference::Create(pg, st->Left(), false);
1421 
1422     {
1423         compiler::IteratorContext forOfCtx(pg, iterator, labelTarget);
1424         pg->LoadAccumulator(st, iterator.NextResult());
1425         lref.SetValue();
1426 
1427         compiler::LoopEnvScope declEnvScope(pg, st->Scope()->DeclScope());
1428         compiler::LoopEnvScope envScope(pg, st->Scope(), {});
1429         st->Body()->Compile(pg);
1430     }
1431 
1432     pg->Branch(st, labelTarget.ContinueTarget());
1433     pg->SetLabel(st, labelTarget.BreakTarget());
1434 }
1435 
Compile(const ir::ForUpdateStatement * st) const1436 void JSCompiler::Compile(const ir::ForUpdateStatement *st) const
1437 {
1438     PandaGen *pg = GetPandaGen();
1439     compiler::LocalRegScope declRegScope(pg, st->Scope()->DeclScope()->InitScope());
1440 
1441     if (st->Init() != nullptr) {
1442         ES2PANDA_ASSERT(st->Init()->IsVariableDeclaration() || st->Init()->IsExpression());
1443         st->Init()->Compile(pg);
1444     }
1445 
1446     auto *startLabel = pg->AllocLabel();
1447     compiler::LabelTarget labelTarget(pg);
1448 
1449     compiler::LoopEnvScope declEnvScope(pg, st->Scope()->DeclScope());
1450     compiler::LoopEnvScope envScope(pg, labelTarget, st->Scope());
1451     pg->SetLabel(st, startLabel);
1452 
1453     {
1454         compiler::LocalRegScope regScope(pg, st->Scope());
1455 
1456         if (st->Test() != nullptr) {
1457             compiler::Condition::Compile(pg, st->Test(), labelTarget.BreakTarget());
1458         }
1459 
1460         st->Body()->Compile(pg);
1461         pg->SetLabel(st, labelTarget.ContinueTarget());
1462         envScope.CopyPetIterationCtx();
1463     }
1464 
1465     if (st->Update() != nullptr) {
1466         st->Update()->Compile(pg);
1467     }
1468 
1469     pg->Branch(st, startLabel);
1470     pg->SetLabel(st, labelTarget.BreakTarget());
1471 }
1472 
Compile(const ir::FunctionDeclaration * st) const1473 void JSCompiler::Compile([[maybe_unused]] const ir::FunctionDeclaration *st) const {}
Compile(const ir::AnnotationDeclaration * st) const1474 void JSCompiler::Compile([[maybe_unused]] const ir::AnnotationDeclaration *st) const {}
Compile(const ir::AnnotationUsage * st) const1475 void JSCompiler::Compile([[maybe_unused]] const ir::AnnotationUsage *st) const {}
1476 
Compile(const ir::IfStatement * st) const1477 void JSCompiler::Compile(const ir::IfStatement *st) const
1478 {
1479     PandaGen *pg = GetPandaGen();
1480     auto *consequentEnd = pg->AllocLabel();
1481     compiler::Label *statementEnd = consequentEnd;
1482 
1483     compiler::Condition::Compile(pg, st->Test(), consequentEnd);
1484     st->Consequent()->Compile(pg);
1485 
1486     if (st->Alternate() != nullptr) {
1487         statementEnd = pg->AllocLabel();
1488         pg->Branch(pg->Insns().back()->Node(), statementEnd);
1489 
1490         pg->SetLabel(st, consequentEnd);
1491         st->Alternate()->Compile(pg);
1492     }
1493 
1494     pg->SetLabel(st, statementEnd);
1495 }
1496 
CompileImpl(const ir::LabelledStatement * self,PandaGen * cg)1497 void CompileImpl(const ir::LabelledStatement *self, PandaGen *cg)
1498 {
1499     compiler::LabelContext labelCtx(cg, self);
1500     self->Body()->Compile(cg);
1501 }
1502 
Compile(const ir::LabelledStatement * st) const1503 void JSCompiler::Compile(const ir::LabelledStatement *st) const
1504 {
1505     PandaGen *pg = GetPandaGen();
1506     CompileImpl(st, pg);
1507 }
1508 
Compile(const ir::ReturnStatement * st) const1509 void JSCompiler::Compile(const ir::ReturnStatement *st) const
1510 {
1511     PandaGen *pg = GetPandaGen();
1512     if (st->Argument() != nullptr) {
1513         st->Argument()->Compile(pg);
1514     } else {
1515         pg->LoadConst(st, compiler::Constant::JS_UNDEFINED);
1516     }
1517 
1518     if (pg->CheckControlFlowChange()) {
1519         compiler::RegScope rs(pg);
1520         compiler::VReg res = pg->AllocReg();
1521 
1522         pg->StoreAccumulator(st, res);
1523         pg->ControlFlowChangeBreak();
1524         pg->LoadAccumulator(st, res);
1525     }
1526 
1527     if (st->Argument() != nullptr) {
1528         pg->ValidateClassDirectReturn(st);
1529         pg->DirectReturn(st);
1530     } else {
1531         pg->ImplicitReturn(st);
1532     }
1533 }
1534 
CompileImpl(const ir::SwitchStatement * self,PandaGen * cg)1535 static void CompileImpl(const ir::SwitchStatement *self, PandaGen *cg)
1536 {
1537     compiler::LocalRegScope lrs(cg, self->Scope());
1538     compiler::SwitchBuilder builder(cg, self);
1539     compiler::VReg tag = cg->AllocReg();
1540 
1541     builder.CompileTagOfSwitch(tag);
1542     uint32_t defaultIndex = 0;
1543 
1544     for (size_t i = 0; i < self->Cases().size(); i++) {
1545         const auto *clause = self->Cases()[i];
1546 
1547         if (clause->Test() == nullptr) {
1548             defaultIndex = i;
1549             continue;
1550         }
1551 
1552         builder.JumpIfCase(tag, i);
1553     }
1554 
1555     if (defaultIndex > 0) {
1556         builder.JumpToDefault(defaultIndex);
1557     } else {
1558         builder.Break();
1559     }
1560 
1561     for (size_t i = 0; i < self->Cases().size(); i++) {
1562         builder.SetCaseTarget(i);
1563         builder.CompileCaseStatements(i);
1564     }
1565 }
1566 
Compile(const ir::SwitchStatement * st) const1567 void JSCompiler::Compile(const ir::SwitchStatement *st) const
1568 {
1569     PandaGen *pg = GetPandaGen();
1570     CompileImpl(st, pg);
1571 }
1572 
Compile(const ir::ThrowStatement * st) const1573 void JSCompiler::Compile(const ir::ThrowStatement *st) const
1574 {
1575     PandaGen *pg = GetPandaGen();
1576     st->Argument()->Compile(pg);
1577     pg->EmitThrow(st);
1578 }
1579 
CompileTryCatch(compiler::PandaGen * pg,const ir::TryStatement * st)1580 static void CompileTryCatch(compiler::PandaGen *pg, const ir::TryStatement *st)
1581 {
1582     ES2PANDA_ASSERT(st->CatchClauses().size() == 1);
1583     ES2PANDA_ASSERT(st->CatchClauses().front() && !st->FinallyBlock());
1584 
1585     compiler::TryContext tryCtx(pg, st);
1586     const auto &labelSet = tryCtx.LabelSet();
1587 
1588     pg->SetLabel(st, labelSet.TryBegin());
1589     st->Block()->Compile(pg);
1590     pg->SetLabel(st, labelSet.TryEnd());
1591 
1592     pg->Branch(st, labelSet.CatchEnd());
1593 
1594     pg->SetLabel(st, labelSet.CatchBegin());
1595     st->CatchClauses().front()->Compile(pg);
1596     pg->SetLabel(st, labelSet.CatchEnd());
1597 }
1598 
CompileFinally(compiler::PandaGen * pg,compiler::TryContext * tryCtx,const compiler::TryLabelSet & labelSet,const ir::TryStatement * st)1599 static void CompileFinally(compiler::PandaGen *pg, compiler::TryContext *tryCtx, const compiler::TryLabelSet &labelSet,
1600                            const ir::TryStatement *st)
1601 {
1602     compiler::RegScope rs(pg);
1603     compiler::VReg exception = pg->AllocReg();
1604     pg->StoreConst(st, exception, compiler::Constant::JS_HOLE);
1605     pg->Branch(st, labelSet.CatchEnd());
1606 
1607     pg->SetLabel(st, labelSet.CatchBegin());
1608     pg->StoreAccumulator(st, exception);
1609 
1610     pg->SetLabel(st, labelSet.CatchEnd());
1611 
1612     compiler::Label *label = pg->AllocLabel();
1613     pg->LoadAccumulator(st, tryCtx->FinalizerRun());
1614 
1615     pg->BranchIfNotUndefined(st, label);
1616     pg->StoreAccumulator(st, tryCtx->FinalizerRun());
1617     tryCtx->EmitFinalizer();
1618     pg->SetLabel(st, label);
1619 
1620     pg->LoadAccumulator(st, exception);
1621     pg->EmitRethrow(st);
1622 }
1623 
CompileTryCatchFinally(compiler::PandaGen * pg,const ir::TryStatement * st)1624 static void CompileTryCatchFinally(compiler::PandaGen *pg, const ir::TryStatement *st)
1625 {
1626     ES2PANDA_ASSERT(st->CatchClauses().size() == 1);
1627     ES2PANDA_ASSERT(st->CatchClauses().front() && st->FinallyBlock());
1628 
1629     compiler::TryContext tryCtx(pg, st);
1630     const auto &labelSet = tryCtx.LabelSet();
1631 
1632     pg->SetLabel(st, labelSet.TryBegin());
1633     {
1634         compiler::TryContext innerTryCtx(pg, st, false);
1635         const auto &innerLabelSet = innerTryCtx.LabelSet();
1636 
1637         pg->SetLabel(st, innerLabelSet.TryBegin());
1638         st->Block()->Compile(pg);
1639         pg->SetLabel(st, innerLabelSet.TryEnd());
1640 
1641         pg->Branch(st, innerLabelSet.CatchEnd());
1642 
1643         pg->SetLabel(st, innerLabelSet.CatchBegin());
1644         st->CatchClauses().front()->Compile(pg);
1645         pg->SetLabel(st, innerLabelSet.CatchEnd());
1646     }
1647     pg->SetLabel(st, labelSet.TryEnd());
1648 
1649     CompileFinally(pg, &tryCtx, labelSet, st);
1650 }
1651 
CompileTryFinally(compiler::PandaGen * pg,const ir::TryStatement * st)1652 static void CompileTryFinally(compiler::PandaGen *pg, const ir::TryStatement *st)
1653 {
1654     ES2PANDA_ASSERT(st->CatchClauses().empty() && st->FinallyBlock());
1655 
1656     compiler::TryContext tryCtx(pg, st);
1657     const auto &labelSet = tryCtx.LabelSet();
1658 
1659     pg->SetLabel(st, labelSet.TryBegin());
1660     {
1661         compiler::TryContext innerTryCtx(pg, st, false);
1662         const auto &innerLabelSet = innerTryCtx.LabelSet();
1663 
1664         pg->SetLabel(st, innerLabelSet.TryBegin());
1665         st->Block()->Compile(pg);
1666         pg->SetLabel(st, innerLabelSet.TryEnd());
1667 
1668         pg->Branch(st, innerLabelSet.CatchEnd());
1669 
1670         pg->SetLabel(st, innerLabelSet.CatchBegin());
1671         pg->EmitThrow(st);
1672         pg->SetLabel(st, innerLabelSet.CatchEnd());
1673     }
1674     pg->SetLabel(st, labelSet.TryEnd());
1675 
1676     CompileFinally(pg, &tryCtx, labelSet, st);
1677 }
1678 
Compile(const ir::TryStatement * st) const1679 void JSCompiler::Compile(const ir::TryStatement *st) const
1680 {
1681     PandaGen *pg = GetPandaGen();
1682     if (st->finalizer_ != nullptr) {
1683         if (!st->CatchClauses().empty()) {
1684             CompileTryCatchFinally(pg, st);
1685         } else {
1686             CompileTryFinally(pg, st);
1687         }
1688     } else {
1689         CompileTryCatch(pg, st);
1690     }
1691 }
1692 
Compile(const ir::VariableDeclarator * st) const1693 void JSCompiler::Compile(const ir::VariableDeclarator *st) const
1694 {
1695     PandaGen *pg = GetPandaGen();
1696     auto lref = compiler::JSLReference::Create(pg, st->Id(), true);
1697     const ir::VariableDeclaration *decl = st->Parent()->AsVariableDeclaration();
1698 
1699     if (st->Init() != nullptr) {
1700         st->Init()->Compile(pg);
1701     } else {
1702         if (decl->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) {
1703             return;
1704         }
1705         if (decl->Kind() == ir::VariableDeclaration::VariableDeclarationKind::LET && !decl->Parent()->IsCatchClause()) {
1706             pg->LoadConst(st, compiler::Constant::JS_UNDEFINED);
1707         }
1708     }
1709 
1710     lref.SetValue();
1711 }
1712 
Compile(const ir::VariableDeclaration * st) const1713 void JSCompiler::Compile(const ir::VariableDeclaration *st) const
1714 {
1715     PandaGen *pg = GetPandaGen();
1716     for (const auto *it : st->Declarators()) {
1717         it->Compile(pg);
1718     }
1719 }
1720 
1721 template <typename CodeGen>
CompileImpl(const ir::WhileStatement * whileStmt,CodeGen * cg)1722 void CompileImpl(const ir::WhileStatement *whileStmt, [[maybe_unused]] CodeGen *cg)
1723 {
1724     compiler::LabelTarget labelTarget(cg);
1725 
1726     cg->SetLabel(whileStmt, labelTarget.ContinueTarget());
1727     compiler::Condition::Compile(cg, whileStmt->Test(), labelTarget.BreakTarget());
1728 
1729     {
1730         compiler::LocalRegScope regScope(cg, whileStmt->Scope());
1731         compiler::LabelContext labelCtx(cg, labelTarget);
1732         whileStmt->Body()->Compile(cg);
1733     }
1734 
1735     cg->Branch(whileStmt, labelTarget.ContinueTarget());
1736     cg->SetLabel(whileStmt, labelTarget.BreakTarget());
1737 }
1738 
Compile(const ir::WhileStatement * st) const1739 void JSCompiler::Compile(const ir::WhileStatement *st) const
1740 {
1741     PandaGen *pg = GetPandaGen();
1742     CompileImpl(st, pg);
1743 }
1744 }  // namespace ark::es2panda::compiler
1745