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" 27namespace ark::es2panda::compiler { 28 29PandaGen *JSCompiler::GetPandaGen() const 30{ 31 return static_cast<PandaGen *>(GetCodeGen()); 32} 33 34// from base folder 35void 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 49static 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 63static 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 83compiler::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 107static 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) 125static 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 192static 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 257static 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 303static 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 363static 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 373void 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 409void 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 424void 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 433void 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 439void 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 466void 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 480static 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 516void 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 545static 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 553void 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 575void 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 638void 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 645void JSCompiler::Compile(const ir::ClassExpression *expr) const 646{ 647 PandaGen *pg = GetPandaGen(); 648 expr->Definition()->Compile(pg); 649} 650 651template <typename CodeGen> 652static 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 665void JSCompiler::Compile(const ir::ConditionalExpression *expr) const 666{ 667 PandaGen *pg = GetPandaGen(); 668 CompileImpl(expr, pg); 669} 670 671void 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 700void 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 706void 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 743void JSCompiler::Compile([[maybe_unused]] const ir::ImportExpression *expr) const 744{ 745 PandaGen *pg = GetPandaGen(); 746 pg->Unimplemented(); 747} 748 749void 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 757void 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 787void 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 803static 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 836static 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 851void 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 903void 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 957void 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 990void 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 998void 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 1010void 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 1028void 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 1070void 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 1085void 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 1106void 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 1163void 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 1182void 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 1202void JSCompiler::Compile(const ir::BigIntLiteral *expr) const 1203{ 1204 PandaGen *pg = GetPandaGen(); 1205 pg->LoadAccumulatorBigInt(expr, expr->Str()); 1206} 1207 1208void 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 1214void JSCompiler::Compile(const ir::NullLiteral *expr) const 1215{ 1216 PandaGen *pg = GetPandaGen(); 1217 pg->LoadConst(expr, compiler::Constant::JS_NULL); 1218} 1219 1220void 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 1234void 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 1240void 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 1247void JSCompiler::Compile([[maybe_unused]] const ir::ExportAllDeclaration *st) const {} 1248 1249void JSCompiler::Compile(const ir::ExportDefaultDeclaration *st) const 1250{ 1251 PandaGen *pg = GetPandaGen(); 1252 st->Decl()->Compile(pg); 1253 pg->StoreModuleVar(st, "default"); 1254} 1255 1256void 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 1266void JSCompiler::Compile([[maybe_unused]] const ir::ImportDeclaration *st) const {} 1267 1268void 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 1278template <typename CodeGen> 1279static 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} 1284void JSCompiler::Compile(const ir::BreakStatement *st) const 1285{ 1286 PandaGen *pg = GetPandaGen(); 1287 CompileImpl(st, pg); 1288} 1289 1290void 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 1298static void CompileImpl(const ir::ContinueStatement *self, PandaGen *cg) 1299{ 1300 compiler::Label *target = cg->ControlFlowChangeContinue(self->Ident()); 1301 cg->Branch(self, target); 1302} 1303 1304void JSCompiler::Compile(const ir::ContinueStatement *st) const 1305{ 1306 PandaGen *pg = GetPandaGen(); 1307 CompileImpl(st, pg); 1308} 1309 1310void JSCompiler::Compile([[maybe_unused]] const ir::DebuggerStatement *st) const {} 1311 1312static 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 1332void JSCompiler::Compile(const ir::DoWhileStatement *st) const 1333{ 1334 PandaGen *pg = GetPandaGen(); 1335 CompileImpl(st, pg); 1336} 1337 1338void JSCompiler::Compile([[maybe_unused]] const ir::EmptyStatement *st) const {} 1339 1340void JSCompiler::Compile(const ir::ExpressionStatement *st) const 1341{ 1342 PandaGen *pg = GetPandaGen(); 1343 st->GetExpression()->Compile(pg); 1344} 1345 1346void 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 1383void 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 1419void 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 1456void JSCompiler::Compile([[maybe_unused]] const ir::FunctionDeclaration *st) const {} 1457 1458void 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 1478void CompileImpl(const ir::LabelledStatement *self, PandaGen *cg) 1479{ 1480 compiler::LabelContext labelCtx(cg, self); 1481 self->Body()->Compile(cg); 1482} 1483 1484void JSCompiler::Compile(const ir::LabelledStatement *st) const 1485{ 1486 PandaGen *pg = GetPandaGen(); 1487 CompileImpl(st, pg); 1488} 1489 1490void 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 1516static 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 1548void JSCompiler::Compile(const ir::SwitchStatement *st) const 1549{ 1550 PandaGen *pg = GetPandaGen(); 1551 CompileImpl(st, pg); 1552} 1553 1554void JSCompiler::Compile(const ir::ThrowStatement *st) const 1555{ 1556 PandaGen *pg = GetPandaGen(); 1557 st->Argument()->Compile(pg); 1558 pg->EmitThrow(st); 1559} 1560 1561static 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 1580static 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 1605static 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 1633static 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 1660void 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 1674void 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 1694void 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 1702template <typename CodeGen> 1703void 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 1720void JSCompiler::Compile(const ir::WhileStatement *st) const 1721{ 1722 PandaGen *pg = GetPandaGen(); 1723 CompileImpl(st, pg); 1724} 1725} // namespace ark::es2panda::compiler 1726