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