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