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