From 3ad33086f164f1510224d0f7dd8719bd89e1b8e7 Mon Sep 17 00:00:00 2001 From: huyunhui Date: Thu, 23 May 2024 16:43:02 +0800 Subject: [PATCH] Fix compilation of super call expression Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I9RNDD Signed-off-by: huyunhui Change-Id: I41697dd4cec365176cbc7a393dc1f4c4ae5d858d --- es2panda/ir/expressions/callExpression.cpp | 113 ++++++++++-------- es2panda/ir/expressions/callExpression.h | 1 + .../super-call/super-call-spread-expected.txt | 1 + .../super-call/super-call-spread.js | 40 +++++++ 4 files changed, 102 insertions(+), 53 deletions(-) create mode 100644 es2panda/test/compiler/js/language/expressions/super-call/super-call-spread-expected.txt create mode 100644 es2panda/test/compiler/js/language/expressions/super-call/super-call-spread.js diff --git a/es2panda/ir/expressions/callExpression.cpp b/es2panda/ir/expressions/callExpression.cpp index 539a38e29b..47d6be7987 100644 --- a/es2panda/ir/expressions/callExpression.cpp +++ b/es2panda/ir/expressions/callExpression.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,64 @@ compiler::VReg CallExpression::CreateSpreadArguments(compiler::PandaGen *pg) con return argsObj; } +void CallExpression::CompileSuperCall(compiler::PandaGen *pg, bool containsSpread) const +{ + if (containsSpread) { + compiler::RegScope paramScope(pg); + compiler::VReg argsObj {}; + // arguments_ is only ...args + if (arguments_.size() == 1) { + argsObj = pg->AllocReg(); + arguments_[0]->AsSpreadElement()->Argument()->Compile(pg); + pg->StoreAccumulator(this, argsObj); + } else { + argsObj = CreateSpreadArguments(pg); + } + + pg->GetFunctionObject(this); + pg->SuperCallSpread(this, argsObj); + } else { + compiler::RegScope paramScope(pg); + compiler::VReg argStart {}; + + if (arguments_.empty()) { + argStart = pg->AllocReg(); + pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); + pg->StoreAccumulator(this, argStart); + } else { + argStart = pg->NextReg(); + } + + for (const auto *it : arguments_) { + compiler::VReg arg = pg->AllocReg(); + it->Compile(pg); + pg->StoreAccumulator(it, arg); + } + + pg->SuperCall(this, argStart, arguments_.size()); + } + + compiler::VReg newThis = pg->AllocReg(); + pg->StoreAccumulator(this, newThis); + + pg->GetThis(this); + pg->ThrowIfSuperNotCorrectCall(this, 1); + + pg->LoadAccumulator(this, newThis); + pg->SetThis(this); + + const auto *classDef = util::Helpers::GetClassDefiniton(util::Helpers::GetContainingConstructor(this)); + if (classDef->NeedInstanceInitializer()) { + auto thisReg = pg->AllocReg(); + pg->MoveVreg(this, thisReg, newThis); + + auto [level, slot] = pg->Scope()->Find(classDef->InstanceInitializer()->Key()); + pg->LoadLexicalVar(this, level, slot); + + pg->CallInit(this, thisReg); + } +} + void CallExpression::Compile(compiler::PandaGen *pg) const { const ir::Expression *realCallee = callee_; @@ -86,59 +145,7 @@ void CallExpression::Compile(compiler::PandaGen *pg) const bool containsSpread = util::Helpers::ContainSpreadElement(arguments_); if (callee_->IsSuperExpression()) { - if (containsSpread) { - compiler::RegScope paramScope(pg); - compiler::VReg argsObj {}; - // arguments_ is only ...args - if (arguments_.size() == 1) { - argsObj = pg->AllocReg(); - pg->StoreAccumulator(this, argsObj); - } else { - argsObj = CreateSpreadArguments(pg); - } - - pg->GetFunctionObject(this); - pg->SuperCallSpread(this, argsObj); - } else { - compiler::RegScope paramScope(pg); - compiler::VReg argStart {}; - - if (arguments_.empty()) { - argStart = pg->AllocReg(); - pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); - pg->StoreAccumulator(this, argStart); - } else { - argStart = pg->NextReg(); - } - - for (const auto *it : arguments_) { - compiler::VReg arg = pg->AllocReg(); - it->Compile(pg); - pg->StoreAccumulator(it, arg); - } - - pg->SuperCall(this, argStart, arguments_.size()); - } - - compiler::VReg newThis = pg->AllocReg(); - pg->StoreAccumulator(this, newThis); - - pg->GetThis(this); - pg->ThrowIfSuperNotCorrectCall(this, 1); - - pg->LoadAccumulator(this, newThis); - pg->SetThis(this); - - const auto *classDef = util::Helpers::GetClassDefiniton(util::Helpers::GetContainingConstructor(this)); - if (classDef->NeedInstanceInitializer()) { - auto thisReg = pg->AllocReg(); - pg->MoveVreg(this, thisReg, newThis); - - auto [level, slot] = pg->Scope()->Find(classDef->InstanceInitializer()->Key()); - pg->LoadLexicalVar(this, level, slot); - - pg->CallInit(this, thisReg); - } + CompileSuperCall(pg, containsSpread); return; } diff --git a/es2panda/ir/expressions/callExpression.h b/es2panda/ir/expressions/callExpression.h index 34c20bdd2f..98b91b102a 100644 --- a/es2panda/ir/expressions/callExpression.h +++ b/es2panda/ir/expressions/callExpression.h @@ -88,6 +88,7 @@ public: private: compiler::VReg CreateSpreadArguments(compiler::PandaGen *pg) const; + void CompileSuperCall(compiler::PandaGen *pg, bool containsSpread) const; Expression *callee_; ArenaVector arguments_; diff --git a/es2panda/test/compiler/js/language/expressions/super-call/super-call-spread-expected.txt b/es2panda/test/compiler/js/language/expressions/super-call/super-call-spread-expected.txt new file mode 100644 index 0000000000..acdc2b8d1e --- /dev/null +++ b/es2panda/test/compiler/js/language/expressions/super-call/super-call-spread-expected.txt @@ -0,0 +1 @@ +aaa diff --git a/es2panda/test/compiler/js/language/expressions/super-call/super-call-spread.js b/es2panda/test/compiler/js/language/expressions/super-call/super-call-spread.js new file mode 100644 index 0000000000..88c163149e --- /dev/null +++ b/es2panda/test/compiler/js/language/expressions/super-call/super-call-spread.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +let instance; +class A { + name = '' + getName() { + return this.name; + } + setName(name) { + this.name = name; + } +} + +class B extends A { + constructor (...args) { + if (!instance) { + instance = super(...args); + } + return instance; + } +} + +let a = new B(); +let b = new B(); + +a.setName('aaa'); +print(b.getName()); -- Gitee