ISA-Refactor for ecmascript

ISA-Refactor for ecmascript

Issue: I5QWXL
Signed-off-by: qiuyu <qiuyu22@huawei.com>
This commit is contained in:
qiuyu 2022-08-11 22:51:28 +08:00
parent 5071676ae9
commit 46397a5114
41 changed files with 1845 additions and 4038 deletions

View File

@ -95,7 +95,7 @@ def assembler_signature(group, is_jump)
o.type, o.name = is_jump ? ['const std::string &', 'label'] : ['int64_t', o.name]
end
elsif o.name.start_with?('id')
o.type, o.name = ['const std::string &', 'id']
o.type, o.name = ['const std::string &', o.name]
else
o.type = 'uint16_t'
end

View File

@ -733,78 +733,45 @@ bool AsmEmitter::AddAnnotations(T *item, ItemContainer *container, const Annotat
}
template <class T>
static void AddBytecodeIndexDependencies(MethodItem *method, const Ins &insn,
const std::unordered_map<std::string, T *> &items)
static void AddDependencyByIndex(MethodItem *method, const Ins &insn,
const std::unordered_map<std::string, T *> &items, size_t idx = 0)
{
ASSERT(!insn.ids.empty());
for (const auto &id : insn.ids) {
auto it = items.find(id);
ASSERT(it != items.cend());
auto *item = it->second;
ASSERT(item->GetIndexType() != panda_file::IndexType::NONE);
method->AddIndexDependency(item);
}
}
static void IncreaseInsLiteralArrayIdByBase(panda::pandasm::Ins &insn, size_t base)
{
switch (insn.opcode) {
case panda::pandasm::Opcode::ECMA_CREATEARRAYWITHBUFFER:
case panda::pandasm::Opcode::ECMA_CREATEOBJECTWITHBUFFER:
case panda::pandasm::Opcode::ECMA_CREATEOBJECTHAVINGMETHOD:
case panda::pandasm::Opcode::ECMA_DEFINECLASSWITHBUFFER:
insn.imms[0] = std::get<int64_t>(insn.imms[0]) + static_cast<int64_t>(base);
return;
case panda::pandasm::Opcode::ECMA_NEWLEXENVWITHNAMEDYN:
insn.imms[1] = std::get<int64_t>(insn.imms[1]) + static_cast<int64_t>(base);
return;
default:
return;
}
ASSERT(idx < insn.ids.size());
const auto &id = insn.ids[idx];
auto it = items.find(id);
ASSERT(it != items.cend());
auto *item = it->second;
ASSERT(item->GetIndexType() != panda_file::IndexType::NONE);
method->AddIndexDependency(item);
}
static void AddBytecodeIndexDependencies(MethodItem *method, const Function &func,
const AsmEmitter::AsmEntityCollections &entities, uint32_t base)
{
for (const auto &insn : func.ins) {
// correct literal array id, need to remove after isa refactoring
if (base != 0) {
IncreaseInsLiteralArrayIdByBase(const_cast<pandasm::Ins &>(insn), base);
}
if (insn.opcode == Opcode::INVALID) {
continue;
}
if (insn.opcode == Opcode::DEFINECLASSWITHBUFFER) {
AddDependencyByIndex(method, insn, entities.method_items);
AddDependencyByIndex(method, insn, entities.literalarray_items, 1);
continue;
}
if (insn.HasFlag(InstFlags::METHOD_ID)) {
AddBytecodeIndexDependencies(method, insn, entities.method_items);
AddDependencyByIndex(method, insn, entities.method_items);
continue;
}
if (insn.HasFlag(InstFlags::FIELD_ID)) {
AddBytecodeIndexDependencies(method, insn, entities.field_items);
if (insn.HasFlag(InstFlags::STRING_ID)) {
AddDependencyByIndex(method, insn, entities.string_items);
continue;
}
if (insn.HasFlag(InstFlags::TYPE_ID)) {
AddBytecodeIndexDependencies(method, insn, entities.class_items);
continue;
if (insn.HasFlag(InstFlags::LITERALARRAY_ID)) {
AddDependencyByIndex(method, insn, entities.literalarray_items);
}
}
for (const auto &catch_block : func.catch_blocks) {
if (catch_block.exception_record.empty()) {
continue;
}
auto it = entities.class_items.find(catch_block.exception_record);
ASSERT(it != entities.class_items.cend());
auto *item = it->second;
ASSERT(item->GetIndexType() != panda_file::IndexType::NONE);
method->AddIndexDependency(item);
}
}
/* static */
@ -1239,6 +1206,7 @@ bool AsmEmitter::CreateMethodItem(ItemContainer *items, AsmEmitter::AsmEntityCol
method = items->CreateItem<ForeignMethodItem>(area, method_name, proto, access_flags);
} else {
method = area->AddMethod(method_name, proto, access_flags, params);
method->SetFunctionKind(func.GetFunctionKind());
}
} else {
if (!func.metadata->IsForeign()) {
@ -1248,7 +1216,7 @@ bool AsmEmitter::CreateMethodItem(ItemContainer *items, AsmEmitter::AsmEntityCol
method = items->CreateItem<ForeignMethodItem>(foreign_area, method_name, proto, access_flags);
}
entities.method_items.insert({mangled_name, method});
if (!func.metadata->IsForeign() && func.metadata->HasImplementation()) {
if (!func.metadata->IsForeign()) {
if (!func.source_file.empty()) {
items->GetOrCreateStringItem(func.source_file);
}
@ -1379,22 +1347,6 @@ void AsmEmitter::SetCodeAndDebugInfo(ItemContainer *items, MethodItem *method, c
method->SetDebugInfo(debug_info);
}
/* static */
void AsmEmitter::SetMethodSourceLang(const Program &program, MethodItem *method, const Function &func,
const std::string &name)
{
std::string record_name = GetOwnerName(name);
if (record_name.empty()) {
method->SetSourceLang(func.language);
return;
}
auto &rec = program.record_table.find(record_name)->second;
if (rec.language != func.language) {
method->SetSourceLang(func.language);
}
}
/* static */
bool AsmEmitter::AddMethodAndParamsAnnotations(ItemContainer *items, const Program &program,
const AsmEmitter::AsmEntityCollections &entities, MethodItem *method,
@ -1442,12 +1394,10 @@ bool AsmEmitter::MakeFunctionDebugInfoAndAnnotations(ItemContainer *items, const
auto *method = static_cast<MethodItem *>(Find(entities.method_items, name));
if (func.metadata->HasImplementation()) {
SetCodeAndDebugInfo(items, method, func, emit_debug_info);
AddBytecodeIndexDependencies(method, func, entities, GetBase());
}
SetCodeAndDebugInfo(items, method, func, emit_debug_info);
AddBytecodeIndexDependencies(method, func, entities, GetBase());
SetMethodSourceLang(program, method, func, name);
method->SetSourceLang(func.language);
if (!AddMethodAndParamsAnnotations(items, program, entities, method, func)) {
return false;
@ -1520,7 +1470,7 @@ bool AsmEmitter::EmitFunctions(ItemContainer *items, const Program &program,
for (const auto &f : program.function_table) {
const auto &[name, func] = f;
if (func.metadata->IsForeign() || !func.metadata->HasImplementation()) {
if (func.metadata->IsForeign()) {
continue;
}
@ -1578,8 +1528,44 @@ bool AsmEmitter::MakeItemsForSingleProgram(ItemContainer *items, const Program &
return true;
}
// temp plan for ic slot number, should be deleted after method refactoring
static void MakeSlotNumberRecord(Program *prog)
{
static const std::string SLOT_NUMBER = "_ESSlotNumberAnnotation";
pandasm::Record record(SLOT_NUMBER, pandasm::extensions::Language::ECMASCRIPT);
record.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
prog->record_table.emplace(SLOT_NUMBER, std::move(record));
}
// temp plan for ic slot number, should be deleted after method refactoring
static void MakeSlotNumberAnnotation(Program *prog)
{
static const std::string SLOT_NUMBER = "_ESSlotNumberAnnotation";
static const std::string ELEMENT_NAME = "SlotNumber";
for (auto &[name, func] : prog->function_table) {
for (const auto &an : func.metadata->GetAnnotations()) {
if (an.GetName() == SLOT_NUMBER) {
return;
}
}
pandasm::AnnotationData anno(SLOT_NUMBER);
pandasm::AnnotationElement ele(ELEMENT_NAME, std::make_unique<pandasm::ScalarValue>(
pandasm::ScalarValue::Create<pandasm::Value::Type::U32>(static_cast<uint32_t>(func.GetSlotsNum()))));
anno.AddElement(std::move(ele));
std::vector<pandasm::AnnotationData> annos;
annos.emplace_back(anno);
func.metadata->AddAnnotations(annos);
}
}
bool AsmEmitter::EmitPrograms(const std::string &filename, const std::vector<Program *> &progs, bool emit_debug_info)
{
ASSERT(!progs.empty());
for (auto *prog : progs) {
MakeSlotNumberRecord(prog);
MakeSlotNumberAnnotation(prog);
}
auto items = ItemContainer {};
auto primitive_types = CreatePrimitiveTypes(&items);
auto entities = AsmEmitter::AsmEntityCollections {};
@ -1624,6 +1610,8 @@ bool AsmEmitter::EmitPrograms(const std::string &filename, const std::vector<Pro
bool AsmEmitter::Emit(ItemContainer *items, const Program &program, PandaFileToPandaAsmMaps *maps, bool emit_debug_info,
panda::panda_file::pgo::ProfileOptimizer *profile_opt)
{
MakeSlotNumberRecord(const_cast<Program *>(&program));
MakeSlotNumberAnnotation(const_cast<Program *>(&program));
auto primitive_types = CreatePrimitiveTypes(items);
auto entities = AsmEmitter::AsmEntityCollections {};
@ -1734,7 +1722,7 @@ bool Function::Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays) const
{
auto labels = std::unordered_map<std::string_view, panda::Label> {};

View File

@ -45,7 +45,7 @@ public:
std::unordered_map<std::string, panda_file::BaseMethodItem *> method_items;
std::unordered_map<std::string, panda_file::BaseFieldItem *> field_items;
std::unordered_map<std::string, panda_file::BaseClassItem *> class_items;
std::unordered_map<std::string_view, panda_file::StringItem *> string_items;
std::unordered_map<std::string, panda_file::StringItem *> string_items;
std::unordered_map<std::string, panda_file::LiteralArrayItem *> literalarray_items;
};
@ -124,8 +124,6 @@ private:
const AsmEntityCollections &entities);
static void SetCodeAndDebugInfo(panda_file::ItemContainer *items, panda_file::MethodItem *method,
const Function &func, bool emit_debug_info);
static void SetMethodSourceLang(const Program &program, panda_file::MethodItem *method, const Function &func,
const std::string &name);
static bool AddMethodAndParamsAnnotations(panda_file::ItemContainer *items, const Program &program,
const AsmEmitter::AsmEntityCollections &entities,
panda_file::MethodItem *method, const Function &func);

View File

@ -86,6 +86,28 @@ struct Function {
Type return_type;
SourceLocation body_location;
std::optional<FileLocation> file_location;
panda::panda_file::FunctionKind function_kind = panda::panda_file::FunctionKind::NONE;
size_t slots_num = 0;
void SetSlotsNum(size_t num)
{
slots_num = num;
}
size_t GetSlotsNum() const
{
return slots_num;
}
void SetFunctionKind(panda::panda_file::FunctionKind kind)
{
function_kind = kind;
}
panda::panda_file::FunctionKind GetFunctionKind() const
{
return function_kind;
}
void SetInsDebug(const std::vector<debuginfo::Ins> &ins_debug)
{
@ -133,7 +155,7 @@ struct Function {
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays) const;
size_t GetLineNumber(size_t i) const;
@ -170,7 +192,7 @@ struct Function {
bool HasImplementation() const
{
return !metadata->IsForeign() && metadata->HasImplementation();
return !metadata->IsForeign();
}
bool IsParameter(uint32_t reg_number) const

View File

@ -59,7 +59,7 @@ enum InstFlags {
constexpr int INVALID_REG_IDX = -1;
constexpr size_t MAX_NUMBER_OF_SRC_REGS = 5; // TODO(mbolshov): auto-generate
constexpr size_t MAX_NUMBER_OF_SRC_REGS = 4; // TODO(mbolshov): auto-generate
constexpr InstFlags operator|(InstFlags a, InstFlags b)
{
@ -111,7 +111,7 @@ struct Ins {
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
const std::unordered_map<std::string_view, panda::Label> &labels) const;

View File

@ -698,23 +698,13 @@ void Parser::ParseResetFunctionTable()
Error::ErrorType::ERR_BAD_ID_FUNCTION, "", k.second.file_location->bound_left,
k.second.file_location->bound_right, k.second.file_location->whole_line);
SetError();
} else if (k.second.HasImplementation() != k.second.body_presence) {
context_.err = Error("Inconsistency of the definition of the function and its metadata.",
k.second.file_location->line_number, Error::ErrorType::ERR_BAD_DEFINITION_FUNCTION, "",
k.second.file_location->bound_left, k.second.file_location->bound_right,
k.second.file_location->whole_line);
SetError();
} else {
for (auto insn_it = k.second.ins.begin(); insn_it != k.second.ins.end(); ++insn_it) {
bool is_calli = insn_it->opcode == Opcode::CALLI_DYN || insn_it->opcode == Opcode::CALLI_DYN_SHORT ||
insn_it->opcode == Opcode::CALLI_DYN_RANGE;
if (is_calli || !(insn_it->IsCall() || insn_it->IsCallRange())) {
if (!(insn_it->IsCall() || insn_it->IsCallRange())) {
continue;
}
bool is_initobj = insn_it->opcode == Opcode::INITOBJ || insn_it->opcode == Opcode::INITOBJ_SHORT ||
insn_it->opcode == Opcode::INITOBJ_RANGE;
size_t diff = is_initobj ? 0 : 1;
size_t diff = 1;
auto func_name = insn_it->ids[0];
if (!IsSignatureOrMangled(func_name)) {
@ -987,7 +977,7 @@ Expected<Program, Error> Parser::ParseAfterMainLoop(const std::string &file_name
}
for (auto &func : program_.function_table) {
if (func.second.metadata->HasImplementation()) {
if (func.second.HasImplementation()) {
func.second.source_file = file_name;
}
}

View File

@ -466,11 +466,6 @@ bool RecordMetadata::IsRuntimeTypeAnnotation() const
return false;
}
bool FunctionMetadata::HasImplementation() const
{
return !(ACC_ABSTRACT & GetAccessFlags()) && !(ACC_NATIVE & GetAccessFlags());
}
bool FunctionMetadata::IsCtor() const
{
return GetAttribute("ctor");

View File

@ -562,8 +562,6 @@ private:
class FunctionMetadata : public ItemMetadata {
public:
virtual bool HasImplementation() const;
virtual bool IsCtor() const;
virtual bool IsCctor() const;

View File

@ -21,7 +21,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::StringItem *> &strings,
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
const std::unordered_map<std::string_view, panda::Label>& labels) const {
if (!IsValidToEmit()) {
@ -47,6 +47,8 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
% ops = []
% nr = 0
% ni = 0
% property_idx_start = 0
% num_id = 0
% insn.operands.each do |op|
% if op.reg?
% ops << "#{regs}[#{nr}]"
@ -66,50 +68,58 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
% end
% ni += 1
% elsif op.id?
% if insn.properties.include?('method_id')
% ops << 'methods.find(ids[0])->second->GetIndex(method)'
% elsif insn.properties.include?('field_id')
% ops << 'fields.find(ids[0])->second->GetIndex(method)'
% elsif insn.properties.include?('type_id')
% ops << 'classes.find(ids[0])->second->GetIndex(method)'
% elsif insn.properties.include?('string_id')
% ops << 'strings.find(ids[0])->second->GetOffset()'
% elsif insn.properties.include?('literalarray_id')
% ops << 'static_cast<uint32_t>(literalarrays.find(ids[0])->second->GetOffset())'
% else
% raise "Unexpected ID type"
% id_properties = insn.properties.slice(property_idx_start, insn.properties.length - property_idx_start)
% id_properties.each_with_index do |prop, prop_idx|
% if prop == 'method_id'
% ops << "methods.find(ids[#{num_id}])->second->GetIndex(method)"
% property_idx_start += prop_idx + 1
% num_id += 1
% break
% elsif prop == 'string_id'
% ops << "strings.find(ids[#{num_id}])->second->GetIndex(method)"
% property_idx_start += prop_idx + 1
% num_id += 1
% break
% elsif prop == 'literalarray_id'
% ops << "literalarrays.find(ids[#{num_id}])->second->GetIndex(method)"
% property_idx_start += prop_idx + 1
% num_id += 1
% break
% else
% next
% end
% end
% else
% raise "Unexpected operand type"
% end
% end
% if insn.call? && insn.properties.include?('method_id')
% ops << ops.shift
% end
% ops
% end
case Opcode::<%= insn.asm_token %>: {
% if insn.properties.include?('method_id')
if ((ids.size() == 0) || (methods.find(ids[0]) == methods.cend())) {
return false;
}
% elsif insn.properties.include?('field_id')
if ((ids.size() == 0) || (fields.find(ids[0]) == fields.cend())) {
return false;
}
% elsif insn.properties.include?('type_id')
if ((ids.size() == 0) || (classes.find(ids[0]) == classes.cend())) {
return false;
}
% elsif insn.properties.include?('string_id')
if ((ids.size() == 0) || (strings.find(ids[0]) == strings.cend())) {
return false;
}
% elsif insn.jump?
% if insn.jump?
if ((ids.size() == 0) || (labels.find(ids[0]) == labels.cend())) {
return false;
}
% end
% num_id = 0
% insn.properties.each do |prop|
% if prop == 'method_id'
if ((ids.size() == 0) || (methods.find(ids[<%= num_id %>]) == methods.cend())) {
return false;
}
% num_id += 1
% elsif prop == 'string_id'
if ((ids.size() == 0) || (strings.find(ids[<%= num_id %>]) == strings.cend())) {
return false;
}
% num_id += 1
% elsif prop == 'literalarray_id'
if ((ids.size() == 0) || (literalarrays.find(ids[<%= num_id %>]) == literalarrays.cend())) {
return false;
}
% num_id += 1
% end
% end
% regs_num = 0
% imms_num = 0
% insn.operands.each do |op|

View File

@ -311,174 +311,6 @@ end
# Wrap all `insn` declaration in a function to call from template
# (because Panda::instructions is initialized only in templates)
def call_me_from_template
%w[and xor or shl shr].each do |op|
visit(op.capitalize) do
switch(type,
[case_switch(i32_types, if_acc?(r(0)),
[case_true("#{op}2", r(1)),
case_false("#{op}", r(0), r(1))]),
case_(i64_types, "#{op}2.64", r(1))]
)
end
end
visit('AShr') do
switch(type,
[case_switch(i32_types, if_acc?(r(0)),
[case_true("ashr2", r(1)),
case_false("ashr", r(0), r(1))]),
case_(i64_types, 'ashr2.64', r(1))]
)
end
%w[add sub mul div mod].each do |op|
visit(op.capitalize) do
switch(type,
[case_switch(i32_types, if_acc?(r(0)),
[case_true("#{op}2", r(1)),
case_false("#{op}", r(0), r(1))]),
case_(i64_types, "#{op}2.64", r(1)),
case_(f32_types, "f#{op}2", r(1)),
case_(f64_types, "f#{op}2.64", r(1))]
)
end
end
visit('AddI') do
switch(type,
[case_switch(i32_types, if_inci?,
[case_true('inci', r(0), imm),
case_false('addi', imm)])]
)
end
visit('SubI') do
switch(type,
[case_switch(i32_types, if_inci?,
[case_true('inci', r(0), "-(#{imm})"),
case_false('subi', imm)])]
)
end
visit('Not') do
switch(type,
[case_(i32_types, 'not'),
case_(i64_types, 'not.64')]
)
end
visit('Neg') do
switch(type,
[case_(i32_types, 'neg'),
case_(i64_types, 'neg.64'),
case_(f32_types, 'fneg'),
case_(f64_types, 'fneg.64')]
)
end
visit('Cmp') do
switch('inst->GetOperandsType()',
[case_(%w[UINT8 UINT16 UINT32], 'ucmp', r(1)),
case_(%w[INT64], 'cmp.64', r(1)),
case_(%w[UINT64], 'ucmp.64', r(1)),
case_switch(['FLOAT32'], if_fcmpg?,
[case_true('fcmpg', r(1)),
case_false('fcmpl', r(1))]),
case_switch(['FLOAT64'], if_fcmpg?,
[case_true('fcmpg.64', r(1)),
case_false('fcmpl.64', r(1))])]
)
end
visit('ReturnVoid') do
plain('return.void')
end
visit('Throw') do
plain('throw', r(0))
end
visit('NullPtr') do
switch(if_acc?(dst_r),
[case_true('lda.null'),
case_false('mov.null', dst_r)]
)
end
visit('LoadConstArray') do
plain('lda.const', dst_r, literalarray_id)
end
visit('NewArray') do
plain('newarr', dst_r, r(1), type_id)
end
visit('LenArray') do
plain('lenarr', r(0))
end
visit('LoadArray') do
switch(type,
[case_(['INT8'], 'ldarr.8', r(0)),
case_(['UINT8'], 'ldarru.16', r(0)),
case_(['INT16'], 'ldarr.16', r(0)),
case_(['UINT16'], 'ldarru.16', r(0)),
case_(['INT32', 'UINT32'], 'ldarr', r(0)),
case_(['INT64', 'UINT64'], 'ldarr.64', r(0)),
case_(['REFERENCE'], 'ldarr.obj', r(0)),
case_(['FLOAT32'], 'fldarr.32', r(0)),
case_(['FLOAT64'], 'fldarr.64', r(0))]
)
end
visit('StoreArray') do
switch(type,
[case_(['INT8', 'UINT8'], 'starr.8', r(0), r(1)),
case_(['INT16', 'UINT16'], 'starr.16', r(0), r(1)),
case_(['INT32', 'UINT32'], 'starr', r(0), r(1)),
case_(['INT64', 'UINT64'], 'starr.64', r(0), r(1)),
case_(['REFERENCE'], 'starr.obj', r(0), r(1)),
case_(['FLOAT32'], 'fstarr.32', r(0), r(1)),
case_(['FLOAT64'], 'fstarr.64', r(0), r(1))]
)
end
visit('LoadStatic') do
switch(type,
[case_(i32_types, 'ldstatic', field_id),
case_(i64_types, 'ldstatic.64', field_id),
case_(f32_types, 'ldstatic', field_id),
case_(f64_types, 'ldstatic.64', field_id),
case_(['REFERENCE'], 'ldstatic.obj', field_id)]
)
end
visit('StoreStatic') do
switch(type,
[case_(i32_types, 'ststatic', field_id),
case_(i64_types, 'ststatic.64', field_id),
case_(f32_types, 'ststatic', field_id),
case_(f64_types, 'ststatic.64', field_id),
case_(['REFERENCE'], 'ststatic.obj', field_id)]
)
end
visit('CheckCast') do
plain('checkcast', type_id)
end
visit('IsInstance') do
plain('isinstance', type_id)
end
visit('LoadType') do
plain('lda.type', type_id)
end
visit('NewObject') do
plain('newobj', dst_r, type_id)
end
# Empty visitors for IR instructions we want to ignore
# (Add missing IRs on demand)
%w[NullCheck BoundsCheck ZeroCheck NegativeCheck SafePoint
@ -488,12 +320,4 @@ def call_me_from_template
empty
end
end
%w[MulI DivI ModI ShlI ShrI AShrI AndI OrI XorI].each do |op|
visit(op) do
switch(type,
[case_(i32_types, "#{op.downcase}", imm)]
)
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -33,13 +33,8 @@ using compiler::BasicBlock;
using compiler::Inst;
using compiler::Opcode;
void DoLdaObj(compiler::Register reg, std::vector<pandasm::Ins> &result);
void DoLda(compiler::Register reg, std::vector<pandasm::Ins> &result);
void DoLda64(compiler::Register reg, std::vector<pandasm::Ins> &result);
void DoSta(compiler::Register reg, std::vector<pandasm::Ins> &result);
void DoSta64(compiler::Register reg, std::vector<pandasm::Ins> &result);
void DoLdaDyn(compiler::Register reg, std::vector<pandasm::Ins> &result);
void DoStaDyn(compiler::Register reg, std::vector<pandasm::Ins> &result);
class BytecodeGen : public compiler::Optimization, public compiler::GraphVisitor {
public:
@ -119,8 +114,6 @@ public:
static void IfImm64(GraphVisitor *v, Inst *inst_base);
static void VisitIntrinsic(GraphVisitor *v, Inst *inst_base);
static void CallHandler(GraphVisitor *visitor, Inst *inst);
static void VisitStoreObject(GraphVisitor *v, Inst *inst_base);
static void VisitLoadObject(GraphVisitor *v, Inst *inst_base);
static void VisitLoadString(GraphVisitor *v, Inst *inst_base);
static void VisitReturn(GraphVisitor *v, Inst *inst_base);

View File

@ -49,6 +49,14 @@ public:
return std::string(it->second);
}
virtual std::string GetLiteralArrayByOffset(uint32_t offset) const
{
auto it = maps_->literalarrays.find(offset);
ASSERT(it != maps_->strings.cend());
return std::string(it->second);
}
std::optional<std::string> GetLiteralArrayIdByOffset(uint32_t offset) const
{
ASSERT(prog_ != nullptr);

View File

@ -402,7 +402,7 @@ bool OptimizePandaFile(pandasm::Program *prog, const pandasm::AsmEmitter::PandaF
panda_file::ClassDataAccessor cda {*pfile, record_id};
cda.EnumerateMethods([prog, maps, is_dynamic, &result](panda_file::MethodDataAccessor &mda) {
if (!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative()) {
if (!mda.IsExternal()) {
result = OptimizeFunction(prog, maps, mda, is_dynamic) && result;
}
});

View File

@ -26,18 +26,19 @@ static bool IsIntrinsicRange(Inst *inst)
}
#ifdef ENABLE_BYTECODE_OPT
switch (inst->CastToIntrinsic()->GetIntrinsicId()) {
#ifdef ARK_INTRINSIC_SET
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_CALLI_RANGE_DYN:
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_CALLI_THIS_RANGE_DYN:
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE:
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_SUPER_CALL:
#else
case compiler::RuntimeInterface::IntrinsicId::ECMA_CALLIRANGEDYN_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::ECMA_CALLITHISRANGEDYN_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::ECMA_NEWOBJDYNRANGE_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::ECMA_SUPERCALL_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::ECMA_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
#endif
case compiler::RuntimeInterface::IntrinsicId::CALLRANGE_IMM8_IMM8_V8:
case compiler::RuntimeInterface::IntrinsicId::WIDE_CALLRANGE_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::CALLTHISRANGE_IMM8_IMM8_V8:
case compiler::RuntimeInterface::IntrinsicId::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::NEWOBJRANGE_IMM8_IMM8_V8:
case compiler::RuntimeInterface::IntrinsicId::NEWOBJRANGE_IMM16_IMM8_V8:
case compiler::RuntimeInterface::IntrinsicId::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
case compiler::RuntimeInterface::IntrinsicId::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
case compiler::RuntimeInterface::IntrinsicId::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
case compiler::RuntimeInterface::IntrinsicId::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8:
case compiler::RuntimeInterface::IntrinsicId::WIDE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
return true;
default:
return false;
@ -49,10 +50,6 @@ static bool IsIntrinsicRange(Inst *inst)
static bool CanHoldRange(Inst *inst)
{
switch (inst->GetOpcode()) {
case compiler::Opcode::CallStatic:
case compiler::Opcode::CallVirtual:
case compiler::Opcode::InitObject:
return true;
case compiler::Opcode::Intrinsic:
return IsIntrinsicRange(inst);
default:
@ -70,10 +67,6 @@ static compiler::Register CalculateNumNeededRangeTemps(const compiler::Graph *gr
continue;
}
auto nargs = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
if (inst->GetOpcode() == compiler::Opcode::InitObject) {
ASSERT(nargs > 0);
nargs -= 1; // exclude LoadAndInitClass
}
if (ret < nargs) {
if (nargs > MAX_NUM_NON_RANGE_ARGS || IsIntrinsicRange(inst)) {
ret = nargs;
@ -634,6 +627,5 @@ void RegEncoder::VisitLoadString([[maybe_unused]] GraphVisitor *v, [[maybe_unuse
void RegEncoder::VisitReturn([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
void RegEncoder::VisitCatchPhi([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
void RegEncoder::VisitCastValueToAnyType([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
#include "generated/check_width.cpp"
} // namespace panda::bytecodeopt

View File

@ -46,6 +46,11 @@ public:
return panda_file_.ResolveMethodIndex(MethodCast(parent_method), index).GetOffset();
}
uint32_t ResolveOffsetByIndex(MethodPtr parent_method, uint16_t index) const override
{
return panda_file_.ResolveOffsetByIndex(MethodCast(parent_method), index).GetOffset();
}
FieldId ResolveFieldIndex(MethodPtr parent_method, FieldIndex index) const override
{
return panda_file_.ResolveFieldIndex(MethodCast(parent_method), index).GetOffset();
@ -103,7 +108,7 @@ public:
{
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
ASSERT(!mda.IsExternal());
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
return cda.GetNumArgs();
@ -126,7 +131,7 @@ public:
{
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
ASSERT(!mda.IsExternal());
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
return cda.GetNumVregs();
@ -136,7 +141,7 @@ public:
{
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
ASSERT(!mda.IsExternal());
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
return cda.GetInstructions();
@ -146,7 +151,7 @@ public:
{
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
ASSERT(!mda.IsExternal());
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
return cda.GetCodeSize();
@ -156,7 +161,7 @@ public:
{
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
ASSERT(!mda.IsExternal());
auto source_lang = mda.GetSourceLang();
ASSERT(source_lang.has_value());

View File

@ -185,6 +185,7 @@ ohos_shared_library("libarkcompiler") {
":irtoc_builder_cpp",
":irtoc_generate_ir_inline",
":isa_gen_libarkcompiler_inst_builder_gen_cpp",
":libarkcompiler_ecma_intrinsics_enum_inl",
":libarkcompiler_generate_ecma_inl",
":libarkcompiler_intrinsics_gen_inl_can_encode_builtin_inl",
":libarkcompiler_intrinsics_gen_inl_generate_operations_intrinsic_graph_inl",
@ -256,6 +257,7 @@ ohos_static_library("libarkcompiler_frontend_static") {
":irtoc_builder_cpp",
":irtoc_generate_ir_inline",
":isa_gen_libarkcompiler_inst_builder_gen_cpp",
":libarkcompiler_ecma_intrinsics_enum_inl",
":libarkcompiler_generate_ecma_inl",
":libarkcompiler_intrinsics_gen_inl_can_encode_builtin_inl",
":libarkcompiler_intrinsics_gen_inl_generate_operations_intrinsic_graph_inl",
@ -333,7 +335,10 @@ ark_gen("libarkcompiler_intrinsics_gen_inl") {
}
ark_isa_gen("libarkcompiler") {
template_files = [ "generate_ecma.inl.erb" ]
template_files = [
"generate_ecma.inl.erb",
"ecma_intrinsics_enum.inl.erb",
]
sources = "optimizer/templates"
requires = [ "$ark_root//assembler/asm_isapi.rb" ]
destination = "$target_gen_dir/generated"

View File

@ -61,6 +61,8 @@ public:
using MethodIndex = uint16_t;
using FieldIndex = uint16_t;
using TypeIndex = uint16_t;
using StringIndex = uint16_t;
using LiteralArrayIndex = uint16_t;
static const uintptr_t RESOLVE_STRING_AOT_COUNTER_LIMIT = PANDA_32BITS_HEAP_START_ADDRESS;
@ -102,6 +104,12 @@ public:
return 0;
}
virtual uint32_t ResolveOffsetByIndex([[maybe_unused]] MethodPtr parent_method,
[[maybe_unused]] uint16_t index) const
{
return 0;
}
virtual FieldId ResolveFieldIndex([[maybe_unused]] MethodPtr parent_method, [[maybe_unused]] FieldIndex index) const
{
return 0;

View File

@ -1333,7 +1333,7 @@ void InstBuilder::BuildLoadFromPool(const BytecodeInstruction *bc_inst)
} else {
// NOLINTNEXTLINE(readability-magic-numbers)
static_assert(opcode == Opcode::LoadString);
type_id = bc_inst->GetId(0).AsFileId().GetOffset();
type_id = GetRuntime()->ResolveOffsetByIndex(GetGraph()->GetMethod(), bc_inst->GetId(0).AsIndex());
inst = GetGraph()->CreateInstLoadString(DataType::REFERENCE, GetPc(bc_inst->GetAddress()));
}
inst->SetTypeId(type_id);

View File

@ -158,13 +158,8 @@ templates:
UpdateDefinitionAcc(GetDefinition(instruction->GetVReg<<%=inst.get_format%>, 0>()));
% end
fldai: |-
% if inst.mnemonic == "fldai"
auto imm = bit_cast<float>(instruction->GetImm<<%=inst.get_format%>, 0>());
UpdateDefinitionAcc(FindOrCreateFloatConstant(imm));
% else
auto imm = bit_cast<double>(instruction->GetImm<<%=inst.get_format%>, 0>());
UpdateDefinitionAcc(FindOrCreateDoubleConstant(imm));
% end
% if inst.properties.include? "dynamic"
if (GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod()) {
TryFillInstIdTypePair(GetDefinitionAcc()->GetId(), static_cast<int>(GetPc(instruction->GetAddress())));

View File

@ -449,7 +449,7 @@ BasicBlock *IrBuilder::GetBlockToJump(BytecodeInstruction *inst, size_t pc)
}
#ifdef ENABLE_BYTECODE_OPT
if (inst->GetOpcode() == BytecodeInstruction::Opcode::ECMA_RETURNUNDEFINED_PREF_NONE) {
if (inst->GetOpcode() == BytecodeInstruction::Opcode::RETURNUNDEFINED) {
return GetGraph()->GetEndBlock();
}
#endif

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) 2022 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.
*/
// Autogenerated file -- DO NOT EDIT!
% Panda.instructions.select{|x| x.namespace == "ecmascript"}.each do |insn|
<%= insn.opcode.upcase %>,
% end

View File

@ -34,19 +34,15 @@ void panda::bytecodeopt::BytecodeGen::VisitEcma(panda::compiler::GraphVisitor *v
% next if inst.properties.include?("jump")
% opcode = inst.opcode.upcase
% params_arr = inst.operands
#ifdef ARK_INTRINSIC_SET
case compiler::RuntimeInterface::IntrinsicId::<%= intrinsic_name %>: {
#else
% group.each do |i|
% intr_id = i.opcode.upcase
case compiler::RuntimeInterface::IntrinsicId::<%= intr_id %>:
% end
{
#endif // ARK_INTRINSIC_SET
% if inst.acc.include?("in")
auto acc_src = inst->GetSrcReg(inst->GetInputsCount() - 2);
if (acc_src != compiler::ACC_REG_ID) {
DoLdaDyn(acc_src, enc->result_);
DoLda(acc_src, enc->result_);
}
% end
% params_str = ""
@ -61,16 +57,21 @@ void panda::bytecodeopt::BytecodeGen::VisitEcma(panda::compiler::GraphVisitor *v
% vreg_index = vreg_index + 1
% input_index = input_index + 1
% elsif param.id?
% if inst.properties.include?("method_id")
% if param.method_id?
ASSERT(inst->HasImms() && inst->GetImms().size() > <%= imm_index %>); // NOLINTNEXTLINE(readability-container-size-empty)
auto ir_id<%= id_index %> = static_cast<uint32_t>(inst->GetImms()[<%= imm_index %>]);
auto bc_id<%= id_index %> = enc->ir_interface_->GetMethodIdByOffset(ir_id<%= id_index %>);
% params_str = params_str + "bc_id#{id_index}, "
% elsif inst.properties.include?("string_id")
% elsif param.string_id?
ASSERT(inst->HasImms() && inst->GetImms().size() > <%= imm_index %>); // NOLINTNEXTLINE(readability-container-size-empty)
auto ir_id<%= id_index %> = static_cast<uint32_t>(inst->GetImms()[<%= imm_index %>]);
auto bc_id<%= id_index %> = enc->ir_interface_->GetStringIdByOffset(ir_id<%= id_index %>);
% params_str = params_str + "bc_id#{id_index}, "
% elsif param.literalarray_id?
ASSERT(inst->HasImms() && inst->GetImms().size() > <%= imm_index %>); // NOLINTNEXTLINE(readability-container-size-empty)
auto ir_id<%= id_index %> = static_cast<uint32_t>(inst->GetImms()[<%= imm_index %>]);
auto bc_id<%= id_index %> = enc->ir_interface_->GetLiteralArrayByOffset(ir_id<%= id_index %>);
% params_str = params_str + "bc_id#{id_index}, "
% end
% id_index = id_index + 1
% imm_index = imm_index + 1
@ -93,7 +94,7 @@ void panda::bytecodeopt::BytecodeGen::VisitEcma(panda::compiler::GraphVisitor *v
% if inst.acc.include?("out")
auto acc_dst = inst->GetDstReg();
if (acc_dst != compiler::ACC_REG_ID) {
DoStaDyn(inst->GetDstReg(), enc->result_);
DoSta(inst->GetDstReg(), enc->result_);
}
% end
break;

View File

@ -81,8 +81,17 @@ def get_type(type)
'f64[]' => 'DataType::FLOAT64',
'ref[]' => 'DataType::REFERENCE',
'none' => 'DataType::NO_TYPE'}
raise "Unknown type #{type}" if @type_map[type].nil?
@type_map[type]
return 'DataType::ANY' if @type_map[type].nil?
# raise "Unknown type #{type}" if @type_map[type].nil?
return @type_map[type]
end
def get_template_by_inst(inst)
if (inst.namespace == "ecmascript")
return "ecma"
else
return get_template(inst.stripped_mnemonic)
end
end
def get_template(mn)
@ -92,7 +101,7 @@ def get_template(mn)
/^return.*/ => "return",
/^[uf]?cmp/ => "cmp",
/^[ifu][813264]{1,2}to[ifu][813264]{1,2}$/ => "cast",
/^j(eq|ne|lt|gt|le|ge)z?$/ => "if",
/^j(eq|ne|lt|gt|le|ge|stricteq|nstricteq)(z|null|undefined)?$/ => "if",
/^jmp.*/ => "jump",
/(fdiv|fmod|add|sub|mul|and|or|xor|ashr|shr|shl|neg|not)[2i]?$/ => "binop",
/^(div|mod)u?[2i]?$/ => "binop_z",
@ -138,6 +147,8 @@ def get_cc(inst)
return 'ConditionCode::CC_GT' if inst.opcode.start_with? 'jgt'
return 'ConditionCode::CC_LE' if inst.opcode.start_with? 'jle'
return 'ConditionCode::CC_GE' if inst.opcode.start_with? 'jge'
return 'ConditionCode::CC_EQ' if inst.opcode.start_with? 'jstricteq'
return 'ConditionCode::CC_NE' if inst.opcode.start_with? 'jnstricteq'
raise 'get_cc: wrong opcode #{inst.opcode}'
end
@ -159,7 +170,7 @@ namespace panda::compiler {
void InstBuilder::BuildInstruction(const BytecodeInstruction* instruction) {
switch(instruction->GetOpcode()) {
% Panda::instructions.each_with_index do |inst, idx|
% tmpl = inst.mnemonic.include?('polymorphic') ? 'unimplemented' : get_template(inst.stripped_mnemonic)
% tmpl = inst.mnemonic.include?('polymorphic') ? 'unimplemented' : get_template_by_inst(inst)
// NOLINTNEXTLINE(bugprone-branch-clone)
case BytecodeInstruction::Opcode::<%= inst.opcode.upcase %>: {
% if tmpl == 'unimplemented'
@ -292,7 +303,7 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N
switch (bc_inst->GetOpcode()) {
% Panda::instructions.select{|b| b.namespace == "ecmascript"}.each do |inst|
% opc = inst.opcode.upcase
% name = opc.split('_')[1]
% name = opc
% acc_read = inst.acc.include?("in")
% acc_write = inst.acc.include?("out")
% ret_type = acc_write ? "compiler::DataType::ANY" : "compiler::DataType::VOID"
@ -315,9 +326,9 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N
% end
% params_arr = inst.operands
% format = "BytecodeInstruction::Format::" + inst.format.pretty.upcase
% range_should_exclude_last = name == "NEWOBJDYNRANGE" || name == "SUPERCALL" || name == "CREATEOBJECTWITHEXCLUDEDKEYS"
% is_range_call = name == "CALLIRANGEDYN" || name == "CALLITHISRANGEDYN" || range_should_exclude_last
% need_newtarget = name == "SUPERCALLSPREAD" || name == "SUPERCALL"
% range_should_exclude_last = (name.include? "NEWOBJRANGE") || (name.include? "SUPERCALLTHISRANGE") || (name.include? "CREATEOBJECTWITHEXCLUDEDKEYS") || (name.include? "SUPERCALLARROWRANGE") || (name.include? "CALLRANGE")
% is_range_call = (name.include? "CALLTHISRANGE") || range_should_exclude_last
% need_newtarget = (name.include? "SUPERCALLSPREAD") || (name.include? "SUPERCALL")
% num_vregs = params_arr.select{|b| b.reg?}.length
% num_imms = params_arr.select{|b| b.imm?}.length
% num_ids = params_arr.select{|b| b.id?}.length
@ -329,8 +340,9 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N
% if need_newtarget
% num_inputs = num_inputs + 1
% end
% has_ic_slot = inst.properties.include?('ic_slot') || inst.properties.include?('jit_ic_slot')
% if is_range_call
size_t args_count = <%= num_inputs %>U + static_cast<size_t>(bc_inst->GetImm<<%= format %>, 0>());
size_t args_count = <%= num_inputs %>U + static_cast<size_t>(bc_inst->GetImm<<%= format %>, <%= has_ic_slot ? 1 : 0 %>>());
% else
size_t args_count {<%= num_inputs %>U};
% end
@ -355,7 +367,6 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N
% imm_index = 0
% vreg_index = 0
% id16_index = 0
% id32_index = 0
auto inst_save_state = CreateSaveState(Opcode::SaveState, GetPc(bc_inst->GetAddress()));
AddInstruction(inst_save_state);
% params_arr.each do |param|
@ -376,17 +387,19 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N
% vreg_index = vreg_index + 1
% elsif param.id?
% if inst.properties.include?("method_id")
auto m_idx<%= id16_index %> = bc_inst->template GetId<<%= format %>>().AsRawValue();
if (GetGraph()->IsBytecodeOptimizer()) {
m_idx<%= id16_index %> = GetRuntime()->ResolveMethodIndex(GetGraph()->GetMethod(), m_idx<%= id16_index %>);
}
auto m_idx<%= id16_index %> = bc_inst->template GetId<<%= format %>, <%= id16_index %>>().AsRawValue();
m_idx<%= id16_index %> = GetRuntime()->ResolveOffsetByIndex(GetGraph()->GetMethod(), m_idx<%= id16_index %>);
inst->AddImm(GetGraph()->GetAllocator(), m_idx<%= id16_index %>);
% id16_index = id16_index + 1
% elsif inst.properties.include?("string_id")
auto string_id<%= id32_index %> = bc_inst->template GetId<<%= format %>>().AsFileId().GetOffset();
inst->AddImm(GetGraph()->GetAllocator(), string_id<%= id32_index %>);
% id32_index = id32_index + 1
auto string_id<%= id16_index %> = bc_inst->template GetId<<%= format %>, <%= id16_index %>>().AsRawValue();
string_id<%= id16_index %> = GetRuntime()->ResolveOffsetByIndex(GetGraph()->GetMethod(), string_id<%= id16_index %>);
inst->AddImm(GetGraph()->GetAllocator(), string_id<%= id16_index %>);
% elsif inst.properties.include?("literalarray_id")
auto literalarray_id<%= id16_index %> = bc_inst->template GetId<<%= format %>, <%= id16_index %>>().AsRawValue();
literalarray_id<%= id16_index %> = GetRuntime()->ResolveOffsetByIndex(GetGraph()->GetMethod(), literalarray_id<%= id16_index %>);
inst->AddImm(GetGraph()->GetAllocator(), literalarray_id<%= id16_index %>);
% end
% id16_index = id16_index + 1
% end
% end
% if need_newtarget
@ -401,8 +414,9 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N
}
% end
% if is_range_call
% range_reg_idx = name == "CREATEOBJECTWITHEXCLUDEDKEYS" ? 1 : 0
% num_actual_vregs = range_should_exclude_last ? "imm0" : "imm0 + 1"
% range_reg_idx = (name.include? "CREATEOBJECTWITHEXCLUDEDKEYS") ? 1 : 0
% imm_arg_num = has_ic_slot ? 'imm1' : 'imm0'
% num_actual_vregs = range_should_exclude_last ? imm_arg_num : imm_arg_num + " + 1"
size_t start_reg = bc_inst->GetVReg<<%= format %>, <%= range_reg_idx %>>();
for (uint32_t i = 1; i < <%= num_actual_vregs %>; ++i) {
auto input = GetDefinition(start_reg + i);

View File

@ -21,6 +21,7 @@
% end
enum class IntrinsicId {
#include "ecma_intrinsics_enum.inl"
% Compiler::intrinsics.select{ |x| !x.is_irtoc? }.each do |intrinsic|
<%= intrinsic.entrypoint_name %>,
% end
@ -34,179 +35,4 @@ enum class IntrinsicId {
% Compiler::intrinsics.select(&:is_irtoc?).each do |intrinsic|
<%= intrinsic.entrypoint_name %>,
% end
ECMA_LDNAN_PREF_NONE,
ECMA_LDINFINITY_PREF_NONE,
ECMA_LDGLOBALTHIS_PREF_NONE,
ECMA_LDUNDEFINED_PREF_NONE,
ECMA_LDNULL_PREF_NONE,
ECMA_LDSYMBOL_PREF_NONE,
ECMA_LDGLOBAL_PREF_NONE,
ECMA_LDTRUE_PREF_NONE,
ECMA_LDFALSE_PREF_NONE,
ECMA_THROWDYN_PREF_NONE,
ECMA_RETHROWDYN_PREF_NONE,
ECMA_TYPEOFDYN_PREF_NONE,
ECMA_LDLEXENVDYN_PREF_NONE,
ECMA_POPLEXENVDYN_PREF_NONE,
ECMA_GETUNMAPPEDARGS_PREF_NONE,
ECMA_GETPROPITERATOR_PREF_NONE,
ECMA_ASYNCFUNCTIONENTER_PREF_NONE,
ECMA_LDHOLE_PREF_NONE,
ECMA_RETURNUNDEFINED_PREF_NONE,
ECMA_CREATEEMPTYOBJECT_PREF_NONE,
ECMA_CREATEEMPTYARRAY_PREF_NONE,
ECMA_GETITERATOR_PREF_V8_V8,
ECMA_GETITERATOR_PREF_NONE,
ECMA_GETASYNCITERATOR_PREF_NONE,
ECMA_THROWTHROWNOTEXISTS_PREF_NONE,
ECMA_THROWPATTERNNONCOERCIBLE_PREF_NONE,
ECMA_LDHOMEOBJECT_PREF_NONE,
ECMA_THROWDELETESUPERPROPERTY_PREF_NONE,
ECMA_DEBUGGER_PREF_NONE,
ECMA_ADD2DYN_PREF_V8,
ECMA_SUB2DYN_PREF_V8,
ECMA_MUL2DYN_PREF_V8,
ECMA_DIV2DYN_PREF_V8,
ECMA_MOD2DYN_PREF_V8,
ECMA_EQDYN_PREF_V8,
ECMA_NOTEQDYN_PREF_V8,
ECMA_LESSDYN_PREF_V8,
ECMA_LESSEQDYN_PREF_V8,
ECMA_GREATERDYN_PREF_V8,
ECMA_GREATEREQDYN_PREF_V8,
ECMA_SHL2DYN_PREF_V8,
ECMA_SHR2DYN_PREF_V8,
ECMA_ASHR2DYN_PREF_V8,
ECMA_AND2DYN_PREF_V8,
ECMA_OR2DYN_PREF_V8,
ECMA_XOR2DYN_PREF_V8,
ECMA_TONUMBER_PREF_V8,
ECMA_TONUMERIC_PREF_V8,
ECMA_NEGDYN_PREF_V8,
ECMA_NOTDYN_PREF_V8,
ECMA_INCDYN_PREF_V8,
ECMA_DECDYN_PREF_V8,
ECMA_EXPDYN_PREF_V8,
ECMA_ISINDYN_PREF_V8,
ECMA_INSTANCEOFDYN_PREF_V8,
ECMA_STRICTNOTEQDYN_PREF_V8,
ECMA_STRICTEQDYN_PREF_V8,
ECMA_RESUMEGENERATOR_PREF_V8,
ECMA_GETRESUMEMODE_PREF_V8,
ECMA_CREATEGENERATOROBJ_PREF_V8,
ECMA_SETGENERATORSTATE_PREF_V8_IMM8,
ECMA_CREATEASYNCGENERATOROBJ_PREF_V8,
ECMA_THROWCONSTASSIGNMENT_PREF_V8,
ECMA_GETMETHOD_PREF_ID32_V8,
ECMA_GETTEMPLATEOBJECT_PREF_V8,
ECMA_GETNEXTPROPNAME_PREF_V8,
ECMA_CALLARG0DYN_PREF_V8,
ECMA_THROWIFNOTOBJECT_PREF_V8,
ECMA_CLOSEITERATOR_PREF_V8,
ECMA_COPYMODULE_PREF_V8,
ECMA_SUPERCALLSPREAD_PREF_V8,
ECMA_DELOBJPROP_PREF_V8_V8,
ECMA_NEWOBJSPREADDYN_PREF_V8_V8,
ECMA_CREATEITERRESULTOBJ_PREF_V8_V8,
ECMA_SUSPENDGENERATOR_PREF_V8_V8,
ECMA_SUSPENDASYNCGENERATOR_PREF_V8,
ECMA_ASYNCFUNCTIONAWAITUNCAUGHT_PREF_V8_V8,
ECMA_THROWUNDEFINEDIFHOLE_PREF_V8_V8,
ECMA_CALLARG1DYN_PREF_V8_V8,
ECMA_COPYDATAPROPERTIES_PREF_V8_V8,
ECMA_STARRAYSPREAD_PREF_V8_V8,
ECMA_SETOBJECTWITHPROTO_PREF_V8_V8,
ECMA_LDOBJBYVALUE_PREF_V8_V8,
ECMA_STOBJBYVALUE_PREF_V8_V8,
ECMA_STOWNBYVALUE_PREF_V8_V8,
ECMA_LDSUPERBYVALUE_PREF_V8_V8,
ECMA_STSUPERBYVALUE_PREF_V8_V8,
ECMA_LDOBJBYINDEX_PREF_IMM8_V8,
ECMA_LDOBJBYINDEX_PREF_IMM16_V8,
ECMA_LDOBJBYINDEX_PREF_V8_IMM32,
ECMA_STOBJBYINDEX_PREF_IMM8_V8,
ECMA_STOBJBYINDEX_PREF_IMM16_V8,
ECMA_STOBJBYINDEX_PREF_V8_IMM32,
ECMA_STOWNBYINDEX_PREF_IMM8_V8,
ECMA_STOWNBYINDEX_PREF_IMM16_V8,
ECMA_STOWNBYINDEX_PREF_V8_IMM32,
ECMA_CALLSPREADDYN_PREF_V8_V8_V8,
ECMA_ASYNCFUNCTIONRESOLVE_PREF_V8_V8_V8,
ECMA_ASYNCFUNCTIONREJECT_PREF_V8_V8_V8,
ECMA_ASYNCGENERATORRESOLVE_PREF_V8,
ECMA_ASYNCGENERATORREJECT_PREF_V8,
ECMA_CALLARGS2DYN_PREF_V8_V8_V8,
ECMA_CALLARGS3DYN_PREF_V8_V8_V8_V8,
ECMA_DEFINEGETTERSETTERBYVALUE_PREF_V8_V8_V8_V8,
ECMA_NEWOBJDYNRANGE_PREF_IMM16_V8,
ECMA_CALLIRANGEDYN_PREF_IMM16_V8,
ECMA_CALLITHISRANGEDYN_PREF_IMM16_V8,
ECMA_SUPERCALL_PREF_IMM16_V8,
ECMA_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8,
ECMA_DEFINEFUNCDYN_PREF_ID16_IMM16_V8,
ECMA_DEFINENCFUNCDYN_PREF_ID16_IMM16_V8,
ECMA_DEFINEGENERATORFUNC_PREF_ID16_IMM16_V8,
ECMA_DEFINEASYNCFUNC_PREF_ID16_IMM16_V8,
ECMA_DEFINEASYNCGENERATORFUNC_PREF_ID16_V8,
ECMA_DEFINEMETHOD_PREF_ID16_IMM16_V8,
ECMA_NEWLEXENVDYN_PREF_IMM16,
ECMA_COPYLEXENVDYN_PREF_NONE,
ECMA_COPYRESTARGS_PREF_IMM16,
ECMA_CREATEARRAYWITHBUFFER_PREF_IMM16,
ECMA_CREATEOBJECTHAVINGMETHOD_PREF_IMM16,
ECMA_THROWIFSUPERNOTCORRECTCALL_PREF_IMM16,
ECMA_CREATEOBJECTWITHBUFFER_PREF_IMM16,
ECMA_LDLEXVARDYN_PREF_IMM4_IMM4,
ECMA_LDLEXVARDYN_PREF_IMM8_IMM8,
ECMA_LDLEXVARDYN_PREF_IMM16_IMM16,
ECMA_STLEXVARDYN_PREF_IMM4_IMM4_V8,
ECMA_STLEXVARDYN_PREF_IMM8_IMM8_V8,
ECMA_STLEXVARDYN_PREF_IMM16_IMM16_V8,
ECMA_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8,
ECMA_IMPORTMODULE_PREF_ID32,
ECMA_STMODULEVAR_PREF_ID32,
ECMA_TRYLDGLOBALBYNAME_PREF_ID32,
ECMA_TRYSTGLOBALBYNAME_PREF_ID32,
ECMA_LDGLOBALVAR_PREF_ID32,
ECMA_STGLOBALVAR_PREF_ID32,
ECMA_STGLOBALLET_PREF_ID32,
ECMA_LDOBJBYNAME_PREF_ID32_V8,
ECMA_STOBJBYNAME_PREF_ID32_V8,
ECMA_STOWNBYNAME_PREF_ID32_V8,
ECMA_LDSUPERBYNAME_PREF_ID32_V8,
ECMA_STSUPERBYNAME_PREF_ID32_V8,
ECMA_LDMODVARBYNAME_PREF_ID32_V8,
ECMA_TOBOOLEAN_PREF_NONE,
ECMA_NEGATE_PREF_NONE,
ECMA_ISTRUE_PREF_NONE,
ECMA_ISFALSE_PREF_NONE,
ECMA_ISUNDEFINED_PREF_NONE,
ECMA_ISCOERCIBLE_PREF_NONE,
ECMA_JFALSE_PREF_IMM8,
ECMA_JFALSE_PREF_IMM16,
ECMA_JFALSE_PREF_IMM32,
ECMA_JTRUE_PREF_IMM8,
ECMA_JTRUE_PREF_IMM16,
ECMA_JTRUE_PREF_IMM32,
ECMA_RETURN_DYN_PREF_NONE,
ECMA_ITERNEXT_PREF_V8,
ECMA_GETMODULENAMESPACE_PREF_ID32,
ECMA_LDMODULEVAR_PREF_ID32_IMM8,
ECMA_STCONSTTOGLOBALRECORD_PREF_ID32,
ECMA_STLETTOGLOBALRECORD_PREF_ID32,
ECMA_GETITERATORNEXT_PREF_V8_V8,
ECMA_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8,
ECMA_STCLASSTOGLOBALRECORD_PREF_ID32,
ECMA_STOWNBYVALUEWITHNAMESET_PREF_V8_V8,
ECMA_LDFUNCTION_PREF_NONE,
ECMA_NEWLEXENVWITHNAMEDYN_PREF_IMM16_IMM16,
ECMA_LDBIGINT_PREF_ID32,
ECMA_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8,
ECMA_ASYNCGENERATORRESOLVE_PREF_V8_V8_V8,
ECMA_DEFINEASYNCGENERATORFUNC_PREF_ID16_IMM16_V8,
ECMA_DYNAMICIMPORT_PREF_V8,
ECMA_LDPATCHVAR_PREF_IMM16,
ECMA_STPATCHVAR_PREF_IMM16,
ECMA_ASYNCGENERATORREJECT_PREF_V8_V8,
};

View File

@ -180,10 +180,6 @@ void Disassembler::GetMethod(pandasm::Function *method, const panda_file::File::
GetParams(method, method_accessor.GetProtoId());
GetMetaData(method, method_id);
if (!method->HasImplementation()) {
return;
}
if (method_accessor.GetCodeId().has_value()) {
const IdList id_list = GetInstructions(method, method_id, method_accessor.GetCodeId().value());
@ -200,7 +196,7 @@ void Disassembler::GetMethod(pandasm::Function *method, const panda_file::File::
template <typename T>
void Disassembler::FillLiteralArrayData(pandasm::LiteralArray *lit_array, const panda_file::LiteralTag &tag,
const panda_file::LiteralDataAccessor::LiteralValue &value)
const panda_file::LiteralDataAccessor::LiteralValue &value) const
{
panda_file::File::EntityId id(std::get<uint32_t>(value));
auto sp = file_->GetSpanFromId(id);
@ -268,15 +264,12 @@ void Disassembler::FillLiteralData(pandasm::LiteralArray *lit_array,
lit_array->literals_.push_back(lit);
}
void Disassembler::GetLiteralArray(pandasm::LiteralArray *lit_array, const size_t index)
void Disassembler::GetLiteralArrayByOffset(pandasm::LiteralArray *lit_array, panda_file::File::EntityId offset) const
{
LOG(DEBUG, DISASSEMBLER) << "\n[getting literal array]\nindex: " << index;
panda_file::LiteralDataAccessor lit_array_accessor(*file_, file_->GetLiteralArraysId());
lit_array_accessor.EnumerateLiteralVals(
index, [this, lit_array](const panda_file::LiteralDataAccessor::LiteralValue &value,
const panda_file::LiteralTag &tag) {
offset, [this, lit_array](const panda_file::LiteralDataAccessor::LiteralValue &value,
const panda_file::LiteralTag &tag) {
switch (tag) {
case panda_file::LiteralTag::ARRAY_U1: {
FillLiteralArrayData<bool>(lit_array, tag, value);
@ -322,6 +315,14 @@ void Disassembler::GetLiteralArray(pandasm::LiteralArray *lit_array, const size_
});
}
void Disassembler::GetLiteralArray(pandasm::LiteralArray *lit_array, const size_t index) const
{
LOG(DEBUG, DISASSEMBLER) << "\n[getting literal array]\nindex: " << index;
panda_file::LiteralDataAccessor lit_array_accessor(*file_, file_->GetLiteralArraysId());
GetLiteralArrayByOffset(lit_array, lit_array_accessor.GetLiteralArrayId(index));
}
void Disassembler::GetLiteralArrays()
{
const auto lit_arrays_id = file_->GetLiteralArraysId();
@ -652,14 +653,6 @@ void Disassembler::GetMetaData(pandasm::Function *method, const panda_file::File
method->metadata->SetAttribute("external");
}
if (method_accessor.IsNative()) {
method->metadata->SetAttribute("native");
}
if (method_accessor.IsAbstract()) {
method->metadata->SetAttribute("noimpl");
}
std::string ctor_name = panda::panda_file::GetCtorName(file_language_);
std::string cctor_name = panda::panda_file::GetCctorName(file_language_);
@ -1019,27 +1012,33 @@ static bool IsArray(const panda_file::LiteralTag &tag)
}
}
void Disassembler::Serialize(size_t index, const pandasm::LiteralArray &lit_array, std::ostream &os) const
std::string Disassembler::SerializeLiteralArray(const pandasm::LiteralArray &lit_array) const
{
std::stringstream ret;
if (lit_array.literals_.empty()) {
return;
return ret.str();
}
const auto &tag = lit_array.literals_[0].tag_;
if (IsArray(tag)) {
os << ".array array_";
ret << "{array: ";
} else {
os << ".literal literal_";
ret << "{literal: ";
}
os << index << " " << LiteralTagToString(tag);
ret << LiteralTagToString(tag);
if (IsArray(tag)) {
os << " " << lit_array.literals_.size();
ret << " " << lit_array.literals_.size();
}
os << " { ";
ret << " [ ";
SerializeValues(lit_array, ret);
ret << "]}";
return ret.str();
}
SerializeValues(lit_array, os);
os << "}\n";
void Disassembler::Serialize(size_t index, const pandasm::LiteralArray &lit_array, std::ostream &os) const
{
os << "literal_index " << index << " ";
os << SerializeLiteralArray(lit_array);
os << "\n";
}
std::string Disassembler::LiteralTagToString(const panda_file::LiteralTag &tag) const
@ -1082,14 +1081,15 @@ std::string Disassembler::LiteralTagToString(const panda_file::LiteralTag &tag)
return "method_affiliate";
case panda_file::LiteralTag::NULLVALUE:
return "null_value";
case panda_file::LiteralTag::TAGVALUE:
return "tagvalue";
default:
UNREACHABLE();
}
UNREACHABLE();
}
void Disassembler::SerializeValues(const pandasm::LiteralArray &lit_array, std::ostream &os) const
template <typename T>
void Disassembler::SerializeValues(const pandasm::LiteralArray &lit_array, T &os) const
{
switch (lit_array.literals_[0].tag_) {
case panda_file::LiteralTag::ARRAY_U1: {
@ -1300,11 +1300,6 @@ void Disassembler::Serialize(const pandasm::Function &method, std::ostream &os,
Serialize(*method.metadata, {}, os);
}
if (!method.HasImplementation()) {
os << "\n\n";
return;
}
auto method_info_it = prog_info_.methods_info.find(signature);
bool print_method_info = print_information && method_info_it != prog_info_.methods_info.end();
if (print_method_info) {
@ -1489,43 +1484,18 @@ pandasm::Opcode Disassembler::BytecodeOpcodeToPandasmOpcode(uint8_t o) const
std::string Disassembler::IDToString(BytecodeInstruction bc_ins, panda_file::File::EntityId method_id) const
{
std::stringstream name;
const auto offset = file_->ResolveOffsetByIndex(method_id, bc_ins.GetId().AsIndex());
if (bc_ins.HasFlag(BytecodeInstruction::Flags::TYPE_ID)) {
auto idx = bc_ins.GetId().AsIndex();
auto id = file_->ResolveClassIndex(method_id, idx);
auto type = pandasm::Type::FromDescriptor(StringDataToString(file_->GetStringData(id)));
name.str("");
name << type.GetPandasmName();
} else if (bc_ins.HasFlag(BytecodeInstruction::Flags::METHOD_ID)) {
auto idx = bc_ins.GetId().AsIndex();
auto id = file_->ResolveMethodIndex(method_id, idx);
name << GetMethodSignature(id);
if (bc_ins.HasFlag(BytecodeInstruction::Flags::METHOD_ID)) {
name << GetMethodSignature(offset);
} else if (bc_ins.HasFlag(BytecodeInstruction::Flags::STRING_ID)) {
name << '\"';
if (skip_strings_ || quiet_) {
name << std::hex << "0x" << bc_ins.GetId().AsFileId();
} else {
name << StringDataToString(file_->GetStringData(bc_ins.GetId().AsFileId()));
}
name << StringDataToString(file_->GetStringData(offset));
name << '\"';
} else if (bc_ins.HasFlag(BytecodeInstruction::Flags::FIELD_ID)) {
auto idx = bc_ins.GetId().AsIndex();
auto id = file_->ResolveFieldIndex(method_id, idx);
panda_file::FieldDataAccessor field_accessor(*file_, id);
name << GetFullRecordName(field_accessor.GetClassId());
name << '.';
name << StringDataToString(file_->GetStringData(field_accessor.GetNameId()));
} else if (bc_ins.HasFlag(BytecodeInstruction::Flags::LITERALARRAY_ID)) {
panda_file::LiteralDataAccessor lit_array_accessor(*file_, file_->GetLiteralArraysId());
auto idx = bc_ins.GetId().AsFileId();
auto index = lit_array_accessor.ResolveLiteralArrayIndex(idx);
name << "array_" << index;
pandasm::LiteralArray lit_array;
GetLiteralArrayByOffset(&lit_array, panda_file::File::EntityId(offset));
name << SerializeLiteralArray(lit_array);
}
return name.str();

View File

@ -65,10 +65,10 @@ public:
void GetRecord(pandasm::Record *record, const panda_file::File::EntityId &record_id);
void AddMethodToTables(const panda_file::File::EntityId &method_id);
void GetMethod(pandasm::Function *method, const panda_file::File::EntityId &method_id);
void GetLiteralArray(pandasm::LiteralArray *lit_array, const size_t index);
void GetLiteralArray(pandasm::LiteralArray *lit_array, const size_t index) const;
template <typename T>
void FillLiteralArrayData(pandasm::LiteralArray *lit_array, const panda_file::LiteralTag &tag,
const panda_file::LiteralDataAccessor::LiteralValue &value);
const panda_file::LiteralDataAccessor::LiteralValue &value) const;
const ProgInfo &GetProgInfo() const
{
@ -116,7 +116,8 @@ private:
void GetInsInfo(const panda_file::File::EntityId &code_id, MethodInfo *method_info) const;
void Serialize(size_t index, const pandasm::LiteralArray &lit_array, std::ostream &os) const;
void SerializeValues(const pandasm::LiteralArray &lit_array, std::ostream &os) const;
template <typename T>
void SerializeValues(const pandasm::LiteralArray &lit_array, T &os) const;
std::string LiteralTagToString(const panda_file::LiteralTag &tag) const;
void Serialize(const pandasm::Record &record, std::ostream &os, bool print_information = false) const;
void SerializeFields(const pandasm::Record &record, std::ostream &os, bool print_information) const;
@ -152,6 +153,10 @@ private:
panda::panda_file::SourceLang GetRecordLanguage(panda_file::File::EntityId class_id) const;
std::string SerializeLiteralArray(const pandasm::LiteralArray &lit_array) const;
void GetLiteralArrayByOffset(pandasm::LiteralArray *lit_array, panda_file::File::EntityId offset) const;
std::unique_ptr<const panda_file::File> file_;
pandasm::Program prog_;

View File

@ -71,22 +71,11 @@ pandasm::Ins Disassembler::BytecodeInstructionToPandasmInstruction(BytecodeInstr
int overhead;
const bool is_initobj = ins.opcode == pandasm::Opcode::INITOBJ_SHORT ||
ins.opcode == pandasm::Opcode::INITOBJ_RANGE || ins.opcode == pandasm::Opcode::INITOBJ;
const bool is_acc = ins.opcode == pandasm::Opcode::CALL_ACC_SHORT || ins.opcode == pandasm::Opcode::CALL_ACC ||
ins.opcode == pandasm::Opcode::CALL_VIRT_ACC_SHORT ||
ins.opcode == pandasm::Opcode::CALL_VIRT_ACC;
if (mda.IsStatic() || is_initobj) {
if (mda.IsStatic()) {
overhead = ins.regs.size() - pda.GetNumArgs();
} else {
overhead = ins.regs.size() - pda.GetNumArgs() - 1;
}
// call.acc recieves fixed amount of registers
if (is_acc) {
return ins;
}
if (overhead < 0 || overhead > static_cast<int>(ins.regs.size())) {
LOG(ERROR, DISASSEMBLER)
<< "> error encountered in code of " << std::dec << method_id.GetOffset() << " ("

View File

@ -0,0 +1,39 @@
# 2022-08-18-isa-changelog
This document describes change log with the following modifications:
* ISA refactoring
* Function Kind and Header index
* MethodId, StringId and LiteralArrayId
## ISA refactoring
The bytecode size and runtime performance have been suffering for a long time as the all the
ecmascript specific bytecode are prefixed and their opcode were encoded with two bytes.
1. We delete all original java specific opcodes and delete java specific opcode prefix.
2. We remove the prefix of ecmascript specific opcodes, such that most of the bytecode opcode can be encoded with one byte.
3. We add prefix "deprecated" and keep the many old isa as "deprecated"-prefixed opcodes (for compatibility). These prefixed opcode will be deleted once we do not need to concern compatibility.
4. We add prefix "throw" and make all throwing opcodes be prefixed by "throw".
5. We add prefix "wide" to support opcodes which need larger immediate number.
6. We adjust the format of some opcodes (about immediate number and accumulator), so that the bytecode can be more compact.
7. We change the semantics of some opcodes.
8. We add 8-bit or 16-bit imm as inline cache slot for some specific opcodes.
## Function Kind and Header index
As we merge some "define-function" opcodes as one opcode, in function we add one field which records the function kind,
such that runtime can distinguish the "define-function" operations of different kinds.
We also add header index in function such that runtime can access IndexHeader more efficiently.
We reuse the field 32-bit field `access_flags_` to encode Function Kind and Header index.
This will not introduce compatibility issue because the later 24-bit of `access_flags_` is unused indeed.
Now the layout is:
|<- 16-bit header index ->|<- 8-bit function kind ->|<- 8-bit original access flag ->|
## MethodId, StringId and LiteralArrayId
To adapt runtime design, we put string and literal array into the index header of methods,
such that the instructions can get consective indexes for methodId, stringId and literalarrayId.
This will help runtime to build constant pool more efficiently.
As the method number in a class is not limited, we release the constraint that all methodId,
stringId and literalarrayId in a class should be put in a same index header.
Instead, we only ask that all methodId, stringId and literalarrayId in a method should be put in one index header.
As we use 16-bit to encode methodId, stringId and literalarrayId, the number of these Ids in one method cannot exceed 65536 for now.
This released constraint suits for most of application scenarios.

View File

@ -15,8 +15,8 @@ import("//arkcompiler/runtime_core/ark_config.gni")
isa_paths = [
rebase_path("$ark_root/isa/isa.yaml", root_build_dir),
rebase_path("$ark_root/../ets_runtime/ecmascript/ecma_isa.yaml",
root_build_dir),
# rebase_path("$ark_root/../ets_runtime/ecmascript/ecma_isa.yaml",
# root_build_dir),
]
foreach(plugin, enabled_plugins) {
@ -44,10 +44,7 @@ foreach(plugin, enabled_plugins) {
action("isa_combine") {
script = "$ark_root/isa/combine.rb"
input_args = string_join(",", isa_paths)
inputs = [
"$ark_root/isa/isa.yaml",
"$ark_root/../ets_runtime/ecmascript/ecma_isa.yaml",
]
inputs = [ "$ark_root/isa/isa.yaml" ]
outputs = [ "$root_gen_dir/isa/isa.yaml" ]
args = [
"-d",

File diff suppressed because it is too large Load Diff

View File

@ -157,10 +157,25 @@ class Instruction < SimpleDelegator
operands = operands.split(', ')
ops_encoding = format.encoding
count = 0
operands.map do |operand|
name, srcdst, type = Util.parse_operand_signature(operand)
if name.end_with?('id')
count += 1
end
end
id_count = 1
operands.map do |operand|
name, srcdst, type = Util.parse_operand_signature(operand)
key = name
key = 'id' if name.end_with?('id')
if name.end_with?('id')
key = 'id'
if count > 1
key += id_count.to_s
id_count = id_count + 1
end
end
Operand.new(name, srcdst, type, ops_encoding[key].width, ops_encoding[key].offset)
end
end
@ -190,6 +205,20 @@ class Instruction < SimpleDelegator
props + add_props
end
cached def real_properties
filter = []
properties.each do |p|
if p != 'acc_write' && p != 'acc_read' && p != 'acc_none'
filter << p
end
end
filter << 'acc_write' if acc_write?
filter << 'acc_read' if acc_read?
filter << 'acc_none' if acc_none?
return filter
end
def type(index)
acc_and_operands.select(&:src?)[index].type || 'none'
end
@ -263,7 +292,7 @@ class Format
end
cached def pretty
name.sub('op_', '').gsub(/imm[0-9]?/, 'imm').gsub(/v[0-9]?/, 'v').gsub(/_([0-9]+)/, '\1')
name.sub('op_', '').gsub(/id[0-9]?/, 'id').gsub(/imm[0-9]?/, 'imm').gsub(/v[0-9]?/, 'v').gsub(/_([0-9]+)/, '\1')
end
def prefixed?
@ -335,6 +364,18 @@ class Operand
%i[method_id type_id field_id string_id literalarray_id].include?(@name)
end
def method_id?
%i[method_id].include?(@name)
end
def string_id?
%i[string_id].include?(@name)
end
def literalarray_id?
%i[literalarray_id].include?(@name)
end
def dst?
%i[inout out].include?(@srcdst)
end

View File

@ -391,7 +391,14 @@ public:
static constexpr bool HasImm(Format format, size_t idx);
static constexpr Format GetFormat(Opcode opcode);
static constexpr size_t Size(Format format);
static constexpr size_t Size(Opcode opcode)
{
return Size(GetFormat(opcode));
}
};
template <const BytecodeInstMode Mode>

View File

@ -301,6 +301,12 @@ public:
return index[idx];
}
EntityId ResolveOffsetByIndex(EntityId id, Index idx) const
{
auto index = GetMethodIndex(id);
return index[idx];
}
EntityId ResolveFieldIndex(EntityId id, Index idx) const
{
auto index = GetFieldIndex(id);

View File

@ -524,34 +524,36 @@ void ItemContainer::ReorderItems(panda::panda_file::pgo::ProfileOptimizer *profi
profile_opt->ProfileGuidedRelayout(items_);
}
void ItemContainer::ProcessIndexDependecies(BaseItem *item)
void ItemContainer::AddIndexDependecies(BaseItem *item)
{
auto deps = item->GetIndexDependencies();
item->Visit([&deps](BaseItem *param_item) {
const auto &item_deps = param_item->GetIndexDependencies();
deps.insert(deps.end(), item_deps.cbegin(), item_deps.cend());
return true;
});
if (index_section_item_.IsEmpty()) {
index_section_item_.AddHeader();
index_section_item_.GetCurrentHeader()->SetStart(item);
}
if (index_section_item_.GetCurrentHeader()->Add(deps)) {
return;
const auto &item_deps = item->GetIndexDependencies();
if (!index_section_item_.GetCurrentHeader()->Add(item_deps)) {
index_section_item_.GetCurrentHeader()->SetEnd(item);
index_section_item_.AddHeader();
index_section_item_.GetCurrentHeader()->SetStart(item);
if (!index_section_item_.GetCurrentHeader()->Add(item_deps)) {
LOG(FATAL, PANDAFILE) << "Cannot add " << item_deps.size() << " items to index";
UNREACHABLE();
}
}
index_section_item_.GetCurrentHeader()->SetEnd(item);
index_section_item_.AddHeader();
index_section_item_.GetCurrentHeader()->SetStart(item);
if (!index_section_item_.GetCurrentHeader()->Add(deps)) {
LOG(FATAL, PANDAFILE) << "Cannot add " << deps.size() << " items to index";
if (item->GetName() == "method_item") {
static_cast<BaseMethodItem *>(item)->SetHeaderIndex(index_section_item_.GetNumHeaders() - 1);
}
}
void ItemContainer::ProcessIndexDependecies(BaseItem *item)
{
AddIndexDependecies(item);
item->Visit([&](BaseItem *param_item) {
AddIndexDependecies(param_item);
return true;
});
}
bool ItemContainer::WriteHeaderIndexInfo(Writer *writer)
{
if (!writer->Write<uint32_t>(class_map_.size())) {
@ -883,7 +885,7 @@ ItemTypes ItemContainer::IndexItem::GetItemType() const
switch (type_) {
case IndexType::CLASS:
return ItemTypes::CLASS_INDEX_ITEM;
case IndexType::METHOD:
case IndexType::METHOD_STRING_LITERAL:
return ItemTypes::METHOD_INDEX_ITEM;
case IndexType::FIELD:
return ItemTypes::FIELD_INDEX_ITEM;

View File

@ -516,6 +516,8 @@ private:
void UpdateOrderIndexes();
void AddIndexDependecies(BaseItem *item);
void ProcessIndexDependecies(BaseItem *item);
size_t GetForeignOffset() const;

View File

@ -71,6 +71,16 @@ enum class FieldTag : uint8_t {
TYPE_ANNOTATION = 0x06
};
enum class FunctionKind : uint8_t {
NONE = 0x0,
FUNCTION = 0x1,
NC_FUNCTION = 0x2,
GENERATOR_FUNCTION = 0x3,
ASYNC_FUNCTION = 0x4,
ASYNC_GENERATOR_FUNCTION = 0x5,
ASYNC_NC_FUNCTION = 0x6
};
bool IsDynamicLanguage(panda::panda_file::SourceLang lang);
std::optional<panda::panda_file::SourceLang> LanguageFromString(std::string_view lang);
const char *LanguageToString(panda::panda_file::SourceLang lang);
@ -85,6 +95,10 @@ static constexpr uint32_t INVALID_OFFSET = std::numeric_limits<uint32_t>::max();
static constexpr uint32_t INVALID_INDEX = std::numeric_limits<uint32_t>::max();
static constexpr uint32_t MAX_INDEX_16 = std::numeric_limits<uint16_t>::max();
static constexpr uint32_t MAX_INDEX_32 = std::numeric_limits<uint32_t>::max();
static constexpr uint32_t FLAG_WIDTH = 8;
static constexpr uint32_t FUNTION_KIND_WIDTH = 8;
static constexpr uint32_t FUNCTION_KIND_MASK = 0xFF00;
static constexpr uint32_t FLAG_MASK = 0xFF;
constexpr uint32_t PGO_STRING_DEFAULT_COUNT = 5;
constexpr uint32_t PGO_CLASS_DEFAULT_COUNT = 3;
@ -128,11 +142,10 @@ constexpr std::string_view CODE_ITEM = "code_item";
enum class IndexType {
// 16-bit indexes
CLASS = 0x0,
METHOD = 0x1,
METHOD_STRING_LITERAL = 0x1,
FIELD = 0x2,
PROTO = 0x3,
LAST_16 = PROTO,
// 32-bit indexes
LINE_NUMBER_PROG = 0x04,
LAST_32 = LINE_NUMBER_PROG,
@ -419,7 +432,7 @@ public:
DEFAULT_COPY_SEMANTIC(PrimitiveTypeItem);
};
class StringItem : public BaseItem {
class StringItem : public IndexedItem {
public:
explicit StringItem(std::string str);
@ -446,6 +459,11 @@ public:
return utf16_length_;
}
IndexType GetIndexType() const override
{
return IndexType::METHOD_STRING_LITERAL;
}
DEFAULT_MOVE_SEMANTIC(StringItem);
DEFAULT_COPY_SEMANTIC(StringItem);
@ -723,7 +741,7 @@ public:
IndexType GetIndexType() const override
{
return IndexType::METHOD;
return IndexType::METHOD_STRING_LITERAL;
}
StringItem *GetNameItem() const
@ -736,6 +754,18 @@ public:
return class_;
}
void SetFunctionKind(FunctionKind kind)
{
access_flags_ &= (~FUNCTION_KIND_MASK);
access_flags_ |= (static_cast<uint8_t>(kind) << FLAG_WIDTH);
}
void SetHeaderIndex(uint16_t idx)
{
access_flags_ &= (FUNCTION_KIND_MASK | FLAG_MASK);
access_flags_ |= (idx << (FUNTION_KIND_WIDTH + FLAG_WIDTH));
}
~BaseMethodItem() override = default;
DEFAULT_MOVE_SEMANTIC(BaseMethodItem);
@ -752,7 +782,7 @@ private:
BaseClassItem *class_;
StringItem *name_;
ProtoItem *proto_;
uint32_t access_flags_;
uint32_t access_flags_; // layout: |<- 16-bit header index ->|<- 8-bit FunctionKind ->|<- 8-bit flag ->|
};
class MethodParamItem {
@ -1428,7 +1458,7 @@ private:
class ScalarValueItem;
class ArrayValueItem;
class ValueItem : public BaseItem {
class ValueItem : public IndexedItem {
public:
enum class Type { INTEGER, LONG, FLOAT, DOUBLE, ID, ARRAY };
@ -1614,6 +1644,11 @@ public:
bool Write(Writer *writer) override;
IndexType GetIndexType() const override
{
return IndexType::METHOD_STRING_LITERAL;
}
ItemTypes GetItemType() const override
{
return ItemTypes::LITERAL_ARRAY_ITEM;

View File

@ -0,0 +1,70 @@
/**
* Copyright (c) 2022 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 LIBPANDAFILE_INDEX_ACCESSOR_H_
#define LIBPANDAFILE_INDEX_ACCESSOR_H_
#include "file.h"
#include "file_items.h"
namespace panda::panda_file {
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions)
class IndexAccessor {
public:
IndexAccessor(const File &pf, File::EntityId method_id)
{
constexpr size_t SKIP_NUM = 3; // 3 : skip class_idx and proto_idx and name
auto sp = pf.GetSpanFromId(method_id).SubSpan(IDX_SIZE * (SKIP_NUM - 1) + ID_SIZE);
access_flags_ = helpers::ReadULeb128(&sp);
header_index_ = access_flags_ >> (FUNTION_KIND_WIDTH + FLAG_WIDTH);
num_headers_ = pf.GetHeader()->num_indexes;
const auto *header = &(pf.GetIndexHeaders()[header_index_]);
indexes_ = pf.GetMethodIndex(header);
}
~IndexAccessor() = default;
// quick way to resolve offset by 16-bit id in method's instructions
uint32_t GetOffsetById(uint16_t idx) const
{
return indexes_[idx].GetOffset();
}
FunctionKind GetFunctionKind() const
{
return static_cast<FunctionKind>((access_flags_ & FUNCTION_KIND_MASK) >> FLAG_WIDTH);
}
uint16_t GetHeaderIndex() const
{
return header_index_;
}
uint32_t GetNumHeaders() const
{
return num_headers_;
}
private:
Span<const File::EntityId> indexes_;
uint32_t access_flags_;
uint16_t header_index_;
uint32_t num_headers_;
};
} // namespace panda::panda_file
#endif // LIBPANDAFILE_INDEX_ACCESSOR_H_

View File

@ -31,6 +31,12 @@ inline size_t LiteralDataAccessor::GetLiteralValsNum(size_t index)
return num;
}
inline size_t LiteralDataAccessor::GetLiteralValsNum(File::EntityId id) const
{
auto sp = panda_file_.GetSpanFromId(id);
return helpers::Read<LEN_SIZE>(&sp);
}
template <class Callback>
inline void LiteralDataAccessor::EnumerateLiteralVals(size_t index, const Callback &cb)
{

View File

@ -71,6 +71,7 @@ public:
void EnumerateLiteralVals(File::EntityId id, const Callback &cb);
size_t GetLiteralValsNum(size_t index);
size_t GetLiteralValsNum(File::EntityId id) const;
uint32_t GetLiteralNum() const
{

View File

@ -102,9 +102,13 @@ inline BytecodeId BytecodeInst<Mode>::GetId() const {
// Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
if (format == Format::<%= fmt.pretty.upcase %>) {
constexpr std::array<uint8_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<uint8_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
% if offsets.length == 1 && widths.length == 1
return BytecodeId(static_cast<uint32_t>(Read<<%= offsets[0] %>, <%= widths[0] %>>()));
% else
constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
return BytecodeId(static_cast<uint32_t>(Read<OFFSETS[idx], WIDTHS[idx]>()));
% end
}
% end
@ -132,8 +136,8 @@ inline void BytecodeInst<Mode>::UpdateId(BytecodeId new_id, uint32_t idx /* = 0
// Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
if (format == Format::<%= fmt.pretty.upcase %>) {
constexpr std::array<uint8_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<uint8_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
this->Write(new_id.AsRawValue(), OFFSETS[idx] / 8, WIDTHS[idx] / 8);
return;
}
@ -162,8 +166,8 @@ inline BytecodeId BytecodeInst<Mode>::GetId(size_t idx /* = 0 */) const {
% widths = id_ops.map(&:width)
%
case Format::<%= fmt.pretty.upcase %>: {
constexpr std::array<uint8_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<uint8_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
return BytecodeId(static_cast<uint32_t>(Read64(OFFSETS[idx], WIDTHS[idx])));
}
% end
@ -193,8 +197,8 @@ ALWAYS_INLINE inline uint16_t BytecodeInst<Mode>::GetVReg() const { // NOLINTNE
// Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
if constexpr (format == Format::<%= fmt.pretty.upcase %>) {
constexpr std::array<uint8_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<uint8_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
return static_cast<uint16_t>(Read<OFFSETS[idx], WIDTHS[idx]>());
}
@ -223,8 +227,8 @@ ALWAYS_INLINE inline uint16_t BytecodeInst<Mode>::GetVReg(size_t idx /* = 0 */)
% widths = reg_ops.map(&:width)
%
case Format::<%= fmt.pretty.upcase %>: {
constexpr std::array<uint8_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<uint8_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
if (idx > <%= n - 1 %>) {
break;
}
@ -256,8 +260,8 @@ inline auto BytecodeInst<Mode>::GetImm() const { // NOLINTNEXTLINE(readability-
// Disable check due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
if constexpr (format == Format::<%= fmt.pretty.upcase %>) {
constexpr std::array<uint8_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<uint8_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
return Read<OFFSETS[idx], WIDTHS[idx], true>();
}
@ -285,8 +289,8 @@ inline auto BytecodeInst<Mode>::GetImm64(size_t idx /* = 0 */) const {
% widths = imm_ops.map(&:width)
%
case Format::<%= fmt.pretty.upcase %>: {
constexpr std::array<uint8_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<uint8_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
constexpr std::array<size_t, <%= n %>> OFFSETS{<%= offsets.join(", ") %>};
constexpr std::array<size_t, <%= n %>> WIDTHS{<%= widths.join(", ") %>};
return Read64<true>(OFFSETS[idx], WIDTHS[idx]);
}
% end
@ -327,7 +331,13 @@ inline bool BytecodeInst<Mode>::IsPrefixed() const {
template <const BytecodeInstMode Mode>
inline typename BytecodeInst<Mode>::Format BytecodeInst<Mode>::GetFormat() const { // NOLINT(readability-function-size)
switch(GetOpcode()) {
return GetFormat(GetOpcode());
}
/* static */
template <const BytecodeInstMode Mode>
constexpr typename BytecodeInst<Mode>::Format BytecodeInst<Mode>::GetFormat(Opcode opcode) { // NOLINT(readability-function-size)
switch(opcode) {
% Panda::instructions.each do |i|
case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>:
return BytecodeInst<Mode>::Format::<%= i.format.pretty.upcase %>;
@ -343,7 +353,7 @@ inline typename BytecodeInst<Mode>::Format BytecodeInst<Mode>::GetFormat() const
template<const BytecodeInstMode Mode> inline bool BytecodeInst<Mode>::HasFlag(Flags flag) const {
switch(GetOpcode()) {
% Panda::instructions.each do |i|
% flag_array = i.properties.map {|prop| "Flags::" + prop.upcase}
% flag_array = i.real_properties.map {|prop| "Flags::" + prop.upcase}
% flag_array += ['0'] if flag_array.empty?
% flags = flag_array.join(' | ')
case BytecodeInst<Mode>::Opcode::<%= i.opcode.upcase %>: