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