!3915 Support typeinfer for generic types [PART_1]

Merge pull request !3915 from huoqingyi/typeliteral
This commit is contained in:
openharmony_ci 2023-04-24 07:10:00 +00:00 committed by Gitee
commit 8a32f45414
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
18 changed files with 946 additions and 581 deletions

View File

@ -625,6 +625,7 @@ ecma_source = [
"ecmascript/jspandafile/class_info_extractor.cpp",
"ecmascript/jspandafile/debug_info_extractor.cpp",
"ecmascript/jspandafile/literal_data_extractor.cpp",
"ecmascript/jspandafile/type_literal_extractor.cpp",
"ecmascript/jspandafile/accessor/module_data_accessor.cpp",
"ecmascript/jspandafile/panda_file_translator.cpp",
"ecmascript/jspandafile/js_pandafile_executor.cpp",

View File

@ -18,6 +18,7 @@
#include "ecmascript/base/path_helper.h"
#include "ecmascript/compiler/type_recorder.h"
#include "ecmascript/interpreter/interpreter-inl.h"
#include "ecmascript/jspandafile/type_literal_extractor.h"
#include "ecmascript/ts_types/ts_type_parser.h"
#include "libpandafile/code_data_accessor.h"
@ -79,7 +80,7 @@ void BytecodeInfoCollector::ProcessClasses()
cda.EnumerateMethods([this, methods, &methodIdx, pf, &processedInsns,
&recordNames, &methodPcInfos, &recordName] (panda_file::MethodDataAccessor &mda) {
auto methodId = mda.GetMethodId();
CollectFunctionTypeId(vm_->GetJSThread(), methodId);
CollectFunctionTypeId(methodId);
// Generate all constpool
vm_->FindOrCreateConstPool(jsPandaFile_, methodId);
@ -142,99 +143,50 @@ void BytecodeInfoCollector::CollectClassLiteralInfo(const MethodLiteral *method,
}
}
void BytecodeInfoCollector::CollectFunctionTypeId(JSThread *thread, panda_file::File::EntityId fieldId)
void BytecodeInfoCollector::CollectFunctionTypeId(panda_file::File::EntityId fieldId)
{
const panda_file::File *pf = jsPandaFile_->GetPandaFile();
panda_file::MethodDataAccessor mda(*pf, fieldId);
mda.EnumerateAnnotations([this, fieldId, pf, thread] (panda_file::File::EntityId annotationId) {
panda_file::AnnotationDataAccessor ada(*pf, annotationId);
auto *annotationName = reinterpret_cast<const char *>(jsPandaFile_->GetStringData(ada.GetClassId()).data);
ASSERT(annotationName != nullptr);
if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) {
return;
}
uint32_t length = ada.GetCount();
for (uint32_t i = 0; i < length; i++) {
panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
auto *elemName = reinterpret_cast<const char *>(jsPandaFile_->GetStringData(adae.GetNameId()).data);
ASSERT(elemName != nullptr);
if (::strcmp("_TypeOfInstruction", elemName) != 0) {
continue;
uint32_t offset = fieldId.GetOffset();
TypeAnnotationExtractor annoExtractor(jsPandaFile_, offset);
annoExtractor.EnumerateInstsAndTypes(
[this, offset](const int32_t bcOffset, const uint32_t typeId) {
if (bcOffset == TypeRecorder::METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) {
bytecodeInfo_.SetFunctionTypeIDAndMethodOffset(typeId, offset);
return;
}
panda_file::ScalarValue sv = adae.GetScalarValue();
panda_file::File::EntityId literalOffset(sv.GetValue());
JSHandle<TaggedArray> typeOfInstruction =
LiteralDataExtractor::GetTypeLiteral(thread, jsPandaFile_, literalOffset);
for (uint32_t j = 0; j < typeOfInstruction->GetLength(); j = j + 2) { // + 2 means bcOffset and typeId
int32_t bcOffset = typeOfInstruction->Get(j).GetInt();
uint32_t typeId = static_cast<uint32_t>(typeOfInstruction->Get(j + 1).GetInt());
if (bcOffset == TypeRecorder::METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) {
bytecodeInfo_.SetFunctionTypeIDAndMethodOffset(typeId, fieldId.GetOffset());
return;
}
}
}
});
});
}
void BytecodeInfoCollector::IterateLiteral(const MethodLiteral *method,
std::vector<uint32_t> &classOffsetVector)
{
const panda_file::File *pf = jsPandaFile_->GetPandaFile();
panda_file::File::EntityId fieldId = method->GetMethodId();
uint32_t defineMethodOffset = fieldId.GetOffset();
panda_file::MethodDataAccessor methodDataAccessor(*pf, fieldId);
methodDataAccessor.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) {
panda_file::AnnotationDataAccessor ada(*pf, annotation_id);
std::string annotationName = std::string(utf::Mutf8AsCString(pf->GetStringData(ada.GetClassId()).data));
if (annotationName.compare("L_ESTypeAnnotation;") != 0) {
return;
}
uint32_t length = ada.GetCount();
for (uint32_t i = 0; i < length; i++) {
panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
std::string elemName = std::string(utf::Mutf8AsCString(pf->GetStringData(adae.GetNameId()).data));
if (elemName.compare("_TypeOfInstruction") != 0) {
continue;
TypeAnnotationExtractor annoExtractor(jsPandaFile_, defineMethodOffset);
std::map<int32_t, uint32_t> offsetTypeMap;
annoExtractor.EnumerateInstsAndTypes(
[this, &offsetTypeMap, defineMethodOffset](const int32_t bcOffset, const uint32_t typeOffset) {
if (classDefBCIndexes_.find(bcOffset) != classDefBCIndexes_.end() ||
classDefBCIndexes_.find(bcOffset - 1) != classDefBCIndexes_.end()) { // for getter setter
bytecodeInfo_.SetClassTypeOffsetAndDefMethod(typeOffset, defineMethodOffset);
}
panda_file::ScalarValue sv = adae.GetScalarValue();
panda_file::File::EntityId literalOffset(sv.GetValue());
JSHandle<TaggedArray> typeOfInstruction =
LiteralDataExtractor::GetTypeLiteral(vm_->GetJSThread(), jsPandaFile_, literalOffset);
std::map<int32_t, uint32_t> offsetTypeMap;
for (uint32_t j = 0; j < typeOfInstruction->GetLength(); j = j + 2) { // 2: Two parsing once
int32_t bcOffset = typeOfInstruction->Get(j).GetInt();
uint32_t typeOffset = static_cast<uint32_t>(typeOfInstruction->Get(j + 1).GetInt());
if (classDefBCIndexes_.find(bcOffset) != classDefBCIndexes_.end() ||
classDefBCIndexes_.find(bcOffset - 1) != classDefBCIndexes_.end()) { // for getter setter
bytecodeInfo_.SetClassTypeOffsetAndDefMethod(typeOffset, defineMethodOffset);
}
if (bcOffset != TypeRecorder::METHOD_ANNOTATION_THIS_TYPE_OFFSET &&
typeOffset > TSTypeParser::USER_DEFINED_TYPE_OFFSET) {
offsetTypeMap.insert(std::make_pair(bcOffset, typeOffset));
}
if (bcOffset != TypeRecorder::METHOD_ANNOTATION_THIS_TYPE_OFFSET &&
typeOffset > TSTypeParser::USER_DEFINED_TYPE_OFFSET) {
offsetTypeMap.insert(std::make_pair(bcOffset, typeOffset));
}
});
for (auto item : offsetTypeMap) {
uint32_t typeOffset = item.second;
StoreClassTypeOffset(typeOffset, classOffsetVector);
}
for (auto item : offsetTypeMap) {
uint32_t typeOffset = item.second;
StoreClassTypeOffset(typeOffset, classOffsetVector);
}
}
});
classDefBCIndexes_.clear();
}
void BytecodeInfoCollector::StoreClassTypeOffset(const uint32_t typeOffset, std::vector<uint32_t> &classOffsetVector)
{
panda_file::File::EntityId offset(typeOffset);
JSHandle<TaggedArray> literal =
LiteralDataExtractor::GetTypeLiteral(vm_->GetJSThread(), jsPandaFile_, offset);
int typeKind = literal->Get(0).GetInt();
if (typeKind != static_cast<int>(TSTypeKind::CLASS)) {
TypeLiteralExtractor typeLiteralExtractor(jsPandaFile_, typeOffset);
if (typeLiteralExtractor.GetTypeKind() != TSTypeKind::CLASS) {
return;
}
@ -566,26 +518,12 @@ void BytecodeInfoCollector::CollectExportIndexs(const CString &recordName, uint3
bool BytecodeInfoCollector::CheckExportName(const CString &recordName, const JSHandle<EcmaString> &exportStr)
{
auto tsManager = vm_->GetTSManager();
// To compare with the exportTable, we need to parse the literalbuffer in abc TypeAnnotation.
// If the exportTable already exist, we will use it directly. OtherWise, we will parse and store it.
// In type system parser at a later stage, we will also use these arrays to avoid duplicate parsing.
if (tsManager->HasResolvedExportTable(jsPandaFile_, recordName)) {
JSTaggedValue exportTypeTable = tsManager->GetResolvedExportTable(jsPandaFile_, recordName);
JSHandle<TaggedArray> table(vm_->GetJSThread(), exportTypeTable);
return IsEffectiveExportName(exportStr, table);
}
JSHandle<TaggedArray> newResolvedTable = tsManager->GenerateExportTableFromLiteral(jsPandaFile_, recordName);
return IsEffectiveExportName(exportStr, newResolvedTable);
}
bool BytecodeInfoCollector::IsEffectiveExportName(const JSHandle<EcmaString> &exportNameStr,
const JSHandle<TaggedArray> &exportTypeTable)
{
JSHandle<TaggedArray> exportTypeTable = tsManager->GetExportTableFromLiteral(jsPandaFile_, recordName);
uint32_t length = exportTypeTable->GetLength();
for (uint32_t i = 0; i < length; i = i + 2) { // 2: skip a pair of key and value
EcmaString *valueString = EcmaString::Cast(exportTypeTable->Get(i).GetTaggedObject());
uint32_t typeId = static_cast<uint32_t>(exportTypeTable->Get(i + 1).GetInt());
if (EcmaStringAccessor::StringsAreEqual(*exportNameStr, valueString) && typeId != 0) {
if (EcmaStringAccessor::StringsAreEqual(*exportStr, valueString) && typeId != 0) {
return true;
}
}

View File

@ -715,13 +715,10 @@ private:
void IterateLiteral(const MethodLiteral *method, std::vector<uint32_t> &classOffsetVector);
void StoreClassTypeOffset(const uint32_t typeOffset, std::vector<uint32_t> &classOffsetVector);
void CollectClassLiteralInfo(const MethodLiteral *method, const std::vector<std::string> &classNameVec);
void CollectFunctionTypeId(JSThread *thread, panda_file::File::EntityId fieldId);
void CollectFunctionTypeId(panda_file::File::EntityId fieldId);
void CollectImportIndexs(uint32_t methodOffset, uint32_t index);
void CollectExportIndexs(const CString &recordName, uint32_t index);
bool CheckExportName(const CString &recordName,
const JSHandle<EcmaString> &exportStr);
bool IsEffectiveExportName(const JSHandle<EcmaString> &exportNameStr,
const JSHandle<TaggedArray> &exportTypeTable);
bool CheckExportName(const CString &recordName, const JSHandle<EcmaString> &exportStr);
void CollectRecordReferenceREL();
void CollectRecordImportInfo(const CString &recordName);
void CollectRecordExportInfo(const CString &recordName);

View File

@ -15,12 +15,10 @@
#include "ecmascript/compiler/type_recorder.h"
#include "ecmascript/jspandafile/literal_data_extractor.h"
#include "ecmascript/jspandafile/type_literal_extractor.h"
#include "ecmascript/pgo_profiler/pgo_profiler_loader.h"
#include "ecmascript/ts_types/ts_type_parser.h"
#include "libpandafile/method_data_accessor-inl.h"
namespace panda::ecmascript::kungfu {
TypeRecorder::TypeRecorder(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral,
TSManager *tsManager, const CString &recordName, PGOProfilerLoader *loader)
@ -38,60 +36,34 @@ TypeRecorder::TypeRecorder(const JSPandaFile *jsPandaFile, const MethodLiteral *
void TypeRecorder::LoadTypes(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral,
TSManager *tsManager, const CString &recordName)
{
JSThread *thread = tsManager->GetThread();
TSTypeParser typeParser(tsManager);
const panda_file::File *pf = jsPandaFile->GetPandaFile();
panda_file::File::EntityId fieldId = methodLiteral->GetMethodId();
panda_file::MethodDataAccessor mda(*pf, fieldId);
mda.EnumerateAnnotations([&](panda_file::File::EntityId annotationId) {
panda_file::AnnotationDataAccessor ada(*pf, annotationId);
auto *annotationName = reinterpret_cast<const char *>(jsPandaFile->GetStringData(ada.GetClassId()).data);
ASSERT(annotationName != nullptr);
if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) {
TypeAnnotationExtractor annoExtractor(jsPandaFile, fieldId.GetOffset());
GlobalTSTypeRef thisGT;
GlobalTSTypeRef funcGT;
annoExtractor.EnumerateInstsAndTypes([this, &typeParser, &jsPandaFile, &recordName, &thisGT,
&funcGT](const int32_t bcOffset, const uint32_t typeId) {
GlobalTSTypeRef gt = typeParser.CreateGT(jsPandaFile, recordName, typeId);
if (gt.IsDefault()) {
return;
}
uint32_t length = ada.GetCount();
for (uint32_t i = 0; i < length; i++) {
panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
auto *elemName = reinterpret_cast<const char *>(jsPandaFile->GetStringData(adae.GetNameId()).data);
ASSERT(elemName != nullptr);
if (::strcmp("_TypeOfInstruction", elemName) != 0) {
continue;
}
panda_file::ScalarValue sv = adae.GetScalarValue();
panda_file::File::EntityId literalOffset(sv.GetValue());
JSHandle<TaggedArray> typeOfInstruction =
LiteralDataExtractor::GetTypeLiteral(thread, jsPandaFile, literalOffset);
GlobalTSTypeRef thisGT = GlobalTSTypeRef::Default();
GlobalTSTypeRef funcGT = GlobalTSTypeRef::Default();
for (uint32_t j = 0; j < typeOfInstruction->GetLength(); j = j + 2) { // + 2 means bcOffset and typeId
int32_t bcOffset = typeOfInstruction->Get(j).GetInt();
uint32_t typeId = static_cast<uint32_t>(typeOfInstruction->Get(j + 1).GetInt());
GlobalTSTypeRef gt = typeParser.CreateGT(jsPandaFile, recordName, typeId);
if (gt.IsDefault()) {
continue;
}
// The type of a function is recorded as (-1, funcTypeId). If the function is a member of a class,
// the type of the class or its instance is is recorded as (-2, classTypeId). If it is a static
// member, the type id refers to the type of the class; otherwise, it links to the type of the
// instances of the class.
if (bcOffset == METHOD_ANNOTATION_THIS_TYPE_OFFSET) {
thisGT = gt;
continue;
}
if (bcOffset == METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) {
funcGT = gt;
continue;
}
auto type = GateType(gt);
bcOffsetGtMap_.emplace(bcOffset, type);
}
LoadArgTypes(tsManager, funcGT, thisGT);
// The type of a function is recorded as (-1, funcTypeId). If the function is a member of a class,
// the type of the class or its instance is is recorded as (-2, classTypeId). If it is a static
// member, the type id refers to the type of the class; otherwise, it links to the type of the
// instances of the class.
if (bcOffset == METHOD_ANNOTATION_THIS_TYPE_OFFSET) {
thisGT = gt;
return;
}
if (bcOffset == METHOD_ANNOTATION_FUNCTION_TYPE_OFFSET) {
funcGT = gt;
return;
}
auto type = GateType(gt);
bcOffsetGtMap_.emplace(bcOffset, type);
});
LoadArgTypes(tsManager, funcGT, thisGT);
}
void TypeRecorder::LoadTypesFromPGO(const MethodLiteral *methodLiteral, const CString &recordName)

View File

@ -22,7 +22,7 @@
#include "ecmascript/jspandafile/method_literal.h"
#include "ecmascript/mem/c_containers.h"
#include "libpandafile/file.h"
#include "libpandafile/file-inl.h"
#include "libpandafile/file_items.h"
#include "libpandafile/literal_data_accessor.h"

View File

@ -19,7 +19,6 @@
#include "ecmascript/ecma_string.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/jspandafile/js_pandafile.h"
#include "ecmascript/module/js_module_manager.h"
#include "ecmascript/patch/quick_fix_manager.h"
#include "ecmascript/tagged_array-inl.h"
@ -445,46 +444,4 @@ JSHandle<TaggedArray> LiteralDataExtractor::GetDatasIgnoreType(JSThread *thread,
});
return literals;
}
// use for parsing specific literal which record TS type info
JSHandle<TaggedArray> LiteralDataExtractor::GetTypeLiteral(JSThread *thread, const JSPandaFile *jsPandaFile,
EntityId offset)
{
LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
uint32_t num = lda.GetLiteralValsNum(offset) / 2; // 2: half
JSHandle<TaggedArray> literals = factory->NewOldSpaceTaggedArray(num);
uint32_t pos = 0;
lda.EnumerateLiteralVals(
offset, [literals, &pos, factory, thread, jsPandaFile](const LiteralValue &value, const LiteralTag &tag) {
JSTaggedValue jt = JSTaggedValue::Null();
switch (tag) {
case LiteralTag::INTEGER: {
jt = JSTaggedValue(base::bit_cast<int32_t>(std::get<uint32_t>(value)));
break;
}
case LiteralTag::LITERALARRAY: {
ASSERT(std::get<uint32_t>(value) > LITERALARRAY_VALUE_LOW_BOUNDARY);
jt = JSTaggedValue(std::get<uint32_t>(value));
break;
}
case LiteralTag::BUILTINTYPEINDEX: {
jt = JSTaggedValue(std::get<uint8_t>(value));
break;
}
case LiteralTag::STRING: {
StringData sd = jsPandaFile->GetStringData(EntityId(std::get<uint32_t>(value)));
EcmaString *str = factory->GetRawStringFromStringTable(sd, MemSpaceType::OLD_SPACE);
jt = JSTaggedValue(str);
break;
}
default: {
LOG_FULL(FATAL) << "type literal should not exist LiteralTag: " << static_cast<uint8_t>(tag);
break;
}
}
literals->Set(thread, pos++, jt);
});
return literals;
}
} // namespace panda::ecmascript

View File

@ -16,7 +16,7 @@
#ifndef ECMASCRIPT_JSPANDAFILE_LITERAL_DATA_EXTRACTOR_H
#define ECMASCRIPT_JSPANDAFILE_LITERAL_DATA_EXTRACTOR_H
#include "ecmascript/jspandafile/panda_file_translator.h"
#include "ecmascript/jspandafile/js_pandafile.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "libpandafile/literal_data_accessor-inl.h"
@ -57,9 +57,6 @@ public:
static void PUBLIC_API GetMethodOffsets(const JSPandaFile *jsPandaFile, EntityId id,
std::vector<uint32_t> &methodOffsets);
static JSHandle<TaggedArray> PUBLIC_API GetTypeLiteral(JSThread *thread, const JSPandaFile *jsPandaFile,
EntityId offset);
private:
static JSHandle<TaggedArray> EnumerateLiteralVals(JSThread *thread, panda_file::LiteralDataAccessor &lda,
const JSPandaFile *jsPandaFile, size_t index, JSHandle<ConstantPool> constpool,

View File

@ -26,10 +26,9 @@
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tagged_array.h"
#include "ecmascript/ts_types/ts_manager.h"
#include "ecmascript/ts_types/ts_type_table.h"
#include "libpandabase/utils/utf.h"
#include "libpandafile/class_data_accessor-inl.h"
#include "libpandabase/utils/utf.h"
namespace panda::ecmascript {
template<class T, class... Args>

View File

@ -17,14 +17,12 @@
#define ECMASCRIPT_JSPANDAFILE_PANDA_FILE_TRANSLATOR_H
#include "ecmascript/ecma_vm.h"
#include "ecmascript/jspandafile/bytecode_inst/old_instruction.h"
#include "ecmascript/jspandafile/constpool_value.h"
#include "ecmascript/jspandafile/js_pandafile.h"
#include "libpandabase/utils/bit_field.h"
#include "libpandafile/code_data_accessor-inl.h"
#include "libpandafile/file-inl.h"
#include "ecmascript/jspandafile/bytecode_inst/old_instruction.h"
namespace panda::ecmascript {
class Program;

View File

@ -0,0 +1,248 @@
/*
* 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.
*/
#include "ecmascript/jspandafile/type_literal_extractor.h"
#include "libpandafile/literal_data_accessor-inl.h"
#include "libpandafile/method_data_accessor-inl.h"
namespace panda::ecmascript {
using LiteralTag = panda_file::LiteralTag;
using LiteralValue = panda_file::LiteralDataAccessor::LiteralValue;
using StringData = panda_file::StringData;
using EntityId = panda_file::File::EntityId;
using LiteralDataAccessor = panda_file::LiteralDataAccessor;
static constexpr const char *TYPE_ANNO_RECORD_NAME = "L_ESTypeAnnotation;";
static bool IsLegalOffset(uint32_t offset)
{
return offset != 0U;
}
static uint32_t GetMethodAnnoOffset(const JSPandaFile *jsPandaFile, uint32_t methodOffset, const char *annoName)
{
const panda_file::File &pf = *jsPandaFile->GetPandaFile();
EntityId methodId(methodOffset);
panda_file::MethodDataAccessor mda(pf, methodId);
uint32_t annoOffset = 0;
mda.EnumerateAnnotations([&jsPandaFile, &annoName, &pf, &annoOffset](EntityId annotationId) {
panda_file::AnnotationDataAccessor ada(pf, annotationId);
auto *annotationName = reinterpret_cast<const char *>(jsPandaFile->GetStringData(ada.GetClassId()).data);
ASSERT(annotationName != nullptr);
if (::strcmp(TYPE_ANNO_RECORD_NAME, annotationName) != 0) {
return;
}
uint32_t length = ada.GetCount();
for (uint32_t i = 0; i < length; i++) {
panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
auto *elemName = reinterpret_cast<const char *>(jsPandaFile->GetStringData(adae.GetNameId()).data);
ASSERT(elemName != nullptr);
if (::strcmp(annoName, elemName) != 0) {
continue;
}
panda_file::ScalarValue sv = adae.GetScalarValue();
annoOffset = sv.GetValue();
}
});
return annoOffset;
}
TypeLiteralExtractor::TypeLiteralExtractor(const JSPandaFile *jsPandaFile, const uint32_t typeOffset)
: typeOffset_(typeOffset)
{
ProcessTypeLiteral(jsPandaFile, typeOffset);
}
void TypeLiteralExtractor::ProcessTypeLiteral(const JSPandaFile *jsPandaFile, const uint32_t typeOffset)
{
EntityId literalId(typeOffset);
LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor();
bool isFirst = true;
lda.EnumerateLiteralVals(literalId,
[this, &jsPandaFile, &isFirst](const LiteralValue &value, const LiteralTag &tag) {
if (isFirst) {
uint32_t kindValue = std::get<uint32_t>(value);
if (UNLIKELY(!IsVaildKind(kindValue))) {
LOG_COMPILER(FATAL) << "Load type literal failure.";
return;
}
kind_ = static_cast<TSTypeKind>(std::get<uint32_t>(value));
isFirst = false;
return;
}
switch (tag) {
case LiteralTag::INTEGER: {
uint32_t valueValue = std::get<uint32_t>(value);
if (static_cast<int32_t>(valueValue) < 0) {
isGenerics_ = true;
}
array_.emplace_back(valueValue);
break;
}
case LiteralTag::LITERALARRAY: {
array_.emplace_back(std::get<uint32_t>(value));
break;
}
case LiteralTag::BUILTINTYPEINDEX: {
array_.emplace_back(static_cast<uint32_t>(std::get<uint8_t>(value)));
break;
}
case LiteralTag::STRING: {
StringData sd = jsPandaFile->GetStringData(EntityId(std::get<uint32_t>(value)));
CString stringValue = utf::Mutf8AsCString(sd.data);
array_.emplace_back(stringValue);
break;
}
default: {
LOG_COMPILER(FATAL) << "TypeLiteral should not exist LiteralTag: " << static_cast<uint32_t>(tag);
break;
}
}
});
}
TypeSummaryExtractor::TypeSummaryExtractor(const JSPandaFile *jsPandaFile, const CString &recordName)
{
ProcessTypeSummary(jsPandaFile, jsPandaFile->GetTypeSummaryOffset(recordName));
}
void TypeSummaryExtractor::ProcessTypeSummary(const JSPandaFile *jsPandaFile, const uint32_t summaryOffset)
{
EntityId summaryId(summaryOffset);
LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor();
bool isFirstIndex = true;
lda.EnumerateLiteralVals(summaryId,
[this, &isFirstIndex, &jsPandaFile](const LiteralValue &value, const LiteralTag &tag) {
switch (tag) {
case LiteralTag::LITERALARRAY: {
typeOffsets_.emplace_back(std::get<uint32_t>(value));
break;
}
case LiteralTag::BUILTINTYPEINDEX: {
typeOffsets_.emplace_back(static_cast<uint32_t>(std::get<uint8_t>(value)));
break;
}
case LiteralTag::INTEGER: {
if (isFirstIndex) {
numOfTypes_ = std::get<uint32_t>(value);
typeOffsets_.emplace_back(numOfTypes_);
isFirstIndex = false;
} else {
numOfRedirects_ = std::get<uint32_t>(value);
}
break;
}
case LiteralTag::STRING: {
StringData sd = jsPandaFile->GetStringData(EntityId(std::get<uint32_t>(value)));
CString stringValue = utf::Mutf8AsCString(sd.data);
reDirects_.emplace_back(stringValue);
break;
}
default: {
LOG_COMPILER(FATAL) << "TypeSummary should not exist LiteralTag: " << static_cast<uint32_t>(tag);
break;
}
}
});
ASSERT(typeOffsets_.size() == numOfTypes_ + 1);
ASSERT(reDirects_.size() == numOfRedirects_);
}
TypeAnnotationExtractor::TypeAnnotationExtractor(const JSPandaFile *jsPandaFile, const uint32_t methodOffset)
{
ProcessTypeAnnotation(jsPandaFile, methodOffset);
}
void TypeAnnotationExtractor::ProcessTypeAnnotation(const JSPandaFile *jsPandaFile, const uint32_t methodOffset)
{
uint32_t annoOffset = GetMethodAnnoOffset(jsPandaFile, methodOffset, TYPE_ANNO_ELEMENT_NAME);
if (!IsLegalOffset(annoOffset)) {
return;
}
EntityId annoId(annoOffset);
LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor();
lda.EnumerateLiteralVals(annoId, [this](const LiteralValue &value, const LiteralTag &tag) {
switch (tag) {
case LiteralTag::INTEGER: {
int32_t valueValue = base::bit_cast<int32_t>(std::get<uint32_t>(value));
bcOffsets_.emplace_back(valueValue);
break;
}
case LiteralTag::LITERALARRAY: {
typeIds_.emplace_back(std::get<uint32_t>(value));
break;
}
case LiteralTag::BUILTINTYPEINDEX: {
typeIds_.emplace_back(static_cast<uint32_t>(std::get<uint8_t>(value)));
break;
}
default: {
LOG_COMPILER(FATAL) << "TypeAnnotation should not exist LiteralTag: " << static_cast<uint32_t>(tag);
break;
}
}
});
ASSERT(bcOffsets_.size() == typeIds_.size());
}
ExportTypeTableExtractor::ExportTypeTableExtractor(const JSPandaFile *jsPandaFile,
const CString &recordName,
bool isBuiltinTable)
{
ProcessExportTable(jsPandaFile, recordName, isBuiltinTable);
}
void ExportTypeTableExtractor::ProcessExportTable(const JSPandaFile *jsPandaFile,
const CString &recordName,
bool isBuiltinTable)
{
const char *name = isBuiltinTable ? DECLARED_SYMBOL_TYPES : EXPORTED_SYMBOL_TYPES;
uint32_t methodOffset = jsPandaFile->GetMainMethodIndex(recordName);
uint32_t annoOffset = GetMethodAnnoOffset(jsPandaFile, methodOffset, name);
if (!IsLegalOffset(annoOffset)) {
return;
}
EntityId annoId(annoOffset);
LiteralDataAccessor lda = jsPandaFile->GetLiteralDataAccessor();
lda.EnumerateLiteralVals(annoId, [this, &jsPandaFile](const LiteralValue &value, const LiteralTag &tag) {
switch (tag) {
case LiteralTag::LITERALARRAY: {
typeIds_.emplace_back(std::get<uint32_t>(value));
break;
}
case LiteralTag::BUILTINTYPEINDEX: {
typeIds_.emplace_back(static_cast<uint32_t>(std::get<uint8_t>(value)));
break;
}
case LiteralTag::STRING: {
StringData sd = jsPandaFile->GetStringData(EntityId(std::get<uint32_t>(value)));
exportVars_.emplace_back(utf::Mutf8AsCString(sd.data));
break;
}
default: {
LOG_COMPILER(FATAL) << "TypeExportTable should not exist LiteralTag: " << static_cast<uint32_t>(tag);
break;
}
}
});
ASSERT(exportVars_.size() == typeIds_.size());
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,207 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_JSPANDAFILE_TYPE_LITERAL_EXTRACTOR_H
#define ECMASCRIPT_JSPANDAFILE_TYPE_LITERAL_EXTRACTOR_H
#include "ecmascript/jspandafile/js_pandafile.h"
namespace panda::ecmascript {
class TypeLiteralExtractor {
using TypeLiteralValue = std::variant<uint32_t, CString>;
public:
explicit TypeLiteralExtractor(const JSPandaFile *jsPandaFile, const uint32_t typeOffset);
~TypeLiteralExtractor() = default;
NO_COPY_SEMANTIC(TypeLiteralExtractor);
NO_MOVE_SEMANTIC(TypeLiteralExtractor);
inline bool IsVaildTypeLiteral() const
{
return !array_.empty();
}
inline TSTypeKind GetTypeKind() const
{
return kind_;
}
inline bool IsGenerics() const
{
return isGenerics_;
}
inline void SetGenerics()
{
isGenerics_ = true;
}
inline uint32_t GetIntValue(const uint32_t index) const
{
ASSERT(index < array_.size());
auto t = array_[index];
ASSERT(std::holds_alternative<uint32_t>(t));
return std::get<uint32_t>(t);
}
inline const CString &GetStringValue(const uint32_t index) const
{
ASSERT(index < array_.size());
const auto &t = array_[index];
ASSERT(std::holds_alternative<CString>(t));
return std::get<CString>(t);
}
inline uint32_t GetTypeOffset() const
{
return typeOffset_;
}
template <class Callback>
void EnumerateElements(const uint32_t numIndex, const Callback &callback)
{
ASSERT(numIndex < array_.size());
uint32_t length = std::get<uint32_t>(array_[numIndex]);
ASSERT(numIndex + length < array_.size());
for (uint32_t i = 1; i <= length; i++) {
uint32_t value = GetIntValue(numIndex + i);
callback(value);
}
}
template <class Callback>
void EnumerateProperties(const uint32_t numIndex, const uint32_t gap, const Callback &callback)
{
ASSERT(numIndex < array_.size());
ASSERT(gap >= VALUE_OFFSET);
uint32_t length = std::get<uint32_t>(array_[numIndex]);
ASSERT(numIndex + length * gap < array_.size());
for (uint32_t i = 0; i < length; i++) {
uint32_t keyIndex = numIndex + i * gap + KEY_OFFSET;
uint32_t valueIndex = numIndex + i * gap + VALUE_OFFSET;
const CString &key = GetStringValue(keyIndex);
uint32_t value = GetIntValue(valueIndex);
callback(key, value);
}
}
private:
static constexpr uint32_t KEY_OFFSET = 1;
static constexpr uint32_t VALUE_OFFSET = 2;
inline bool IsVaildKind(const uint32_t kindValue) const
{
return (static_cast<uint32_t>(TSTypeKind::TYPEKIND_FIRST) <= kindValue) &&
(kindValue <= static_cast<uint32_t>(TSTypeKind::TYPEKIND_LAST));
}
void ProcessTypeLiteral(const JSPandaFile *jsPandaFile, const uint32_t typeOffset);
std::vector<TypeLiteralValue> array_;
uint32_t typeOffset_ { 0 };
TSTypeKind kind_ { TSTypeKind::UNKNOWN };
bool isGenerics_ { false };
};
class TypeSummaryExtractor {
public:
explicit TypeSummaryExtractor(const JSPandaFile *jsPandaFile, const CString &recordName);
~TypeSummaryExtractor() = default;
NO_COPY_SEMANTIC(TypeSummaryExtractor);
NO_MOVE_SEMANTIC(TypeSummaryExtractor);
template <class Callback>
void EnumerateTypeOffsets(const uint32_t lastIndex, const Callback &callback)
{
ASSERT(lastIndex < typeOffsets_.size());
for (uint32_t i = 0; i <= lastIndex; i++) {
callback(typeOffsets_[i]);
}
}
inline uint32_t GetNumOfTypes() const
{
return numOfTypes_;
}
private:
void ProcessTypeSummary(const JSPandaFile *jsPandaFile, const uint32_t summaryOffset);
std::vector<uint32_t> typeOffsets_ {};
std::vector<CString> reDirects_ {};
uint32_t numOfTypes_ { 0 };
uint32_t numOfRedirects_ { 0 };
};
class TypeAnnotationExtractor {
public:
explicit TypeAnnotationExtractor(const JSPandaFile *jsPandaFile, const uint32_t methodOffset);
~TypeAnnotationExtractor() = default;
NO_COPY_SEMANTIC(TypeAnnotationExtractor);
NO_MOVE_SEMANTIC(TypeAnnotationExtractor);
template <class Callback>
void EnumerateInstsAndTypes(const Callback &callback)
{
ASSERT(bcOffsets_.size() == typeIds_.size());
uint32_t length = bcOffsets_.size();
for (uint32_t i = 0; i < length; i++) {
callback(bcOffsets_[i], typeIds_[i]);
}
}
private:
static constexpr const char *TYPE_ANNO_ELEMENT_NAME = "_TypeOfInstruction";
void ProcessTypeAnnotation(const JSPandaFile *jsPandaFile, const uint32_t methodOffset);
std::vector<int32_t> bcOffsets_ {};
std::vector<uint32_t> typeIds_ {};
};
class ExportTypeTableExtractor {
public:
explicit ExportTypeTableExtractor(const JSPandaFile *jsPandaFile, const CString &recordName, bool isBuiltinTable);
~ExportTypeTableExtractor() = default;
NO_COPY_SEMANTIC(ExportTypeTableExtractor);
NO_MOVE_SEMANTIC(ExportTypeTableExtractor);
inline uint32_t GetLength() const
{
ASSERT(exportVars_.size() == typeIds_.size());
return exportVars_.size() + typeIds_.size();
}
template <class Callback>
void EnumerateModuleTypes(const Callback &callback)
{
ASSERT(exportVars_.size() == typeIds_.size());
uint32_t length = exportVars_.size();
for (uint32_t i = 0; i < length; i++) {
callback(exportVars_[i], typeIds_[i]);
}
}
private:
static constexpr const char *DECLARED_SYMBOL_TYPES = "declaredSymbolTypes";
static constexpr const char *EXPORTED_SYMBOL_TYPES = "exportedSymbolTypes";
void ProcessExportTable(const JSPandaFile *jsPandaFile, const CString &recordName, bool isBuiltinTable);
std::vector<CString> exportVars_ {};
std::vector<uint32_t> typeIds_ {};
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JSPANDAFILE_TYPE_LITERAL_EXTRACTOR_H

View File

@ -20,12 +20,9 @@
#include "libpandabase/utils/bit_field.h"
namespace panda::ecmascript {
/*
* To maintain consistency with the frontend, ITERATOR_INSTANCE should always be at
* the end of TSTypeKind, because there is no ITERATOR_INSTANCE in the frontend.
*/
enum class TSTypeKind : int {
enum class TSTypeKind : uint8_t {
PRIMITIVE = 0,
// the following typekinds are recorded in abc files and are consistent with the corresponding values
CLASS,
CLASS_INSTANCE,
FUNCTION,
@ -33,9 +30,17 @@ enum class TSTypeKind : int {
ARRAY,
OBJECT,
IMPORT,
INTERFACE_KIND,
INTERFACE,
BUILTININST,
GENERICINST,
INDEXSIG,
// the following typekinds are not recorded in abc files and will be created at compile time
ITERATOR_INSTANCE,
UNKNOWN
UNKNOWN,
TYPEKIND_FIRST = CLASS,
TYPEKIND_LAST = INDEXSIG,
};
enum class TSPrimitiveType : int {

View File

@ -20,7 +20,6 @@
#include "ecmascript/jspandafile/js_pandafile_manager.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/subtyping_operator.h"
#include "ecmascript/ts_types/ts_type_parser.h"
#include "ecmascript/ts_types/ts_type_table_generator.h"
#include "ecmascript/vtable.h"
@ -235,7 +234,7 @@ TSTypeKind TSManager::GetTypeKind(const GlobalTSTypeRef &gt) const
case JSType::TS_OBJECT_TYPE:
return TSTypeKind::OBJECT;
case JSType::TS_INTERFACE_TYPE:
return TSTypeKind::INTERFACE_KIND;
return TSTypeKind::INTERFACE;
case JSType::TS_ITERATOR_INSTANCE_TYPE:
return TSTypeKind::ITERATOR_INSTANCE;
default:
@ -909,7 +908,7 @@ std::string TSManager::GetTypeStr(kungfu::GateType gateType) const
return "object";
case TSTypeKind::IMPORT:
return "import";
case TSTypeKind::INTERFACE_KIND:
case TSTypeKind::INTERFACE:
return "interface";
case TSTypeKind::ITERATOR_INSTANCE:
return "iterator_instance";
@ -1220,12 +1219,36 @@ kungfu::GateType TSManager::TryNarrowUnionType(kungfu::GateType gateType)
return gateType;
}
JSHandle<TaggedArray> TSManager::GetExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName)
{
// To compare with the exportTable, we need to parse the literalbuffer in abc TypeAnnotation.
// If the exportTable already exist, we will use it directly. OtherWise, we will parse and store it.
// In type system parser at a later stage, we will also use these arrays to avoid duplicate parsing.
if (HasResolvedExportTable(jsPandaFile, recordName)) {
JSTaggedValue exportTypeTable = GetResolvedExportTable(jsPandaFile, recordName);
JSHandle<TaggedArray> table(vm_->GetJSThread(), exportTypeTable);
return table;
}
JSHandle<TaggedArray> typeOfExportedSymbols = GenerateExportTableFromLiteral(jsPandaFile, recordName);
AddResolvedExportTable(jsPandaFile, recordName, typeOfExportedSymbols.GetTaggedValue());
return typeOfExportedSymbols;
}
JSHandle<TaggedArray> TSManager::GenerateExportTableFromLiteral(const JSPandaFile *jsPandaFile,
const CString &recordName)
{
TSTypeParser parser(this);
JSHandle<TaggedArray> typeOfExportedSymbols = parser.GetExportDataFromRecord(jsPandaFile, recordName);
AddResolvedExportTable(jsPandaFile, recordName, typeOfExportedSymbols.GetTaggedValue());
bool isBuiltinTable = (std::strcmp(recordName.c_str(), TSTypeTable::BUILTINS_TABLE_NAME) == 0);
ExportTypeTableExtractor exTableExtractor(jsPandaFile, recordName, isBuiltinTable);
uint32_t length = exTableExtractor.GetLength();
JSHandle<TaggedArray> typeOfExportedSymbols = factory_->NewOldSpaceTaggedArray(length);
uint32_t index = 0;
exTableExtractor.EnumerateModuleTypes(
[this, &typeOfExportedSymbols, &index](const CString &name, const uint32_t typeId) {
JSHandle<EcmaString> str = factory_->NewFromUtf8(name);
typeOfExportedSymbols->Set(thread_, index++, JSTaggedValue(str.GetTaggedValue()));
typeOfExportedSymbols->Set(thread_, index++, JSTaggedValue(typeId));
});
return typeOfExportedSymbols;
}
@ -1285,12 +1308,11 @@ void TSManager::GenerateBuiltinSummary()
SetBuiltinPandaFile(jsPandaFile.get());
CString builtinsRecordName(TSTypeTable::BUILTINS_TABLE_NAME);
SetBuiltinRecordName(builtinsRecordName);
panda_file::File::EntityId summaryOffset(jsPandaFile->GetTypeSummaryOffset(builtinsRecordName));
JSHandle<TaggedArray> builtinOffsets =
LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile.get(), summaryOffset);
for (uint32_t i = 0; i <= static_cast<uint32_t>(BuiltinTypeId::NUM_OF_BUILTIN_TYPES); i++) {
builtinOffsets_.emplace_back(static_cast<uint32_t>(builtinOffsets->Get(i).GetInt()));
}
TypeSummaryExtractor summExtractor(jsPandaFile.get(), builtinsRecordName);
summExtractor.EnumerateTypeOffsets(static_cast<uint32_t>(BuiltinTypeId::NUM_OF_BUILTIN_TYPES),
[this](const uint32_t typeOffset) {
builtinOffsets_.emplace_back(typeOffset);
});
}
void TSManager::PrintNumOfTypes() const

View File

@ -16,12 +16,13 @@
#ifndef ECMASCRIPT_TS_TYPES_TS_MANAGER_H
#define ECMASCRIPT_TS_TYPES_TS_MANAGER_H
#include "ecmascript/js_handle.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/ts_types/global_ts_type_ref.h"
#include "ecmascript/ts_types/ts_obj_layout_info.h"
#include "ecmascript/compiler/bytecode_info_collector.h"
#include "ecmascript/compiler/compilation_driver.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/jspandafile/type_literal_extractor.h"
#include "ecmascript/ts_types/global_ts_type_ref.h"
#include "ecmascript/ts_types/ts_obj_layout_info.h"
namespace panda::ecmascript {
enum class MTableIdx : uint8_t {
@ -411,7 +412,7 @@ public:
V(Array, TSTypeKind::ARRAY) \
V(Object, TSTypeKind::OBJECT) \
V(Import, TSTypeKind::IMPORT) \
V(Interface, TSTypeKind::INTERFACE_KIND) \
V(Interface, TSTypeKind::INTERFACE) \
V(IteratorInstance, TSTypeKind::ITERATOR_INSTANCE) \
#define IS_TSTYPEKIND(NAME, TSTYPEKIND) \
@ -440,7 +441,11 @@ public:
bool isImportType = false)
{
auto key = std::make_pair(jsPandaFile, offset);
literalOffsetGTMap_.emplace(key, gt);
if (literalOffsetGTMap_.find(key) != literalOffsetGTMap_.end()) {
literalOffsetGTMap_[key] = gt;
} else {
literalOffsetGTMap_.emplace(key, gt);
}
if (!isImportType) {
auto value = std::make_pair(recordName, offset);
gtLiteralOffsetMap_.emplace(gt, value);
@ -693,7 +698,7 @@ public:
kungfu::GateType TryNarrowUnionType(kungfu::GateType gateType);
JSHandle<TaggedArray> GenerateExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName);
JSHandle<TaggedArray> GetExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName);
private:
NO_COPY_SEMANTIC(TSManager);
@ -701,6 +706,8 @@ private:
GlobalTSTypeRef AddTSTypeToTypeTable(const JSHandle<TSType> &type, int tableId) const;
JSHandle<TaggedArray> GenerateExportTableFromLiteral(const JSPandaFile *jsPandaFile, const CString &recordName);
GlobalTSTypeRef FindUnionInTypeTable(JSHandle<TSTypeTable> table, JSHandle<TSUnionType> unionType) const;
GlobalTSTypeRef FindIteratorInstanceInInferTable(GlobalTSTypeRef kindGt, GlobalTSTypeRef elementGt) const;

View File

@ -77,7 +77,6 @@ class TSClassType : public TSType {
public:
CAST_CHECK(TSClassType, IsTSClassType);
static constexpr size_t FIELD_LENGTH = 4; // every field record name, typeIndex, accessFlag, readonly
static constexpr size_t INSTANCE_TYPE_OFFSET = TSType::SIZE;
static GlobalTSTypeRef GetPropTypeGT(JSThread *thread, JSHandle<TSClassType> classType,
@ -149,9 +148,6 @@ class TSInterfaceType : public TSType {
public:
CAST_CHECK(TSInterfaceType, IsTSInterfaceType);
// every field record name, typeIndex, accessFlag, readonly
static constexpr size_t FIELD_LENGTH = 4;
static GlobalTSTypeRef GetPropTypeGT(JSThread *thread, JSHandle<TSInterfaceType> classInstanceType,
JSHandle<JSTaggedValue> propName);

View File

@ -17,13 +17,16 @@
#include "ecmascript/base/path_helper.h"
#include "ecmascript/jspandafile/js_pandafile_manager.h"
#include "ecmascript/jspandafile/literal_data_extractor.h"
#include "ecmascript/jspandafile/type_literal_extractor.h"
#include "ecmascript/module/js_module_manager.h"
#include "libpandafile/annotation_data_accessor.h"
#include "libpandafile/class_data_accessor-inl.h"
namespace panda::ecmascript {
// For each property of one class, object or interface, it's name and typeIndex are recorded in order,
// and if it is a field, then accessFlag and readonly of this property will be additionally recorded.
static constexpr uint32_t FIELD_LENGTH = 4;
static constexpr uint32_t METHOD_LENGTH = 2;
static constexpr uint32_t INDEX_OCCUPIED_OFFSET = 1;
TSTypeParser::TSTypeParser(TSManager *tsManager)
: tsManager_(tsManager), vm_(tsManager->GetEcmaVM()),
thread_(vm_->GetJSThread()), factory_(vm_->GetFactory()),
@ -72,14 +75,13 @@ GlobalTSTypeRef TSTypeParser::ParseBuiltinObjType(uint32_t typeId)
GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId)
{
panda_file::File::EntityId offset(typeId);
JSHandle<TaggedArray> literal = LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, offset);
if (literal->GetLength() == 0) { // typeLiteral maybe hole in d.abc
return GetAndStoreGT(jsPandaFile, typeId, recordName);
TypeLiteralExtractor typeLiteralExtractor(jsPandaFile, typeId);
if (!typeLiteralExtractor.IsVaildTypeLiteral()) { // typeLiteral maybe hole in d.abc
return GlobalTSTypeRef::Default();
}
TSTypeKind kind = static_cast<TSTypeKind>(literal->Get(TYPE_KIND_INDEX_IN_LITERAL).GetInt());
if (kind == TSTypeKind::IMPORT) {
return ResolveImportType(jsPandaFile, recordName, literal, typeId);
if (typeLiteralExtractor.GetTypeKind() == TSTypeKind::IMPORT) {
return ResolveImportType(jsPandaFile, recordName, &typeLiteralExtractor);
}
uint32_t moduleId = tableGenerator_.TryGetModuleId(recordName);
@ -100,7 +102,7 @@ GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CS
table->SetNumberOfTypes(thread_, localId);
GlobalTSTypeRef gt = GetAndStoreGT(jsPandaFile, typeId, recordName, moduleId, localId);
JSHandle<JSTaggedValue> type = ParseNonImportType(jsPandaFile, recordName, literal, kind, typeId);
JSHandle<JSTaggedValue> type = ParseNonImportType(jsPandaFile, recordName, &typeLiteralExtractor);
if (UNLIKELY(type->IsUndefined())) {
return GetAndStoreGT(jsPandaFile, typeId, recordName);
}
@ -111,9 +113,11 @@ GlobalTSTypeRef TSTypeParser::ParseType(const JSPandaFile *jsPandaFile, const CS
}
GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
JSHandle<TaggedArray> literal, uint32_t typeId)
TypeLiteralExtractor *typeLiteralExtractor)
{
JSHandle<EcmaString> importVarNamePath(thread_, literal->Get(IMPORT_PATH_OFFSET_IN_LITERAL)); // #A#./A
uint32_t typeId = typeLiteralExtractor->GetTypeOffset();
JSHandle<EcmaString> importVarNamePath =
factory_->NewFromUtf8(typeLiteralExtractor->GetStringValue(DEFAULT_INDEX));
JSHandle<EcmaString> relativePath = GenerateImportRelativePath(importVarNamePath);
CString cstringRelativePath = ConvertToString(*relativePath);
// skip @ohos:|@app:|@native: prefixed imports
@ -135,7 +139,7 @@ GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile,
uint32_t moduleId = tableGenerator_.TryGetModuleId(entryPoint);
if (UNLIKELY(!GlobalTSTypeRef::IsVaildModuleId(moduleId))) {
LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the recored "
LOG_COMPILER(DEBUG) << "The maximum number of TSTypeTables is reached. All TSTypes in the record "
<< entryPoint << " will not be parsed and will be treated as any.";
return GetAndStoreGT(jsPandaFile, typeId, recordName);
}
@ -150,40 +154,43 @@ GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile,
}
JSHandle<JSTaggedValue> TSTypeParser::ParseNonImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
JSHandle<TaggedArray> literal, TSTypeKind kind, uint32_t typeId)
TypeLiteralExtractor *typeLiteralExtractor)
{
auto kind = typeLiteralExtractor->GetTypeKind();
switch (kind) {
case TSTypeKind::CLASS: {
JSHandle<TSClassType> classType = ParseClassType(jsPandaFile, recordName, literal, typeId);
JSHandle<TSClassType> classType = ParseClassType(jsPandaFile, recordName, typeLiteralExtractor);
return JSHandle<JSTaggedValue>(classType);
}
case TSTypeKind::CLASS_INSTANCE: {
JSHandle<TSClassInstanceType> classInstanceType = ParseClassInstanceType(jsPandaFile, recordName, literal);
JSHandle<TSClassInstanceType> classInstanceType =
ParseClassInstanceType(jsPandaFile, recordName, typeLiteralExtractor);
return JSHandle<JSTaggedValue>(classInstanceType);
}
case TSTypeKind::INTERFACE_KIND: {
JSHandle<TSInterfaceType> interfaceType = ParseInterfaceType(jsPandaFile, recordName, literal);
case TSTypeKind::INTERFACE: {
JSHandle<TSInterfaceType> interfaceType = ParseInterfaceType(jsPandaFile, recordName, typeLiteralExtractor);
return JSHandle<JSTaggedValue>(interfaceType);
}
case TSTypeKind::UNION: {
JSHandle<TSUnionType> unionType = ParseUnionType(jsPandaFile, recordName, literal);
JSHandle<TSUnionType> unionType = ParseUnionType(jsPandaFile, recordName, typeLiteralExtractor);
return JSHandle<JSTaggedValue>(unionType);
}
case TSTypeKind::FUNCTION: {
JSHandle<TSFunctionType> functionType = ParseFunctionType(jsPandaFile, recordName, literal, typeId);
JSHandle<TSFunctionType> functionType =
ParseFunctionType(jsPandaFile, recordName, typeLiteralExtractor);
return JSHandle<JSTaggedValue>(functionType);
}
case TSTypeKind::ARRAY: {
JSHandle<TSArrayType> arrayType = ParseArrayType(jsPandaFile, recordName, literal);
JSHandle<TSArrayType> arrayType = ParseArrayType(jsPandaFile, recordName, typeLiteralExtractor);
return JSHandle<JSTaggedValue>(arrayType);
}
case TSTypeKind::OBJECT: {
JSHandle<TSObjectType> objectType = ParseObjectType(jsPandaFile, recordName, literal);
JSHandle<TSObjectType> objectType = ParseObjectType(jsPandaFile, recordName, typeLiteralExtractor);
return JSHandle<JSTaggedValue>(objectType);
}
default: {
LOG_COMPILER(DEBUG) << "Do not support parse types with kind " << static_cast<uint32_t>(kind) << ". "
<< "Please check whether the type literal " << typeId
<< "Please check whether the type literal " << typeLiteralExtractor->GetTypeOffset()
<< " recorded in the record " << recordName << " is correct.";
return thread_->GlobalConstants()->GetHandledUndefined();
}
@ -191,20 +198,228 @@ JSHandle<JSTaggedValue> TSTypeParser::ParseNonImportType(const JSPandaFile *jsPa
}
JSHandle<TSClassType> TSTypeParser::ParseClassType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal, uint32_t typeId)
TypeLiteralExtractor *typeLiteralExtractor)
{
JSHandle<TSClassType> classType = factory_->NewTSClassType();
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS);
ClassLiteralInfo classLitInfo(typeLiteralExtractor);
uint32_t numNonStaticFieldsIndex = classLitInfo.numNonStaticFieldsIndex;
uint32_t numNonStaticMethodsIndex = classLitInfo.numNonStaticMethodsIndex;
uint32_t numStaticFieldsIndex = classLitInfo.numStaticFieldsIndex;
uint32_t numStaticMethodsIndex = classLitInfo.numStaticMethodsIndex;
std::string className = tsManager_->GetClassNameByOffset(jsPandaFile, typeId);
JSHandle<TSClassType> classType = factory_->NewTSClassType();
SetClassName(classType, jsPandaFile, typeLiteralExtractor);
SetSuperClassType(classType, jsPandaFile, recordName, typeLiteralExtractor);
// resolve instance type
uint32_t numFields = typeLiteralExtractor->GetIntValue(numNonStaticFieldsIndex);
JSHandle<TSObjectType> instanceType = factory_->NewTSObjectType(numFields);
FillPropTypes(jsPandaFile, recordName, instanceType, typeLiteralExtractor, numNonStaticFieldsIndex, FIELD_LENGTH);
classType->SetInstanceType(thread_, instanceType);
// resolve prototype type
uint32_t numNonStatic = typeLiteralExtractor->GetIntValue(numNonStaticMethodsIndex);
JSHandle<TSObjectType> prototypeType = factory_->NewTSObjectType(numNonStatic);
FillPropTypes(jsPandaFile, recordName, prototypeType, typeLiteralExtractor,
numNonStaticMethodsIndex, METHOD_LENGTH);
classType->SetPrototypeType(thread_, prototypeType);
// resolve constructor type
uint32_t numStaticFields = typeLiteralExtractor->GetIntValue(numStaticFieldsIndex);
uint32_t numStaticMethods = typeLiteralExtractor->GetIntValue(numStaticMethodsIndex);
uint32_t numStatic = numStaticFields + numStaticMethods;
JSHandle<TSObjectType> constructorType = factory_->NewTSObjectType(numStatic);
FillPropTypes(jsPandaFile, recordName, constructorType, typeLiteralExtractor, numStaticFieldsIndex, FIELD_LENGTH);
FillPropTypes(jsPandaFile, recordName, constructorType, typeLiteralExtractor,
numStaticMethodsIndex, METHOD_LENGTH);
classType->SetConstructorType(thread_, constructorType);
return classType;
}
JSHandle<TSClassInstanceType> TSTypeParser::ParseClassInstanceType(const JSPandaFile *jsPandaFile,
const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS_INSTANCE);
JSHandle<TSClassInstanceType> classInstanceType = factory_->NewTSClassInstanceType();
// classTypeId is stored in the first position
uint32_t classTypeId = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX);
auto classGT = CreateGT(jsPandaFile, recordName, classTypeId);
classInstanceType->SetClassGT(classGT);
return classInstanceType;
}
JSHandle<TSInterfaceType> TSTypeParser::ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::INTERFACE);
JSHandle<TSInterfaceType> interfaceType = factory_->NewTSInterfaceType();
InterfaceLiteralInfo interfaceLitInfo(typeLiteralExtractor);
uint32_t numFieldsIndex = interfaceLitInfo.numFieldsIndex;
uint32_t numMethodsIndex = interfaceLitInfo.numMethodsIndex;
// resolve extends of interface
uint32_t numExtends = typeLiteralExtractor->GetIntValue(InterfaceLiteralInfo::NUM_EXTENDS_INDEX);
JSHandle<TaggedArray> extendsId = factory_->NewTaggedArray(numExtends);
uint32_t extendsIndex = 0;
typeLiteralExtractor->EnumerateElements(InterfaceLiteralInfo::NUM_EXTENDS_INDEX,
[this, &jsPandaFile, &recordName, &extendsIndex, &extendsId](const uint32_t literalValue) {
auto extendGT = CreateGT(jsPandaFile, recordName, literalValue);
extendsId->Set(thread_, extendsIndex++, JSTaggedValue(extendGT.GetType()));
});
interfaceType->SetExtends(thread_, extendsId);
uint32_t numFields = typeLiteralExtractor->GetIntValue(numFieldsIndex);
uint32_t numMethods = typeLiteralExtractor->GetIntValue(numMethodsIndex);
uint32_t totalFields = numFields + numMethods;
JSHandle<TSObjectType> fieldsType = factory_->NewTSObjectType(totalFields);
FillPropTypes(jsPandaFile, recordName, fieldsType, typeLiteralExtractor, numFieldsIndex, FIELD_LENGTH);
FillInterfaceMethodTypes(jsPandaFile, recordName, fieldsType, typeLiteralExtractor, numMethodsIndex);
interfaceType->SetFields(thread_, fieldsType);
return interfaceType;
}
JSHandle<TSUnionType> TSTypeParser::ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::UNION);
// the number of union types is stored in the first position
uint32_t numOfUnionMembers = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX);
JSHandle<TSUnionType> unionType = factory_->NewTSUnionType(numOfUnionMembers);
JSHandle<TaggedArray> components(thread_, unionType->GetComponents());
uint32_t index = 0;
typeLiteralExtractor->EnumerateElements(DEFAULT_INDEX,
[this, &jsPandaFile, &recordName, &index, &components](const uint32_t literalValue) {
auto componentGT = CreateGT(jsPandaFile, recordName, literalValue);
components->Set(thread_, index++, JSTaggedValue(componentGT.GetType()));
});
unionType->SetComponents(thread_, components);
return unionType;
}
JSHandle<TSFunctionType> TSTypeParser::ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::FUNCTION);
FunctionLiteralInfo functionLitInfo(typeLiteralExtractor);
uint32_t numParasIndex = functionLitInfo.numParasIndex;
uint32_t returnTypeIndex = functionLitInfo.returnTypeIndex;
uint32_t length = typeLiteralExtractor->GetIntValue(numParasIndex);
JSHandle<TSFunctionType> functionType = factory_->NewTSFunctionType(length);
SetFunctionThisType(functionType, jsPandaFile, recordName, typeLiteralExtractor);
JSHandle<TaggedArray> parameterTypes(thread_, functionType->GetParameterTypes());
uint32_t index = 0;
typeLiteralExtractor->EnumerateElements(numParasIndex,
[this, &jsPandaFile, &recordName, &index, &parameterTypes](const uint32_t literalValue) {
auto parameterGT = CreateGT(jsPandaFile, recordName, literalValue);
if (tsManager_->IsClassTypeKind(parameterGT)) {
parameterGT = tsManager_->CreateClassInstanceType(parameterGT);
}
parameterTypes->Set(thread_, index++, JSTaggedValue(parameterGT.GetType()));
});
functionType->SetParameterTypes(thread_, parameterTypes);
JSHandle<JSTaggedValue> functionName(
factory_->NewFromUtf8(typeLiteralExtractor->GetStringValue(FunctionLiteralInfo::NAME_INDEX)));
functionType->SetName(thread_, functionName);
uint32_t returntypeId = typeLiteralExtractor->GetIntValue(returnTypeIndex);
auto returnGT = CreateGT(jsPandaFile, recordName, returntypeId);
functionType->SetReturnGT(returnGT);
uint32_t bitField = typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::BITFIELD_INDEX);
functionType->SetBitField(bitField);
StoreMethodOffset(functionType, typeLiteralExtractor);
return functionType;
}
JSHandle<TSArrayType> TSTypeParser::ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::ARRAY);
JSHandle<TSArrayType> arrayType = factory_->NewTSArrayType();
// the type of elements of array is stored in the first position
auto elemetnGT = CreateGT(jsPandaFile, recordName, typeLiteralExtractor->GetIntValue(DEFAULT_INDEX));
if (tsManager_->IsClassTypeKind(elemetnGT)) {
elemetnGT = tsManager_->CreateClassInstanceType(elemetnGT);
}
arrayType->SetElementGT(elemetnGT);
return arrayType;
}
JSHandle<TSObjectType> TSTypeParser::ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::OBJECT);
// the number of properties of object is stored in the first position
uint32_t length = typeLiteralExtractor->GetIntValue(DEFAULT_INDEX);
JSHandle<TSObjectType> objectType = factory_->NewTSObjectType(length);
FillPropTypes(jsPandaFile, recordName, objectType, typeLiteralExtractor, DEFAULT_INDEX, METHOD_LENGTH);
return objectType;
}
void TSTypeParser::FillPropTypes(const JSPandaFile *jsPandaFile,
const CString &recordName,
const JSHandle<TSObjectType> &objectType,
TypeLiteralExtractor *typeLiteralExtractor,
const uint32_t numOfFieldIndex,
const uint32_t gap)
{
JSHandle<TSObjLayoutInfo> layout(thread_, objectType->GetObjLayoutInfo());
JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
typeLiteralExtractor->EnumerateProperties(numOfFieldIndex, gap,
[this, &key, &jsPandaFile, &recordName, &layout](const CString &literalKey, const uint32_t literalValue) {
JSHandle<JSTaggedValue> propName(factory_->NewFromUtf8(literalKey));
key.Update(propName.GetTaggedValue());
ASSERT(key->IsString());
auto gt = CreateGT(jsPandaFile, recordName, literalValue);
if (tsManager_->IsClassTypeKind(gt)) {
gt = tsManager_->CreateClassInstanceType(gt);
}
layout->AddKeyAndType(thread_, key.GetTaggedValue(), JSTaggedValue(gt.GetType()));
});
}
void TSTypeParser::FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile,
const CString &recordName,
const JSHandle<TSObjectType> &objectType,
TypeLiteralExtractor *typeLiteralExtractor,
const uint32_t numExtends)
{
JSHandle<TSObjLayoutInfo> layout(thread_, objectType->GetObjLayoutInfo());
JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
typeLiteralExtractor->EnumerateElements(numExtends,
[this, &jsPandaFile, &recordName, &layout, &key](const uint32_t literalValue) {
auto gt = CreateGT(jsPandaFile, recordName, literalValue);
if (tsManager_->IsFunctionTypeKind(gt)) {
JSHandle<JSTaggedValue> tsType = tsManager_->GetTSType(gt);
ASSERT(tsType->IsTSFunctionType());
JSHandle<TSFunctionType> functionType(tsType);
key.Update(functionType->GetName());
};
layout->AddKeyAndType(thread_, key.GetTaggedValue(), JSTaggedValue(gt.GetType()));
});
}
void TSTypeParser::SetClassName(const JSHandle<TSClassType> &classType,
const JSPandaFile *jsPandaFile,
TypeLiteralExtractor *typeLiteralExtractor)
{
std::string className = tsManager_->GetClassNameByOffset(jsPandaFile, typeLiteralExtractor->GetTypeOffset());
JSHandle<EcmaString> classEcmaString = factory_->NewFromStdString(className);
classType->SetName(thread_, classEcmaString.GetTaggedValue());
}
uint32_t index = 0;
ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::CLASS);
const uint32_t ignoreLength = 2; // 2: ignore accessFlag and readonly
index += ignoreLength;
int extendsTypeId = literal->Get(index++).GetInt();
void TSTypeParser::SetSuperClassType(const JSHandle<TSClassType> &classType,
const JSPandaFile *jsPandaFile,
const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
uint32_t extendsTypeId = typeLiteralExtractor->GetIntValue(ClassLiteralInfo::SUPER_CLASS_INDEX);
if (TSClassType::IsBaseClassType(extendsTypeId)) {
classType->SetHasLinked(true);
} else {
@ -214,284 +429,32 @@ JSHandle<TSClassType> TSTypeParser::ParseClassType(const JSPandaFile *jsPandaFil
classType->SetHasLinked(true);
}
}
// ignore implement
uint32_t numImplement = literal->Get(index++).GetInt();
index += numImplement;
// resolve instance type
uint32_t numFields = static_cast<uint32_t>(literal->Get(index++).GetInt());
JSHandle<TSObjectType> instanceType = factory_->NewTSObjectType(numFields);
JSHandle<TSObjLayoutInfo> instanceTypeInfo(thread_, instanceType->GetObjLayoutInfo());
ASSERT(instanceTypeInfo->GetPropertiesCapacity() == numFields);
FillPropertyTypes(jsPandaFile, recordName, instanceTypeInfo, literal, 0, numFields, index, true);
classType->SetInstanceType(thread_, instanceType);
// resolve prototype type
uint32_t numNonStatic = literal->Get(index++).GetInt();
JSHandle<TSObjectType> prototypeType = factory_->NewTSObjectType(numNonStatic);
JSHandle<TSObjLayoutInfo> nonStaticTypeInfo(thread_, prototypeType->GetObjLayoutInfo());
ASSERT(nonStaticTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(numNonStatic));
FillPropertyTypes(jsPandaFile, recordName, nonStaticTypeInfo, literal, 0, numNonStatic, index, false);
classType->SetPrototypeType(thread_, prototypeType);
// resolve constructor type
// static include fields and methods, which the former takes up 4 spaces and the latter takes up 2 spaces.
uint32_t numStaticFields = literal->Get(index++).GetInt();
uint32_t numStaticMethods = literal->Get(index + numStaticFields * TSClassType::FIELD_LENGTH).GetInt();
uint32_t numStatic = numStaticFields + numStaticMethods;
// new function type when support it
JSHandle<TSObjectType> constructorType = factory_->NewTSObjectType(numStatic);
JSHandle<TSObjLayoutInfo> staticTypeInfo(thread_, constructorType->GetObjLayoutInfo());
ASSERT(staticTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(numStatic));
FillPropertyTypes(jsPandaFile, recordName, staticTypeInfo, literal, 0, numStaticFields, index, true);
index++; // jmp over numStaticMethods
// static methods
FillPropertyTypes(jsPandaFile, recordName, staticTypeInfo, literal, numStaticFields, numStatic, index, false);
classType->SetConstructorType(thread_, constructorType);
return classType;
}
JSHandle<TSClassInstanceType> TSTypeParser::ParseClassInstanceType(const JSPandaFile *jsPandaFile,
const CString &recordName,
const JSHandle<TaggedArray> &literal)
void TSTypeParser::SetFunctionThisType(const JSHandle<TSFunctionType> &functionType,
const JSPandaFile *jsPandaFile,
const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(static_cast<TSTypeKind>(literal->Get(TYPE_KIND_INDEX_IN_LITERAL).GetInt()) ==
TSTypeKind::CLASS_INSTANCE);
JSHandle<TSClassInstanceType> classInstanceType = factory_->NewTSClassInstanceType();
uint32_t classTypeId = static_cast<uint32_t>(literal->Get(TSClassInstanceType::CREATE_CLASS_OFFSET).GetInt());
auto classGT = CreateGT(jsPandaFile, recordName, classTypeId);
classInstanceType->SetClassGT(classGT);
return classInstanceType;
}
JSHandle<TSInterfaceType> TSTypeParser::ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal)
{
uint32_t index = 0;
JSHandle<TSInterfaceType> interfaceType = factory_->NewTSInterfaceType();
ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::INTERFACE_KIND);
index++;
// resolve extends of interface
uint32_t numExtends = literal->Get(index++).GetInt();
JSHandle<TaggedArray> extendsId = factory_->NewTaggedArray(numExtends);
JSMutableHandle<JSTaggedValue> extendsType(thread_, JSTaggedValue::Undefined());
for (uint32_t extendsIndex = 0; extendsIndex < numExtends; extendsIndex++) {
auto typeId = literal->Get(index++).GetInt();
auto extendGT = CreateGT(jsPandaFile, recordName, typeId);
extendsType.Update(JSTaggedValue(extendGT.GetType()));
extendsId->Set(thread_, extendsIndex, extendsType);
}
interfaceType->SetExtends(thread_, extendsId);
// resolve fields and methods of interface
uint32_t numFields = static_cast<uint32_t>(literal->Get(index++).GetInt());
// field takes up 4 spaces and method takes up 2 spaces.
uint32_t numMethods = static_cast<uint32_t>(literal->Get(index +
numFields * TSInterfaceType::FIELD_LENGTH).GetInt());
uint32_t totalFields = numFields + numMethods;
JSHandle<TSObjectType> fieldsType = factory_->NewTSObjectType(totalFields);
JSHandle<TSObjLayoutInfo> fieldsTypeInfo(thread_, fieldsType->GetObjLayoutInfo());
ASSERT(fieldsTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(totalFields));
FillPropertyTypes(jsPandaFile, recordName, fieldsTypeInfo, literal, 0, numFields, index, true);
index++; // jmp over numMethod
FillInterfaceMethodTypes(jsPandaFile, recordName, fieldsTypeInfo, literal, numFields, totalFields, index);
interfaceType->SetFields(thread_, fieldsType);
return interfaceType;
}
JSHandle<TSUnionType> TSTypeParser::ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal)
{
uint32_t literalIndex = 0;
ASSERT(static_cast<TSTypeKind>(literal->Get(literalIndex).GetInt()) == TSTypeKind::UNION);
literalIndex++;
uint32_t numOfUnionMembers = literal->Get(literalIndex++).GetInt();
JSHandle<TSUnionType> unionType = factory_->NewTSUnionType(numOfUnionMembers);
JSHandle<TaggedArray> components(thread_, unionType->GetComponents());
for (uint32_t index = 0; index < numOfUnionMembers; ++index) {
uint32_t componentTypeId = literal->Get(literalIndex++).GetInt();
auto componentGT = CreateGT(jsPandaFile, recordName, componentTypeId);
components->Set(thread_, index, JSTaggedValue(componentGT.GetType()));
}
unionType->SetComponents(thread_, components);
return unionType;
}
JSHandle<TSFunctionType> TSTypeParser::ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal, uint32_t functionId)
{
uint32_t index = 0;
ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::FUNCTION);
index++;
int32_t bitField = literal->Get(index++).GetInt();
JSHandle<JSTaggedValue> functionName(thread_, literal->Get(index++));
bool hasThisType = static_cast<bool>(literal->Get(index++).GetInt());
int32_t thisTypeId = 0;
if (hasThisType) {
thisTypeId = literal->Get(index++).GetInt();
}
int32_t length = literal->Get(index++).GetInt();
JSHandle<TSFunctionType> functionType = factory_->NewTSFunctionType(length);
JSHandle<TaggedArray> parameterTypes(thread_, functionType->GetParameterTypes());
JSMutableHandle<JSTaggedValue> parameterTypeRef(thread_, JSTaggedValue::Undefined());
for (int32_t i = 0; i < length; ++i) {
auto typeId = literal->Get(index++).GetInt();
auto parameterGT = CreateGT(jsPandaFile, recordName, typeId);
if (tsManager_->IsClassTypeKind(parameterGT)) {
parameterGT = tsManager_->CreateClassInstanceType(parameterGT);
}
parameterTypeRef.Update(JSTaggedValue(parameterGT.GetType()));
parameterTypes->Set(thread_, i, parameterTypeRef);
}
int32_t returntypeId = literal->Get(index++).GetInt();
functionType->SetName(thread_, functionName);
bool hasThisType = static_cast<bool>(typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::HAS_THIS_TYPE_INDEX));
if (hasThisType) {
// if hasThisType is true, then the next position will store typeId of this
uint32_t thisTypeId = typeLiteralExtractor->GetIntValue(FunctionLiteralInfo::HAS_THIS_TYPE_INDEX + 1);
auto thisGT = CreateGT(jsPandaFile, recordName, thisTypeId);
functionType->SetThisGT(thisGT);
}
}
functionType->SetParameterTypes(thread_, parameterTypes);
auto returnGT = CreateGT(jsPandaFile, recordName, returntypeId);
functionType->SetReturnGT(returnGT);
functionType->SetBitField(bitField);
auto bcInfoCollector = tsManager_->GetBytecodeInfoCollector();
if (bcInfoCollector != nullptr) {
auto &bcInfo = bcInfoCollector->GetBytecodeInfo();
uint32_t methodOffset = bcInfo.IterateFunctionTypeIDAndMethodOffset(functionId);
void TSTypeParser::StoreMethodOffset(const JSHandle<TSFunctionType> &functionType,
TypeLiteralExtractor *typeLiteralExtractor)
{
if (bcInfo_ != nullptr) {
uint32_t typeOffset = typeLiteralExtractor->GetTypeOffset();
uint32_t methodOffset = bcInfo_->IterateFunctionTypeIDAndMethodOffset(typeOffset);
if (methodOffset != 0) {
functionType->SetMethodOffset(methodOffset);
}
}
return functionType;
}
JSHandle<TSArrayType> TSTypeParser::ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal)
{
uint32_t index = 0;
ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::ARRAY);
index++;
JSHandle<JSTaggedValue> elementTypeId(thread_, literal->Get(index++));
ASSERT(elementTypeId->IsInt());
JSHandle<TSArrayType> arrayType = factory_->NewTSArrayType();
auto elemetnGT = CreateGT(jsPandaFile, recordName, elementTypeId->GetInt());
if (tsManager_->IsClassTypeKind(elemetnGT)) {
elemetnGT = tsManager_->CreateClassInstanceType(elemetnGT);
}
arrayType->SetElementGT(elemetnGT);
return arrayType;
}
JSHandle<TSObjectType> TSTypeParser::ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal)
{
uint32_t index = 0;
ASSERT(static_cast<TSTypeKind>(literal->Get(index).GetInt()) == TSTypeKind::OBJECT);
index++;
uint32_t length = literal->Get(index++).GetInt();
JSHandle<TSObjectType> objectType = factory_->NewTSObjectType(length);
JSHandle<TSObjLayoutInfo> propertyTypeInfo(thread_, objectType->GetObjLayoutInfo());
ASSERT(propertyTypeInfo->GetPropertiesCapacity() == static_cast<uint32_t>(length));
FillPropertyTypes(jsPandaFile, recordName, propertyTypeInfo, literal, 0, length, index, false);
objectType->SetObjLayoutInfo(thread_, propertyTypeInfo);
return objectType;
}
void TSTypeParser::FillPropertyTypes(const JSPandaFile *jsPandaFile, const CString &recordName,
JSHandle<TSObjLayoutInfo> &layout, const JSHandle<TaggedArray> &literal,
uint32_t startIndex, uint32_t lastIndex, uint32_t &index, bool isField)
{
JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> value(thread_, JSTaggedValue::Undefined());
for (uint32_t fieldIndex = startIndex; fieldIndex < lastIndex; ++fieldIndex) {
key.Update(literal->Get(index++));
ASSERT(key->IsString());
auto gt = CreateGT(jsPandaFile, recordName, literal->Get(index++).GetInt());
if (tsManager_->IsClassTypeKind(gt)) {
gt = tsManager_->CreateClassInstanceType(gt);
}
value.Update(JSTaggedValue(gt.GetType()));
layout->AddKeyAndType(thread_, key.GetTaggedValue(), value.GetTaggedValue());
if (isField) {
index += 2; // 2: ignore accessFlag and readonly
}
}
}
void TSTypeParser::FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile, const CString &recordName,
JSHandle<TSObjLayoutInfo> &layout, const JSHandle<TaggedArray> &literal,
uint32_t startIndex, uint32_t lastIndex, uint32_t &index)
{
JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> value(thread_, JSTaggedValue::Undefined());
for (uint32_t methodIndex = startIndex; methodIndex < lastIndex; ++methodIndex) {
auto gt = CreateGT(jsPandaFile, recordName, literal->Get(index++).GetInt());
value.Update(JSTaggedValue(gt.GetType()));
if (tsManager_->IsFunctionTypeKind(gt)) {
JSHandle<JSTaggedValue> tsType = tsManager_->GetTSType(gt);
ASSERT(tsType->IsTSFunctionType());
JSHandle<TSFunctionType> functionType(tsType);
key.Update(functionType->GetName());
};
layout->AddKeyAndType(thread_, key.GetTaggedValue(), value.GetTaggedValue());
}
}
JSHandle<TaggedArray> TSTypeParser::GetExportDataFromRecord(const JSPandaFile *jsPandaFile,
const CString &recordName)
{
const panda_file::File &pf = *jsPandaFile->GetPandaFile();
panda_file::File::EntityId methodId(jsPandaFile->GetMainMethodIndex(recordName));
panda_file::MethodDataAccessor mda(pf, methodId);
const char *symbolTypes;
auto *fileName = pf.GetFilename().c_str();
if (::strcmp(TSTypeTable::BUILTINS_TABLE_NAME, fileName) == 0) {
symbolTypes = DECLARED_SYMBOL_TYPES;
} else {
symbolTypes = EXPORTED_SYMBOL_TYPES;
}
JSHandle<TaggedArray> typeOfExportedSymbols(thread_, thread_->GlobalConstants()->GetEmptyArray());
mda.EnumerateAnnotations([&](panda_file::File::EntityId annotationId) {
panda_file::AnnotationDataAccessor ada(pf, annotationId);
auto *annotationName = reinterpret_cast<const char *>(jsPandaFile->GetStringData(ada.GetClassId()).data);
ASSERT(annotationName != nullptr);
if (::strcmp("L_ESTypeAnnotation;", annotationName) != 0) {
return;
}
uint32_t length = ada.GetCount();
for (uint32_t i = 0; i < length; i++) {
panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
auto *elemName = reinterpret_cast<const char *>(jsPandaFile->GetStringData(adae.GetNameId()).data);
ASSERT(elemName != nullptr);
if (::strcmp(symbolTypes, elemName) != 0) {
continue;
}
panda_file::ScalarValue sv = adae.GetScalarValue();
panda_file::File::EntityId literalOffset(sv.GetValue());
typeOfExportedSymbols = LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, literalOffset);
// typeOfExprotedSymbols: "symbol0", "type0", "symbol1", "type1" ...
}
});
return typeOfExportedSymbols;
}
JSHandle<JSTaggedValue> TSTypeParser::GenerateExportTableFromRecord(const JSPandaFile *jsPandaFile,
@ -501,24 +464,15 @@ JSHandle<JSTaggedValue> TSTypeParser::GenerateExportTableFromRecord(const JSPand
JSHandle<JSTaggedValue> exportValeTable = TSTypeTable::GetExportValueTable(thread_, table);
if (exportValeTable->IsUndefined()) {
// Read export-data from annotation of the .abc File
JSHandle<TaggedArray> exportTable;
if (tsManager_->HasResolvedExportTable(jsPandaFile, recordName)) {
JSTaggedValue resolvedTable = tsManager_->GetResolvedExportTable(jsPandaFile, recordName);
exportTable = JSHandle<TaggedArray>::Cast(JSHandle<JSTaggedValue>(thread_, resolvedTable));
} else {
exportTable = GetExportDataFromRecord(jsPandaFile, recordName);
}
JSHandle<TaggedArray> exportTable = tsManager_->GetExportTableFromLiteral(jsPandaFile, recordName);
uint32_t length = exportTable->GetLength();
// Replace typeIds with GT
JSTaggedValue target;
for (uint32_t i = 1; i < length; i += 2) { // 2: skip a pair of key and value
target = exportTable->Get(i);
JSTaggedValue target = exportTable->Get(i);
// Create GT based on typeId, and wrapped it into a JSTaggedValue
uint32_t typeId = static_cast<uint32_t>(target.GetInt());
GlobalTSTypeRef typeGT = CreateGT(jsPandaFile, recordName, typeId);
GlobalTSTypeRef gt = CreateGT(jsPandaFile, recordName, typeId);
// Set the wrapped GT to exportTable
exportTable->Set(thread_, i, JSTaggedValue(typeGT.GetType()));
exportTable->Set(thread_, i, JSTaggedValue(gt.GetType()));
}
TSTypeTable::SetExportValueTable(thread_, table, exportTable);
return JSHandle<JSTaggedValue>(exportTable);
@ -591,4 +545,35 @@ GlobalTSTypeRef TSTypeParser::IterateStarExport(JSHandle<EcmaString> target, con
}
return GlobalTSTypeRef::Default();
}
static uint32_t CalculateNextNumIndex(const TypeLiteralExtractor *typeLiteralExtractor,
uint32_t startIndex = 0,
uint32_t gap = 1)
{
return startIndex + INDEX_OCCUPIED_OFFSET + (typeLiteralExtractor->GetIntValue(startIndex) * gap);
}
ClassLiteralInfo::ClassLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::CLASS);
numNonStaticFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, NUM_IMPLEMENTS_INDEX);
numNonStaticMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numNonStaticFieldsIndex, FIELD_LENGTH);
numStaticFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, numNonStaticMethodsIndex, METHOD_LENGTH);
numStaticMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numStaticFieldsIndex, FIELD_LENGTH);
}
InterfaceLiteralInfo::InterfaceLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::INTERFACE);
numFieldsIndex = CalculateNextNumIndex(typeLiteralExtractor, NUM_EXTENDS_INDEX);
numMethodsIndex = CalculateNextNumIndex(typeLiteralExtractor, numFieldsIndex, FIELD_LENGTH);
}
FunctionLiteralInfo::FunctionLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor)
{
ASSERT(typeLiteralExtractor->GetTypeKind() == TSTypeKind::FUNCTION);
numParasIndex = HAS_THIS_TYPE_INDEX + INDEX_OCCUPIED_OFFSET +
typeLiteralExtractor->GetIntValue(HAS_THIS_TYPE_INDEX);
returnTypeIndex = CalculateNextNumIndex(typeLiteralExtractor, numParasIndex);
}
} // namespace panda::ecmascript

View File

@ -36,17 +36,11 @@ public:
GlobalTSTypeRef PUBLIC_API CreateGT(const JSPandaFile *jsPandaFile, const CString &recordName, uint32_t typeId);
JSHandle<TaggedArray> GetExportDataFromRecord(const JSPandaFile *jsPandaFile, const CString &recordName);
static constexpr size_t USER_DEFINED_TYPE_OFFSET = 100;
private:
static constexpr size_t TYPE_KIND_INDEX_IN_LITERAL = 0;
static constexpr size_t BUILDIN_TYPE_OFFSET = 20;
static constexpr size_t IMPORT_PATH_OFFSET_IN_LITERAL = 1;
static constexpr const char* DECLARED_SYMBOL_TYPES = "declaredSymbolTypes";
static constexpr const char* EXPORTED_SYMBOL_TYPES = "exportedSymbolTypes";
static constexpr size_t DEFAULT_INDEX = 0;
inline GlobalTSTypeRef GetAndStoreGT(const JSPandaFile *jsPandaFile, uint32_t typeId, const CString &recordName,
uint32_t moduleId = 0, uint32_t localId = 0)
@ -76,45 +70,60 @@ private:
GlobalTSTypeRef ParseBuiltinObjType(uint32_t typeId);
GlobalTSTypeRef ResolveImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
JSHandle<TaggedArray> literal, uint32_t typeId);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<JSTaggedValue> ParseNonImportType(const JSPandaFile *jsPandaFile, const CString &recordName,
JSHandle<TaggedArray> literal, TSTypeKind kind, uint32_t typeId);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<TSClassType> ParseClassType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal, uint32_t typeId);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<TSClassInstanceType> ParseClassInstanceType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<TSInterfaceType> ParseInterfaceType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<TSUnionType> ParseUnionType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<TSFunctionType> ParseFunctionType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal, uint32_t functionId);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<TSArrayType> ParseArrayType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal);
TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<TSObjectType> ParseObjectType(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TaggedArray> &literal);
TypeLiteralExtractor *typeLiteralExtractor);
void FillPropertyTypes(const JSPandaFile *jsPandaFile,
const CString &recordName,
JSHandle<TSObjLayoutInfo> &layout,
const JSHandle<TaggedArray> &literal,
uint32_t startIndex, uint32_t lastIndex,
uint32_t &index, bool isField);
void FillPropTypes(const JSPandaFile *jsPandaFile,
const CString &recordName,
const JSHandle<TSObjectType> &objectType,
TypeLiteralExtractor *typeLiteralExtractor,
const uint32_t numOfFieldIndex,
const uint32_t gap);
void FillInterfaceMethodTypes(const JSPandaFile *jsPandaFile,
const CString &recordName,
JSHandle<TSObjLayoutInfo> &layout,
const JSHandle<TaggedArray> &literal,
uint32_t startIndex, uint32_t lastIndex,
uint32_t &index);
const JSHandle<TSObjectType> &objectType,
TypeLiteralExtractor *typeLiteralExtractor,
const uint32_t numExtends);
void SetClassName(const JSHandle<TSClassType> &classType,
const JSPandaFile *jsPandaFile,
TypeLiteralExtractor *typeLiteralExtractor);
void SetSuperClassType(const JSHandle<TSClassType> &classType,
const JSPandaFile *jsPandaFile,
const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor);
void SetFunctionThisType(const JSHandle<TSFunctionType> &functionType,
const JSPandaFile *jsPandaFile,
const CString &recordName,
TypeLiteralExtractor *typeLiteralExtractor);
void StoreMethodOffset(const JSHandle<TSFunctionType> &functionType, TypeLiteralExtractor *typeLiteralExtractor);
JSHandle<JSTaggedValue> GenerateExportTableFromRecord(const JSPandaFile *jsPandaFile, const CString &recordName,
const JSHandle<TSTypeTable> &table);
@ -137,5 +146,40 @@ private:
TSTypeTableGenerator tableGenerator_;
kungfu::BCInfo *bcInfo_ {nullptr};
};
struct ClassLiteralInfo {
explicit ClassLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor);
~ClassLiteralInfo() = default;
static constexpr uint32_t SUPER_CLASS_INDEX = 1;
static constexpr uint32_t NUM_IMPLEMENTS_INDEX = 2;
uint32_t numNonStaticFieldsIndex {0};
uint32_t numNonStaticMethodsIndex {0};
uint32_t numStaticFieldsIndex {0};
uint32_t numStaticMethodsIndex {0};
};
struct InterfaceLiteralInfo {
explicit InterfaceLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor);
~InterfaceLiteralInfo() = default;
static constexpr uint32_t NUM_EXTENDS_INDEX = 0;
uint32_t numFieldsIndex {0};
uint32_t numMethodsIndex {0};
};
struct FunctionLiteralInfo {
explicit FunctionLiteralInfo(const TypeLiteralExtractor *typeLiteralExtractor);
~FunctionLiteralInfo() = default;
static constexpr uint32_t BITFIELD_INDEX = 0;
static constexpr uint32_t NAME_INDEX = 1;
static constexpr uint32_t HAS_THIS_TYPE_INDEX = 2;
uint32_t numParasIndex {0};
uint32_t returnTypeIndex {0};
};
} // panda::ecmascript
#endif // ECMASCRIPT_TS_TYPES_TS_TYPE_PARSER_H

View File

@ -55,16 +55,8 @@ JSHandle<TSTypeTable> TSTypeTableGenerator::GetOrGenerateTSTypeTable(const JSPan
return tsManager_->GetTSTypeTable(moduleId);
}
JSHandle<EcmaString> recordNameStr = factory_->NewFromUtf8(recordName);
// read type summary literal
// struct of summaryLiteral: {numTypes, literalOffset0, literalOffset1, ...}
panda_file::File::EntityId summaryOffset(jsPandaFile->GetTypeSummaryOffset(recordName));
JSHandle<TaggedArray> summaryLiteral =
LiteralDataExtractor::GetTypeLiteral(thread_, jsPandaFile, summaryOffset);
uint32_t numIdx = static_cast<uint32_t>(BuiltinTypeId::NUM_INDEX_IN_SUMMARY);
uint32_t numTypes = static_cast<uint32_t>(summaryLiteral->Get(numIdx).GetInt());
// Initialize a empty TSTypeTable with length of (numTypes + RESERVE_TABLE_LENGTH)
JSHandle<TSTypeTable> table = AddTypeTable(recordNameStr, numTypes);
TypeSummaryExtractor summExtractor(jsPandaFile, recordName);
JSHandle<TSTypeTable> table = AddTypeTable(recordNameStr, summExtractor.GetNumOfTypes());
return table;
}