diff --git a/arkguard/src/common/ApiExtractor.ts b/arkguard/src/common/ApiExtractor.ts index 7d9952df7e56cd46de667c778b8cfceb77daf9e5..310d7435e7d911921ac35f8759236c87b3e1c629 100644 --- a/arkguard/src/common/ApiExtractor.ts +++ b/arkguard/src/common/ApiExtractor.ts @@ -524,6 +524,11 @@ export namespace ApiExtractor { fileNames = fs.readdirSync(apiPath); for (let fileName of fileNames) { let filePath: string = path.join(apiPath, fileName); + try { + fs.accessSync(filePath, fs.constants.R_OK); + } catch (err) { + continue; + } if (fs.statSync(filePath).isDirectory()) { const ohPackageJsonPath = path.join(filePath, 'oh-package.json5'); let packgeNameAndVersion = ''; diff --git a/es2panda/BUILD.gn b/es2panda/BUILD.gn index 04fb8650e5d03106f4bac18c63d123e3adc4a40b..e937a3e2f55d0726be656ed54acc5a308fc57ea0 100644 --- a/es2panda/BUILD.gn +++ b/es2panda/BUILD.gn @@ -398,7 +398,7 @@ ohos_static_library("es2panda_lib") { "${target_out_dir}", "//third_party/icu/icu4c/source/common", "//third_party/icu/icu4c/source/i18n", - "//third_party/icu/icu4c/source ", + "//third_party/icu/icu4c/source", ] deps = [ diff --git a/es2panda/ir/base/classDefinition.cpp b/es2panda/ir/base/classDefinition.cpp index 67d36bfe0bd103b6b59ac3899287aed6ad74def3..040aee4556de2d95f394a49c07047fe0b2e0597b 100644 --- a/es2panda/ir/base/classDefinition.cpp +++ b/es2panda/ir/base/classDefinition.cpp @@ -288,11 +288,7 @@ void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const uti continue; } - if (prop->IsPrivate()) { - continue; - } - - if (prop->IsAbstract()) { + if (prop->IsPrivate() || prop->IsAbstract()) { continue; } @@ -301,7 +297,8 @@ void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const uti switch (prop->Kind()) { case ir::MethodDefinitionKind::METHOD: { - compiler::Operand key = pg->ToPropertyKey(prop->Key(), prop->Computed()); + compiler::Operand key = prop->Computed() ? prop->KeyReg() : + pg->ToPropertyKey(prop->Key(), false); pg->LoadAccumulator(this, dest); const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression(); @@ -312,28 +309,7 @@ void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const uti } case ir::MethodDefinitionKind::GET: case ir::MethodDefinitionKind::SET: { - compiler::VReg keyReg = pg->LoadPropertyKey(prop->Key(), prop->Computed()); - - compiler::VReg undef = pg->AllocReg(); - pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); - pg->StoreAccumulator(this, undef); - - compiler::VReg getter = undef; - compiler::VReg setter = undef; - - pg->LoadAccumulator(this, dest); - - compiler::VReg accessor = pg->AllocReg(); - prop->Value()->Compile(pg); - pg->StoreAccumulator(prop->Value(), accessor); - - if (prop->Kind() == ir::MethodDefinitionKind::GET) { - getter = accessor; - } else { - setter = accessor; - } - - pg->DefineGetterSetterByValue(this, dest, keyReg, getter, setter, prop->Computed()); + CompileGetterOrSetter(pg, dest, prop); break; } default: { @@ -385,6 +361,15 @@ void ClassDefinition::CompileComputedKeys(compiler::PandaGen *pg) const pg->ToComputedPropertyKey(prop->Key()); pg->StoreLexicalVar(prop->Key(), 0, GetSlot(prop->Key())); } + } else if (stmt->IsMethodDefinition()) { + auto *methodDef = stmt->AsMethodDefinition(); + if (methodDef->Computed()) { + compiler::VReg keyReg = pg->AllocReg(); + methodDef->SetKeyReg(keyReg); + methodDef->Key()->Compile(pg); + pg->ToComputedPropertyKey(methodDef->Key()); + pg->StoreAccumulator(methodDef->Key(), keyReg); + } } } } @@ -409,6 +394,10 @@ void ClassDefinition::Compile(compiler::PandaGen *pg) const util::StringView ctorId = ctor_->Function()->Scope()->InternalName(); util::BitSet compiled(body_.size()); + if (hasComputedKey_) { + CompileComputedKeys(pg); + } + int32_t bufIdx = CreateClassPublicBuffer(pg, compiled); pg->DefineClassWithBuffer(this, ctorId, bufIdx, baseReg); @@ -422,10 +411,6 @@ void ClassDefinition::Compile(compiler::PandaGen *pg) const CompileMissingProperties(pg, compiled, classReg); - if (hasComputedKey_) { - CompileComputedKeys(pg); - } - if (hasPrivateElement_) { int32_t bufIdx = CreateClassPrivateBuffer(pg); pg->CreatePrivateProperty(this, scope_->privateFieldCnt_, bufIdx); @@ -492,6 +477,8 @@ void ClassDefinition::BuildClassEnvironment(bool useDefineSemantic) if (methodDef->IsPrivate()) { privateProperties.push_back(stmt); methodDef->IsStatic() ? staticPrivateMethodCnt ++ : instancePrivateMethodCnt++; + } else if (methodDef->Computed()) { + hasComputedKey_ = true; } continue; } @@ -503,22 +490,17 @@ void ClassDefinition::BuildClassEnvironment(bool useDefineSemantic) ASSERT(stmt->IsClassProperty()); const auto *prop = stmt->AsClassProperty(); - // Do not process non-static public fields when not using define semantic. if (!prop->IsPrivate() && !prop->IsStatic() && !useDefineSemantic) { continue; } + prop->IsStatic() ? needStaticInitializer_ = true : needInstanceInitializer_ = true; + if (prop->IsComputed() && prop->NeedCompileKey()) { hasComputedKey_ = true; scope_->AddClassVariable(prop->Key()); - } - if (prop->IsStatic()) { - needStaticInitializer_ = true; - } else { - needInstanceInitializer_ = true; - } - if (prop->Key()->IsPrivateIdentifier()) { + } else if (prop->IsPrivate()) { privateFieldCnt++; privateProperties.push_back(stmt); } @@ -622,4 +604,31 @@ void ClassDefinition::CompileSendableClass(compiler::PandaGen *pg) const } } +void ClassDefinition::CompileGetterOrSetter(compiler::PandaGen *pg, compiler::VReg dest, + const MethodDefinition *prop) const +{ + compiler::VReg keyReg = prop->Computed() ? prop->KeyReg() : pg->LoadPropertyKey(prop->Key(), false); + + compiler::VReg undef = pg->AllocReg(); + pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); + pg->StoreAccumulator(this, undef); + + compiler::VReg getter = undef; + compiler::VReg setter = undef; + + pg->LoadAccumulator(this, dest); + + compiler::VReg accessor = pg->AllocReg(); + prop->Value()->Compile(pg); + pg->StoreAccumulator(prop->Value(), accessor); + + if (prop->Kind() == ir::MethodDefinitionKind::GET) { + getter = accessor; + } else { + setter = accessor; + } + + pg->DefineGetterSetterByValue(this, dest, keyReg, getter, setter, prop->Computed()); +} + } // namespace panda::es2panda::ir diff --git a/es2panda/ir/base/classDefinition.h b/es2panda/ir/base/classDefinition.h index 86a584cbb580e40fc28f43cd71d9aa98daa6df70..5e3f461b12730305f7a100a816cf15dbafd06b0e 100644 --- a/es2panda/ir/base/classDefinition.h +++ b/es2panda/ir/base/classDefinition.h @@ -248,6 +248,7 @@ private: void CompileComputedKeys(compiler::PandaGen *pg) const; int32_t CreateFieldTypeBuffer(compiler::PandaGen *pg) const; void CompileSendableClass(compiler::PandaGen *pg) const; + void CompileGetterOrSetter(compiler::PandaGen *pg, compiler::VReg dest, const MethodDefinition *prop) const; binder::ClassScope *scope_; Identifier *ident_; diff --git a/es2panda/ir/base/methodDefinition.h b/es2panda/ir/base/methodDefinition.h index 217d8863026127b46604dd840234222700766646..d5f9ce90856b42a115daf9a2650ba281fa9ce41a 100644 --- a/es2panda/ir/base/methodDefinition.h +++ b/es2panda/ir/base/methodDefinition.h @@ -151,6 +151,16 @@ public: overloads_.push_back(overload); } + void SetKeyReg(compiler::VReg keyReg) + { + keyReg_ = keyReg; + } + + compiler::VReg KeyReg() const + { + return keyReg_; + } + const ScriptFunction *Function() const; ScriptFunction *Function(); @@ -164,6 +174,7 @@ public: private: MethodDefinitionKind kind_; Expression *key_; + compiler::VReg keyReg_ {0}; FunctionExpression *value_; ModifierFlags modifiers_; ArenaVector overloads_; diff --git a/es2panda/test/compiler/js/class-tdz-2-expected.txt b/es2panda/test/compiler/js/class-tdz-2-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..499d2f8dc4cac2760ea68c13d42bdedbe1fd3293 --- /dev/null +++ b/es2panda/test/compiler/js/class-tdz-2-expected.txt @@ -0,0 +1 @@ +ReferenceError diff --git a/es2panda/test/compiler/js/class-tdz-2.js b/es2panda/test/compiler/js/class-tdz-2.js new file mode 100644 index 0000000000000000000000000000000000000000..b687ce41d8bbd5a9bbdc9b05c56cc6f370c91084 --- /dev/null +++ b/es2panda/test/compiler/js/class-tdz-2.js @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 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. + */ + +try { + class A { + [A]() { + A; + }; + } +} catch (e) { + print(e.name); +} \ No newline at end of file diff --git a/es2panda/test/compiler/js/class-tdz-3-expected.txt b/es2panda/test/compiler/js/class-tdz-3-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..499d2f8dc4cac2760ea68c13d42bdedbe1fd3293 --- /dev/null +++ b/es2panda/test/compiler/js/class-tdz-3-expected.txt @@ -0,0 +1 @@ +ReferenceError diff --git a/es2panda/test/compiler/js/class-tdz-3.js b/es2panda/test/compiler/js/class-tdz-3.js new file mode 100644 index 0000000000000000000000000000000000000000..e5f7a04694aa95ea8d66f715a6345fbe76f5e975 --- /dev/null +++ b/es2panda/test/compiler/js/class-tdz-3.js @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 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. + */ + +try { + class A { + [A] = ()=>{A;}; + } +} catch (e) { + print(e.name); +} \ No newline at end of file diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 5b7ac5a9edcd8c4dd082b90fc6ec8e129c50668f..7b6f6762dd73e95e80aec46f0b99ece5aed8554f 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1035,9 +1035,9 @@ checker::ETSObjectType *ChooseCalleeObj(ETSChecker *checker, ir::CallExpression return expr->Callee()->AsMemberExpression()->ObjType(); } -checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType, - bool isConstructorCall, bool isFunctionalInterface, - bool isUnionTypeWithFunctionalInterface) +checker::Signature *ETSAnalyzer::ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, + checker::Type *calleeType, bool isFunctionalInterface, + bool isUnionTypeWithFunctionalInterface) const { bool extensionFunctionType = expr->Callee()->IsMemberExpression() && checker->ExtensionETSFunctionType(calleeType); @@ -1047,7 +1047,7 @@ checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *ex if (extensionFunctionType) { return ResolveCallExtensionFunction(calleeType->AsETSFunctionType(), checker, expr); } - auto &signatures = ChooseSignatures(checker, calleeType, isConstructorCall, isFunctionalInterface, + auto &signatures = ChooseSignatures(checker, calleeType, expr->IsETSConstructorCall(), isFunctionalInterface, isUnionTypeWithFunctionalInterface); checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start()); if (signature->Function()->IsExtensionMethod()) { @@ -1077,8 +1077,8 @@ checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Typ checker->ThrowTypeError("This expression is not callable.", expr->Start()); } - checker::Signature *signature = ResolveSignature(checker, expr, calleeType, isConstructorCall, - isFunctionalInterface, isUnionTypeWithFunctionalInterface); + checker::Signature *signature = + ResolveSignature(checker, expr, calleeType, isFunctionalInterface, isUnionTypeWithFunctionalInterface); checker->CheckObjectLiteralArguments(signature, expr->Arguments()); checker->AddUndefinedParamsForDefaultParams(signature, expr->Arguments(), checker); @@ -1521,51 +1521,34 @@ checker::Type *ETSAnalyzer::Check(ir::ThisExpression *expr) const return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const +void ProcessExclamationMark(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType) { - ETSChecker *checker = GetETSChecker(); - - if (expr->TsType() != nullptr) { - return expr->TsType(); + if (checker->IsNullLikeOrVoidExpression(expr->Argument())) { + auto tsType = checker->CreateETSBooleanType(true); + tsType->AddTypeFlag(checker::TypeFlag::CONSTANT); + expr->SetTsType(tsType); + return; } - auto argType = expr->argument_->Check(checker); - const auto isCondExpr = expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK; - checker::Type *operandType = checker->ApplyUnaryOperatorPromotion(argType, true, true, isCondExpr); - auto unboxedOperandType = isCondExpr ? checker->ETSBuiltinTypeAsConditionalType(argType) - : checker->ETSBuiltinTypeAsPrimitiveType(argType); - - if (argType != nullptr && argType->IsETSBigIntType() && argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) { - switch (expr->OperatorType()) { - case lexer::TokenType::PUNCTUATOR_MINUS: { - checker::Type *type = checker->CreateETSBigIntLiteralType(argType->AsETSBigIntType()->GetValue()); - - // We do not need this const anymore as we are negating the bigint object in runtime - type->RemoveTypeFlag(checker::TypeFlag::CONSTANT); - expr->argument_->SetTsType(type); - expr->SetTsType(type); - return expr->TsType(); - } - default: - // Handled below - // NOTE(kkonsw): handle other unary operators for bigint literals - break; - } + if (operandType == nullptr || !operandType->IsConditionalExprType()) { + checker->ThrowTypeError("Bad operand type, the type of the operand must be boolean type.", + expr->Argument()->Start()); } - if (argType != nullptr && argType->IsETSBigIntType()) { - switch (expr->OperatorType()) { - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::PUNCTUATOR_PLUS: - case lexer::TokenType::PUNCTUATOR_TILDE: { - expr->SetTsType(argType); - return expr->TsType(); - } - default: - break; - } + auto exprRes = operandType->ResolveConditionExpr(); + if (std::get<0>(exprRes)) { + auto tsType = checker->CreateETSBooleanType(!std::get<1>(exprRes)); + tsType->AddTypeFlag(checker::TypeFlag::CONSTANT); + expr->SetTsType(tsType); + return; } + expr->SetTsType(checker->GlobalETSBooleanType()); +} + +void SetTsTypeForUnaryExpression(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType, + checker::Type *argType) +{ switch (expr->OperatorType()) { case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::PUNCTUATOR_PLUS: { @@ -1598,27 +1581,7 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const break; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { - if (checker->IsNullLikeOrVoidExpression(expr->Argument())) { - auto tsType = checker->CreateETSBooleanType(true); - tsType->AddTypeFlag(checker::TypeFlag::CONSTANT); - expr->SetTsType(tsType); - break; - } - - if (operandType == nullptr || !operandType->IsConditionalExprType()) { - checker->ThrowTypeError("Bad operand type, the type of the operand must be boolean type.", - expr->Argument()->Start()); - } - - auto exprRes = operandType->ResolveConditionExpr(); - if (std::get<0>(exprRes)) { - auto tsType = checker->CreateETSBooleanType(!std::get<1>(exprRes)); - tsType->AddTypeFlag(checker::TypeFlag::CONSTANT); - expr->SetTsType(tsType); - break; - } - - expr->SetTsType(checker->GlobalETSBooleanType()); + ProcessExclamationMark(checker, expr, operandType); break; } case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: { @@ -1630,6 +1593,54 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const break; } } +} + +checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const +{ + ETSChecker *checker = GetETSChecker(); + + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + auto argType = expr->argument_->Check(checker); + const auto isCondExpr = expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK; + checker::Type *operandType = checker->ApplyUnaryOperatorPromotion(argType, true, true, isCondExpr); + auto unboxedOperandType = isCondExpr ? checker->ETSBuiltinTypeAsConditionalType(argType) + : checker->ETSBuiltinTypeAsPrimitiveType(argType); + + if (argType != nullptr && argType->IsETSBigIntType() && argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) { + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_MINUS: { + checker::Type *type = checker->CreateETSBigIntLiteralType(argType->AsETSBigIntType()->GetValue()); + + // We do not need this const anymore as we are negating the bigint object in runtime + type->RemoveTypeFlag(checker::TypeFlag::CONSTANT); + expr->argument_->SetTsType(type); + expr->SetTsType(type); + return expr->TsType(); + } + default: + // Handled below + // NOTE(kkonsw): handle other unary operators for bigint literals + break; + } + } + + if (argType != nullptr && argType->IsETSBigIntType()) { + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_TILDE: { + expr->SetTsType(argType); + return expr->TsType(); + } + default: + break; + } + } + + SetTsTypeForUnaryExpression(checker, expr, operandType, argType); if ((argType != nullptr) && argType->IsETSObjectType() && (unboxedOperandType != nullptr) && unboxedOperandType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { diff --git a/ets2panda/checker/ETSAnalyzer.h b/ets2panda/checker/ETSAnalyzer.h index 074193f35adc108ca118c4ad4a728f32bc0a2bfe..9df71aa9212cd889a5b99ce7493097c4081ea81b 100644 --- a/ets2panda/checker/ETSAnalyzer.h +++ b/ets2panda/checker/ETSAnalyzer.h @@ -40,6 +40,8 @@ public: private: ETSChecker *GetETSChecker() const; void CheckMethodModifiers(ir::MethodDefinition *node) const; + checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType, + bool isFunctionalInterface, bool isUnionTypeWithFunctionalInterface) const; checker::Type *GetReturnType(ir::CallExpression *expr, checker::Type *calleeType) const; checker::Type *GetFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc) const; };