Support typeinfer for generic types [PART_1]

In order to support typeinfer for generic types, we first need to refactor
the process of extracting types and parsing types to handling negative numbers,
which represent formal parameters of generic types recorded in type literals in abc files.

Issus:
https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I6UYLQ

Tests:
test262, typeinfer test, aot test

Signed-off-by: huoqingyi <huoqingyi@huawei.com>
Change-Id: I8197a93c81cc2b2335a418b0307b23880a0799e4
This commit is contained in:
huoqingyi 2023-04-12 10:41:30 +08:00
parent f45cc301c6
commit 34ddc47922
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;
}