mirror of
https://github.com/openharmony/ark_runtime_core.git
synced 2026-07-01 13:17:23 -04:00
upload runtime_core
Signed-off-by: y00576111 <yaojian16@huawei.com> Change-Id: I2509006818624fd3960ef645165fdb1f317d3d5e
This commit is contained in:
+2
-2
@@ -164,13 +164,13 @@ template("ark_gen") {
|
||||
# * requires -- if defined, will require additional Ruby files for template generation, must be list
|
||||
# * extra_dependencies -- a list of files that should be considered as dependencies lable, must be list, not used
|
||||
template("ark_isa_gen") {
|
||||
isa_data = "$ark_root/isa/isa.yaml"
|
||||
isa_data = "$root_gen_dir/isa/isa.yaml"
|
||||
isa_requires = [ "$ark_root/isa/isapi.rb" ]
|
||||
if (defined(invoker.requires)) {
|
||||
isa_requires += invoker.requires
|
||||
}
|
||||
|
||||
dependencies = []
|
||||
dependencies = ["$ark_root/isa:isa_combine"]
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
dependencies += invoker.extra_dependencies
|
||||
}
|
||||
|
||||
+4
-8
@@ -20,6 +20,8 @@ config("arkassembler_public_config") {
|
||||
"$target_gen_dir",
|
||||
"$target_gen_dir/include",
|
||||
]
|
||||
|
||||
defines = [ "PANDA_WITH_ECMASCRIPT" ]
|
||||
}
|
||||
|
||||
libarkassembler_sources = [
|
||||
@@ -162,20 +164,14 @@ ark_gen_file("ark_asm_ins_create_builtins_api_h") {
|
||||
ark_gen_file("builtin_parsing_cpp") {
|
||||
template_file = "templates/builtin_parsing.cpp.erb"
|
||||
data_file = "../isa/builtins.yaml"
|
||||
requires = [
|
||||
"../isa/builtinsapi.rb",
|
||||
"//ark/js_runtime/ecmascript/ecma_builtins.rb",
|
||||
]
|
||||
requires = [ "../isa/builtinsapi.rb" ]
|
||||
output_file = "$target_gen_dir/builtin_parsing.cpp"
|
||||
}
|
||||
|
||||
ark_gen_file("builtin_parsing_tests_cpp") {
|
||||
template_file = "templates/builtin_parsing_tests.cpp.erb"
|
||||
data_file = "../isa/builtins.yaml"
|
||||
requires = [
|
||||
"../isa/builtinsapi.rb",
|
||||
"//ark/js_runtime/ecmascript/ecma_builtins.rb",
|
||||
]
|
||||
requires = [ "../isa/builtinsapi.rb" ]
|
||||
output_file = "$target_gen_dir/builtin_parsing_tests.cpp"
|
||||
}
|
||||
|
||||
|
||||
+6
-22
@@ -18,35 +18,19 @@ Instruction.class_eval do
|
||||
end
|
||||
|
||||
def builtin?
|
||||
%w[builtin].include?(stripped_mnemonic)
|
||||
end
|
||||
|
||||
def builtin_idr4?
|
||||
builtin? && mnemonic.split('.')[-1] == 'idr4'
|
||||
end
|
||||
|
||||
def builtin_idr6?
|
||||
builtin? && mnemonic.split('.')[-1] == 'idr6'
|
||||
stripped_mnemonic == 'builtin'
|
||||
end
|
||||
|
||||
def call?
|
||||
%w[call initobj].include?(stripped_mnemonic)
|
||||
properties.include?('call') || stripped_mnemonic == 'initobj'
|
||||
end
|
||||
|
||||
def calli?
|
||||
%w[calli].include?(stripped_mnemonic)
|
||||
end
|
||||
|
||||
def call_range?
|
||||
call? && mnemonic.split('.')[-1] == 'range'
|
||||
end
|
||||
|
||||
def calli_range?
|
||||
calli? && mnemonic.split('.')[-1] == 'range'
|
||||
def range?
|
||||
mnemonic.split('.')[-1] == 'range'
|
||||
end
|
||||
|
||||
def simple_call?
|
||||
(call? || calli?) && !call_range?
|
||||
call? && !range?
|
||||
end
|
||||
|
||||
def return?
|
||||
@@ -108,7 +92,7 @@ end
|
||||
def assembler_signature(group, is_jump)
|
||||
insn = group.first
|
||||
sig = format_ops(insn.format)
|
||||
sig.each_with_index do |o, i|
|
||||
sig.each do |o|
|
||||
if o.name.start_with?('imm')
|
||||
if insn.asm_token.start_with?('F')
|
||||
o.type, o.name = is_jump ? ['const std::string &', 'label'] : ["double", o.name]
|
||||
|
||||
@@ -772,6 +772,10 @@ static std::unique_ptr<ScalarValue> CreateValue(const panda::pandasm::LiteralArr
|
||||
{
|
||||
switch (literal.tag_) {
|
||||
case panda_file::LiteralTag::TAGVALUE:
|
||||
[[fallthrough]];
|
||||
case panda_file::LiteralTag::ACCESSOR:
|
||||
[[fallthrough]];
|
||||
case panda_file::LiteralTag::NULLVALUE:
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::U8>(std::get<uint8_t>(literal.value_)));
|
||||
case panda_file::LiteralTag::BOOL:
|
||||
@@ -780,6 +784,9 @@ static std::unique_ptr<ScalarValue> CreateValue(const panda::pandasm::LiteralArr
|
||||
case panda_file::LiteralTag::ARRAY_I8:
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::I8>(std::get<uint8_t>(literal.value_)));
|
||||
case panda_file::LiteralTag::METHODAFFILIATE:
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::U16>(std::get<uint16_t>(literal.value_)));
|
||||
case panda_file::LiteralTag::ARRAY_I16:
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::I16>(std::get<uint16_t>(literal.value_)));
|
||||
@@ -807,16 +814,10 @@ static std::unique_ptr<ScalarValue> CreateValue(const panda::pandasm::LiteralArr
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::STRING>(std::string_view(std::get<std::string>(literal.value_))));
|
||||
case panda_file::LiteralTag::METHOD:
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::METHOD>(std::string_view(std::get<std::string>(literal.value_))));
|
||||
[[fallthrough]];
|
||||
case panda_file::LiteralTag::GENERATORMETHOD:
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::METHOD>(std::string_view(std::get<std::string>(literal.value_))));
|
||||
case panda_file::LiteralTag::ACCESSOR:
|
||||
[[fallthrough]];
|
||||
case panda_file::LiteralTag::NULLVALUE:
|
||||
return std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::U8>(std::get<uint8_t>(literal.value_)));
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
||||
@@ -146,11 +146,6 @@ struct Ins {
|
||||
return HasFlag(InstFlags::CALL);
|
||||
}
|
||||
|
||||
bool IsBuiltinIdr6() const
|
||||
{
|
||||
return opcode == Opcode::BUILTIN_IDR6;
|
||||
}
|
||||
|
||||
bool IsPseudoCall() const
|
||||
{
|
||||
return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "assembly-file-location.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
@@ -59,7 +59,6 @@ bool Parser::ParseRecordFields()
|
||||
context_.ins_number = curr_record_->field_list.size();
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "parse line " << line_stric_ << " as field (.field name)";
|
||||
|
||||
if (!ParseRecordField()) {
|
||||
if (context_.err.err != Error::ErrorType::ERR_NONE) {
|
||||
return false;
|
||||
@@ -228,7 +227,6 @@ bool Parser::ParseFunctionCode()
|
||||
void Parser::ParseAsRecord(const std::vector<Token> &tokens)
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "started parsing of record (line " << line_stric_ << "): " << tokens[0].whole_line;
|
||||
|
||||
func_def_ = false;
|
||||
record_def_ = true;
|
||||
|
||||
@@ -271,7 +269,6 @@ void Parser::ParseAsRecord(const std::vector<Token> &tokens)
|
||||
void Parser::ParseAsFunction(const std::vector<Token> &tokens)
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "started parsing of function (line " << line_stric_ << "): " << tokens[0].whole_line;
|
||||
|
||||
record_def_ = false;
|
||||
func_def_ = true;
|
||||
|
||||
@@ -708,7 +705,6 @@ Expected<Program, Error> Parser::Parse(TokenSet &vectors_tokens, const std::stri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParseAfterLine(is_first_statement)) {
|
||||
break;
|
||||
}
|
||||
@@ -1182,7 +1178,7 @@ bool Parser::ParseOperandInteger()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Parser::ParseOperandFloat()
|
||||
bool Parser::ParseOperandFloat(bool is_64bit)
|
||||
{
|
||||
if (context_.err.err != Error::ErrorType::ERR_NONE) {
|
||||
return false;
|
||||
@@ -1202,7 +1198,7 @@ bool Parser::ParseOperandFloat()
|
||||
return false;
|
||||
}
|
||||
|
||||
double n = FloatNumber(p);
|
||||
double n = FloatNumber(p, is_64bit);
|
||||
if (errno == ERANGE) {
|
||||
context_.err =
|
||||
GetError("Too large immediate (length is more than 64 bit).", Error::ErrorType::ERR_BAD_FLOAT_WIDTH);
|
||||
|
||||
@@ -161,7 +161,7 @@ private:
|
||||
bool ParseOperandVreg();
|
||||
bool ParseOperandComma();
|
||||
bool ParseOperandInteger();
|
||||
bool ParseOperandFloat();
|
||||
bool ParseOperandFloat(bool is_64bit);
|
||||
bool ParseOperandId();
|
||||
bool ParseOperandLabel();
|
||||
bool ParseOperandField();
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
namespace panda::pandasm {
|
||||
|
||||
int64_t Parser::MnemonicToBuiltinId() {
|
||||
const auto token = context_.GiveToken();
|
||||
[[maybe_unused]] const auto token = context_.GiveToken();
|
||||
|
||||
--context_;
|
||||
const auto ins = context_.GiveToken();
|
||||
[[maybe_unused]] const auto ins = context_.GiveToken();
|
||||
++context_;
|
||||
|
||||
% PandaBuiltins::builtins.each_with_index do |builtin, i|
|
||||
@@ -60,4 +60,4 @@ bool Parser::ParseOperandBuiltinMnemonic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
} // namespace panda::pandasm
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "mangling.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
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,
|
||||
@@ -101,7 +100,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
|
||||
% raise "Unexpected operand type"
|
||||
% end
|
||||
% end
|
||||
% if insn.call?
|
||||
% if insn.call? && insn.properties.include?('method_id')
|
||||
% ops << ops.shift
|
||||
% end
|
||||
% ops
|
||||
@@ -137,7 +136,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
|
||||
% imms_num += 1
|
||||
% end
|
||||
% end
|
||||
% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6?
|
||||
% if insn.simple_call?
|
||||
% if imms_num > 0
|
||||
if (imms.size() < <%= imms_num %>) {
|
||||
return false;
|
||||
@@ -164,7 +163,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
|
||||
}
|
||||
% end
|
||||
% end
|
||||
% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6?
|
||||
% if insn.simple_call?
|
||||
auto registers = regs;
|
||||
% call_map[insn.mnemonic].map { |m| inst_map[m] }.each do |i|
|
||||
% registers = i.operands.select(&:reg?)
|
||||
|
||||
@@ -34,10 +34,10 @@ std::string panda::pandasm::Ins::ToString(std::string endline, bool print_args /
|
||||
case panda::pandasm::Opcode::<%= insn.asm_token%>: {
|
||||
full_operation += "<%= insn.mnemonic%>";
|
||||
% print_kind = case
|
||||
% when insn.call? && !insn.properties.include?('method_id')
|
||||
% 'PrintKind::CALLI'
|
||||
% when insn.call? || !insn.public?
|
||||
% 'PrintKind::CALL'
|
||||
% when insn.calli?
|
||||
% 'PrintKind::CALLI'
|
||||
% else
|
||||
% 'PrintKind::DEFAULT'
|
||||
% end
|
||||
|
||||
@@ -49,7 +49,7 @@ bool Parser::ParseOperands()
|
||||
% end
|
||||
% required_args = operands.size
|
||||
% required_args = 1 if insn.call?
|
||||
% required_args = 2 if insn.calli?
|
||||
% required_args = 2 if insn.stripped_mnemonic == 'calli'
|
||||
% operands.each_with_index do |op, j|
|
||||
%
|
||||
% if (j != 0)
|
||||
@@ -83,13 +83,13 @@ bool Parser::ParseOperands()
|
||||
|
||||
ParseOperandVreg();
|
||||
% elsif op.imm?
|
||||
% if (!insn.public? && j == 0)
|
||||
% if (insn.builtin? && j == 0)
|
||||
ParseOperandBuiltinMnemonic();
|
||||
% elsif properties.include?("jump")
|
||||
ParseOperandLabel();
|
||||
% else
|
||||
% if properties.include?("float")
|
||||
ParseOperandFloat();
|
||||
ParseOperandFloat(<%= op.size == 64 ? "true" : "false" %>);
|
||||
% else
|
||||
ParseOperandInteger();
|
||||
% end
|
||||
|
||||
@@ -176,13 +176,16 @@ inline bool ValidateFloat(std::string_view p)
|
||||
return !nowexp;
|
||||
}
|
||||
|
||||
inline double FloatNumber(std::string_view p)
|
||||
inline double FloatNumber(std::string_view p, bool is_64bit)
|
||||
{
|
||||
constexpr size_t GENERAL_SHIFT = 2;
|
||||
// expects a valid number
|
||||
if (p.size() > GENERAL_SHIFT && p.substr(0, GENERAL_SHIFT) == "0x") { // hex literal
|
||||
char *end = nullptr;
|
||||
return bit_cast<double>(strtoull(p.data(), &end, 0));
|
||||
if (is_64bit) {
|
||||
return bit_cast<double>(strtoull(p.data(), &end, 0));
|
||||
}
|
||||
return bit_cast<float>(static_cast<uint32_t>(strtoull(p.data(), &end, 0)));
|
||||
}
|
||||
return std::strtold(std::string(p.data(), p.length()).c_str(), nullptr);
|
||||
}
|
||||
|
||||
+3
-3
@@ -39,7 +39,7 @@ $ make coverage
|
||||
```
|
||||
Location of the code coverage report: BUILD_DIR/compiler/coverage_report
|
||||
|
||||
## Check style
|
||||
## Check style
|
||||
|
||||
To check the style, perform the previous steps and build style-checker targets. Note that you must install clang-format and clang-tidy with libraries. For details, see scripts/bootstrap*.sh.
|
||||
```
|
||||
@@ -62,12 +62,12 @@ Run `make help | grep clang` to see all possible clang-[format|style] targets.
|
||||
For issues in opt.cpp, you may check the style through clang-format `make clang_format_opt_opt.cpp`, or through clang-tidy `make clang_tidy_opt_opt.cpp`. For the force clang-format code style, use `make clang_force_format_opt_opt.cpp`.
|
||||
For code-style check through one check system, use `make clang_tidy` or `make clang_format`.
|
||||
|
||||
Generated files:
|
||||
Generated files:
|
||||
* `compile_commands.json` - json nija-commands file to correct execution clang-tidy.
|
||||
* Standard cmake-files: `CMakeCache.txt`, `Makefile`, `cmake_install.cmake` and folder `CMakeFiles`.
|
||||
|
||||
|
||||
Discussion about format : rus-os-team/virtual-machines-and-tools/vm-investigation-and-design#24
|
||||
Discussion about format : rus-os-team/virtual-machines-and-tools/vm-investigation-and-design#24
|
||||
* Clang-tidy style file - `.clang-tidy`
|
||||
* Clang-format style file - `.clang-format`
|
||||
* Script to show diff through clang-format execution - `build/run-clang-format.py`
|
||||
|
||||
@@ -75,7 +75,7 @@ function(panda_gen)
|
||||
REQUIRES ${GEN_ARG_REQUIRES}
|
||||
EXTRA_DEPENDENCIES ${GEN_ARG_EXTRA_DEPENDENCIES}
|
||||
)
|
||||
add_custom_target(${TARGET} ALL DEPENDS ${OUTPUT_FILE})
|
||||
add_custom_target(${TARGET} DEPENDS ${OUTPUT_FILE})
|
||||
add_dependencies(${GEN_ARG_TARGET_NAME} ${TARGET})
|
||||
endforeach()
|
||||
endfunction()
|
||||
@@ -103,9 +103,10 @@ function(panda_isa_gen)
|
||||
"${multivalues}"
|
||||
${ARGN}
|
||||
)
|
||||
set(ISA_DATA "${PANDA_ROOT}/isa/isa.yaml")
|
||||
set(ISA_DATA "${CMAKE_BINARY_DIR}/isa/isa.yaml")
|
||||
set(ISAPI "${PANDA_ROOT}/isa/isapi.rb")
|
||||
list(INSERT ISA_GEN_ARG_REQUIRES 0 ${ISAPI})
|
||||
list(APPEND ISA_GEN_ARG_EXTRA_DEPENDENCIES isa_assert)
|
||||
panda_gen(DATA ${ISA_DATA}
|
||||
TEMPLATES ${ISA_GEN_ARG_TEMPLATES}
|
||||
SOURCE ${ISA_GEN_ARG_SOURCE}
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
import("//ark/runtime_core/ark_config.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
config("arkdisassembler_public_config") {
|
||||
defines = [ "PANDA_WITH_ECMASCRIPT" ]
|
||||
}
|
||||
|
||||
arkdisassembler_sources = [
|
||||
"$target_gen_dir/bc_ins_to_pandasm_ins.cpp",
|
||||
"$target_gen_dir/get_ins_info.cpp",
|
||||
@@ -25,6 +29,7 @@ arkdisassembler_sources = [
|
||||
|
||||
arkdisassembler_configs = [
|
||||
sdk_libc_secshared_config,
|
||||
":arkdisassembler_public_config",
|
||||
"$ark_root:ark_config",
|
||||
"$ark_root/libpandabase:arkbase_public_config",
|
||||
"$ark_root/assembler:arkassembler_public_config",
|
||||
@@ -121,10 +126,7 @@ ark_isa_gen("isa_gen_ark_disam") {
|
||||
ark_gen_file("get_instructions_cpp") {
|
||||
template_file = "$ark_root/disassembler/templates/get_instructions.cpp.erb"
|
||||
data_file = "$ark_root/isa/builtins.yaml"
|
||||
requires = [
|
||||
"$ark_root/isa/builtinsapi.rb",
|
||||
"//ark/js_runtime/ecmascript/ecma_builtins.rb",
|
||||
]
|
||||
requires = [ "$ark_root/isa/builtinsapi.rb" ]
|
||||
output_file = "$target_gen_dir/get_instructions.cpp"
|
||||
}
|
||||
|
||||
|
||||
@@ -230,17 +230,6 @@ add_custom_target(disasm_binaries_test_metadata)
|
||||
|
||||
add_dependencies(disasm_binaries_test_metadata disasm_binaries-meta)
|
||||
|
||||
# builtin_tests files
|
||||
compile_pre_build(TARGET disasm_binaries-builtins
|
||||
FILE_SRC ${DISASM_TESTS_DIR}/builtins.pa
|
||||
FILE_DST ${DISASM_BIN_DIR}/builtins.bc)
|
||||
|
||||
add_custom_target(disasm_binaries_test_builtins)
|
||||
|
||||
add_dependencies(disasm_binaries_test_builtins disasm_binaries-builtins)
|
||||
|
||||
add_dependencies(disasm_test_instructions disasm_binaries_test_builtins)
|
||||
|
||||
add_custom_target(disasm_tests
|
||||
DEPENDS disasm_test_records
|
||||
DEPENDS disasm_test_labels
|
||||
|
||||
@@ -43,7 +43,7 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File
|
||||
}
|
||||
|
||||
auto pa_ins = BytecodeInstructionToPandasmInstruction(bc_ins, method_id, method->language);
|
||||
|
||||
|
||||
// alter instructions operands depending on instruction type
|
||||
if (pa_ins.IsConditionalJump() || pa_ins.IsJump()) {
|
||||
const int32_t jmp_offset = std::get<int64_t>(pa_ins.imms.at(0));
|
||||
@@ -65,7 +65,7 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File
|
||||
<< "0x" << std::hex << code_id.GetOffset() << "). incorrect instruction at offset "
|
||||
<< (bc_ins.GetAddress() - ins_arr) << ": invalid jump offset "
|
||||
<< jmp_offset << " - jumping in the middle of another instruction!";
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " ("
|
||||
@@ -78,7 +78,7 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File
|
||||
// if builtin - change imm to mnemonic
|
||||
switch (pa_ins.opcode) {
|
||||
% PandaBuiltins::instructions.each do |insn|
|
||||
case pandasm::Opcode::<%=insn.mnemonic.tr('.', '_').upcase%>:
|
||||
case pandasm::Opcode::<%=insn.mnemonic.tr('.', '_').upcase%>:
|
||||
switch(pa_ins.imms[0].index()) {
|
||||
// contains int64_t
|
||||
case 0:
|
||||
@@ -140,4 +140,4 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File
|
||||
return unknown_external_methods;
|
||||
}
|
||||
|
||||
} // namespace panda::disasm
|
||||
} // namespace panda::disasm
|
||||
|
||||
@@ -310,35 +310,6 @@ TEST(instructions_test, test_newarr)
|
||||
EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u64[]") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST(instructions_test, test_builtins)
|
||||
{
|
||||
Disassembler d {};
|
||||
|
||||
std::stringstream ss {};
|
||||
d.Disassemble(g_bin_path_abs + "builtins.bc");
|
||||
d.Serialize(ss);
|
||||
|
||||
size_t beg_g = ss.str().find("g_f32_f32_void_(f32 a0, f32 a1) <static> {");
|
||||
size_t end_g = ss.str().find('}', beg_g);
|
||||
|
||||
ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found";
|
||||
|
||||
std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {")));
|
||||
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.acc i32tof32") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.acc i64tof32") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.acc f64tof32") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.acc monitorenter") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.acc monitorexit") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fadd2f32, a1") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fsub2f32, v13") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fmul2f32, v13") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fdiv2f32, v13") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fmod2f32, v13") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fcmpl2f32, a0") != std::string::npos);
|
||||
EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fcmpg2f32, v13") != std::string::npos);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::string dir_basename {};
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Copyright (c) 2021 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.
|
||||
|
||||
import("//ark/runtime_core/ark_config.gni")
|
||||
|
||||
action("isa_combine") {
|
||||
script = "$ark_root/isa/combine.rb"
|
||||
inputs = [
|
||||
"$ark_root/isa/isa.yaml",
|
||||
"$ark_root/../js_runtime/ecmascript/ecma_isa.yaml"
|
||||
]
|
||||
input0 = rebase_path(inputs[0], root_build_dir)
|
||||
input1 = rebase_path(inputs[1], root_build_dir)
|
||||
outputs = ["$root_gen_dir/isa/isa.yaml"]
|
||||
args = [
|
||||
"-d",
|
||||
"$input0,$input1",
|
||||
"-o",
|
||||
rebase_path(outputs[0], root_build_dir)
|
||||
]
|
||||
}
|
||||
+13
-15
@@ -11,25 +11,24 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.5.2 FATAL_ERROR)
|
||||
|
||||
project(isa)
|
||||
|
||||
set(ISA_FILE "${PROJECT_SOURCE_DIR}/isa.yaml")
|
||||
set(ISA_FILE "${CMAKE_BINARY_DIR}/isa/isa.yaml")
|
||||
set(ISA_CORE_FILE "${PROJECT_SOURCE_DIR}/isa.yaml")
|
||||
set(ISA_ASSERTS "${PROJECT_SOURCE_DIR}/asserts.rb")
|
||||
set(ISA_COMBINE "${PROJECT_SOURCE_DIR}/combine.rb")
|
||||
set(ISAPI "${PROJECT_SOURCE_DIR}/isapi.rb")
|
||||
set(ISA_PLUGIN_FILES "")
|
||||
|
||||
# ISA YAML validation against the schema
|
||||
string(REPLACE ";" "," ISA_PLUGIN_FILES_STR "${ISA_PLUGIN_FILES}")
|
||||
|
||||
set(ISA_SCHEMA "${PROJECT_SOURCE_DIR}/schema.json")
|
||||
|
||||
set(VALIDATE_MARKER "${PROJECT_BINARY_DIR}/validate.ok")
|
||||
add_custom_command(OUTPUT ${VALIDATE_MARKER}
|
||||
COMMENT "Validate ISA file"
|
||||
COMMAND pajv -s ${ISA_SCHEMA} -d ${ISA_FILE} && ${CMAKE_COMMAND} -E touch ${VALIDATE_MARKER}
|
||||
DEPENDS ${ISA_SCHEMA} ${ISA_FILE}
|
||||
# ISA combine
|
||||
add_custom_command(OUTPUT ${ISA_FILE}
|
||||
COMMENT "Combine ISA files"
|
||||
COMMAND ${ISA_COMBINE} -d "${ISA_CORE_FILE},${ISA_PLUGIN_FILES_STR}" -o ${ISA_FILE}
|
||||
DEPENDS ${ISA_COMBINE} ${ISA_CORE_FILE} ${ISA_PLUGIN_FILES}
|
||||
)
|
||||
add_custom_target(isa_validate DEPENDS ${VALIDATE_MARKER})
|
||||
add_custom_target(isa_combine DEPENDS ${ISA_FILE})
|
||||
|
||||
# Check ISA_FILE content
|
||||
|
||||
@@ -41,13 +40,12 @@ add_custom_command(OUTPUT ${ASSERT_MARKER}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${ASSERT_MARKER}
|
||||
DEPENDS ${ISA_FILE} ${ISA_GEN_RB} ${ISA_ASSERTS} ${ISAPI}
|
||||
)
|
||||
add_custom_target(isa_assert ALL DEPENDS ${ASSERT_MARKER})
|
||||
add_custom_target(isa_assert DEPENDS ${ASSERT_MARKER})
|
||||
add_dependencies(isa_assert isa_combine)
|
||||
|
||||
# Template generation
|
||||
|
||||
set(TEMPLATES
|
||||
instructions.txt.erb
|
||||
isa.md.erb
|
||||
)
|
||||
|
||||
panda_isa_gen(TEMPLATES ${TEMPLATES})
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
File format and ISA ChangeLog
|
||||
=============================
|
||||
|
||||
* 0.0.0.2
|
||||
+ Removed compatibility check based on the isa checksum.
|
||||
+ Introduced new backward compatibility policy.
|
||||
+36
-8
@@ -16,16 +16,34 @@ def assert(name)
|
||||
raise "#{loc.path}:#{loc.lineno}: '#{name}' assertion failed" unless yield
|
||||
end
|
||||
|
||||
def uniq?(arr)
|
||||
arr.uniq.size == arr.size
|
||||
module Enumerable
|
||||
def sorted?
|
||||
each_cons(2).all? { |a, b| (a <=> b) <= 0 }
|
||||
end
|
||||
|
||||
def sorted_by?(&block)
|
||||
map(&block).sorted?
|
||||
end
|
||||
|
||||
def uniq?
|
||||
uniq.size == size
|
||||
end
|
||||
end
|
||||
|
||||
assert('Unique opcodes') { uniq?(Panda.instructions.map(&:opcode)) }
|
||||
assert('Unique opcodes') { Panda.instructions.map(&:opcode).uniq? }
|
||||
|
||||
assert('Non-prefixed instruction opcodes and prefixes should fit one byte') do
|
||||
Panda.instructions.reject(&:prefix).size + Panda.prefixes.size <= 256
|
||||
end
|
||||
|
||||
assert('Non-prefixed instruction opcode indexes are sorted') do
|
||||
Panda.instructions.reject(&:prefix).sorted_by?(&:opcode_idx)
|
||||
end
|
||||
|
||||
assert('Prefix opcode indexes are sorted') do
|
||||
Panda.prefixes.sorted_by?(&:opcode_idx)
|
||||
end
|
||||
|
||||
assert('All instructions for a prefix should fit one byte') do
|
||||
Panda.prefixes.map do |prefix|
|
||||
Panda.instructions.select { |insn| insn.prefix && (insn.prefix.name == prefix.name) }.size <= 256
|
||||
@@ -47,11 +65,19 @@ assert('Prefix should be defined') do
|
||||
end
|
||||
|
||||
assert('All prefixes should have unique name') do
|
||||
uniq?(Panda.prefixes.map(&:name))
|
||||
Panda.prefixes.map(&:name).uniq?
|
||||
end
|
||||
|
||||
assert('There should be non-zero gap between non-prefixed and prefixes') do
|
||||
!Panda.dispatch_table.invalid_non_prefixed_interval.to_a.empty?
|
||||
end
|
||||
|
||||
assert('There should be non-zero gap between public and private prefixes') do
|
||||
!Panda.dispatch_table.invalid_prefixes_interval.to_a.empty?
|
||||
end
|
||||
|
||||
assert('All tags are unique between categories') do
|
||||
uniq?(%i[verification exceptions properties].flat_map { |type| Panda.send(type).map(&:tag) })
|
||||
%i[verification exceptions properties].flat_map { |type| Panda.send(type).map(&:tag) }.uniq?
|
||||
end
|
||||
|
||||
assert('All tags are used') do
|
||||
@@ -116,7 +142,9 @@ assert('All calls write into accumulator') do
|
||||
end
|
||||
|
||||
assert('Calls should be non-prefixed') do # otherwise support in interpreter-to-compiler bridges
|
||||
Panda.instructions.select { |i| i.properties.include?('call') }.select(&:prefix).empty?
|
||||
Panda.instructions.select do |i|
|
||||
i.properties.include?('call') && !i.mnemonic.include?('polymorphic')
|
||||
end.select(&:prefix).empty?
|
||||
end
|
||||
|
||||
assert('Jumps differ from other control-flow') do # At least currently
|
||||
@@ -135,8 +163,8 @@ assert('Conversions should correspond to source and destination type') do
|
||||
end.all?
|
||||
end
|
||||
|
||||
assert('Operand type should be one of none, ref, u1, u2, i8, u8, i16, u16, i32, u32, i64, u64, b64, f64, top, any') do
|
||||
types = %w[none ref u1 u2 i8 u8 i16 u16 i32 u32 f32 i64 u64 b64 f64 top any]
|
||||
assert('Operand type should be one of none, ref, u1, u2, i8, u8, i16, u16, i32, u32, b32, i64, u64, b64, f64, top, any') do
|
||||
types = %w[none ref u1 u2 i8 u8 i16 u16 i32 u32 b32 f32 i64 u64 b64 f64 top any]
|
||||
Panda.instructions.map do |i|
|
||||
i.acc_and_operands.all? { |op| types.include?(op.type.sub('[]', '')) }
|
||||
end.all?
|
||||
|
||||
+1
-138
@@ -394,142 +394,5 @@ groups:
|
||||
acc: out:top
|
||||
format: [op_imm1_8_id_16_imm2_16_v1_8_v2_8]
|
||||
|
||||
- title: Built-in opcode with method id and one regs
|
||||
description: Non-public extension of the instruction set.
|
||||
verification:
|
||||
- none
|
||||
exceptions:
|
||||
- x_none
|
||||
properties:
|
||||
- acc_write
|
||||
- method_id
|
||||
pseudo: |
|
||||
pseudo: |
|
||||
builtin = resolve_builtin(imm)
|
||||
acc = builtin(id, v1)
|
||||
semantics: |
|
||||
skip
|
||||
instructions:
|
||||
- sig: builtin.idr3 imm, v1:in:top, method_id
|
||||
acc: out:top
|
||||
format: [op_imm_8_v1_8_id_16]
|
||||
|
||||
- title: Built-in opcode with method id and two regs
|
||||
description: Non-public extension of the instruction set.
|
||||
verification:
|
||||
- none
|
||||
exceptions:
|
||||
- x_none
|
||||
properties:
|
||||
- acc_write
|
||||
- method_id
|
||||
pseudo: |
|
||||
pseudo: |
|
||||
builtin = resolve_builtin(imm)
|
||||
acc = builtin(id, v1, v2)
|
||||
semantics: |
|
||||
skip
|
||||
instructions:
|
||||
- sig: builtin.idr4 imm, v1:in:top, v2:in:top, method_id
|
||||
acc: out:top
|
||||
format: [op_imm_8_v1_4_v2_4_id_16]
|
||||
|
||||
- title: Built-in opcode with method id and four regs
|
||||
description: Non-public extension of the instruction set.
|
||||
verification:
|
||||
- none
|
||||
exceptions:
|
||||
- x_none
|
||||
properties:
|
||||
- acc_write
|
||||
- method_id
|
||||
pseudo: |
|
||||
pseudo: |
|
||||
builtin = resolve_builtin(imm)
|
||||
acc = builtin(id, v1, v2, v3, v4)
|
||||
semantics: |
|
||||
skip
|
||||
instructions:
|
||||
- sig: builtin.idr6 imm, v1:in:top, v2:in:top, v3:in:top, v4:in:top, method_id
|
||||
acc: out:top
|
||||
format: [op_imm_8_v1_4_v2_4_v3_4_v4_4_id_16]
|
||||
|
||||
builtins:
|
||||
|
||||
builtins: [ ]
|
||||
#
|
||||
# f64 conversions and binary operations (including comparisons)
|
||||
# that preserve f32 precision for more accurate emulation of
|
||||
# Java single-precision floats. f64 is consumed and produced,
|
||||
# otherwise semantics and output values match corresponding
|
||||
# f64 instructions from the public part of the ISA.
|
||||
#
|
||||
|
||||
- sig: i32tof32
|
||||
acc: inout:i32->f64
|
||||
|
||||
- sig: i64tof32
|
||||
acc: inout:i64->f64
|
||||
|
||||
- sig: f64tof32
|
||||
acc: inout:f64->f64
|
||||
|
||||
- sig: fadd2f32 v:in:f64
|
||||
acc: inout:f64
|
||||
|
||||
- sig: fsub2f32 v:in:f64
|
||||
acc: inout:f64
|
||||
|
||||
- sig: fmul2f32 v:in:f64
|
||||
acc: inout:f64
|
||||
|
||||
- sig: fdiv2f32 v:in:f64
|
||||
acc: inout:f64
|
||||
|
||||
- sig: fmod2f32 v:in:f64
|
||||
acc: inout:f64
|
||||
|
||||
- sig: fcmpl2f32 v:in:f64
|
||||
acc: inout:f64->i32
|
||||
|
||||
- sig: fcmpg2f32 v:in:f64
|
||||
acc: inout:f64->i32
|
||||
|
||||
#
|
||||
# monitorenter and monitorexit are used to synchronize object access between threads.
|
||||
# Each object is associated with a monitor, and each monitor has a counter that allows one
|
||||
# to control access to the monitor object.
|
||||
#
|
||||
# These two opcodes take acc as input, and acc is assumed to hold the reference to the object.
|
||||
#
|
||||
# * monitorenter
|
||||
# When the thread tries to gain ownership of the monitor it
|
||||
# executes monitorenter and then one of three things can happen:
|
||||
# - The monitor entry count is zero. It means the monitor does not
|
||||
# belong to any thread. Then the thread enters the monitor and sets
|
||||
# the monitor entry count to one. The thread becomes the monitor owner.
|
||||
# - The monitor already belongs to the thread. In this case the thread re-enters
|
||||
# the monitor and increments the monitor entry count.
|
||||
# - The monitor already belongs to another thread. At this rate the thread blocks.
|
||||
# When the monitor entry count is zero, the blocked thread may try to enter
|
||||
# the monitor again.
|
||||
#
|
||||
# It is worth noting that as result of this opcode, an exception may be thrown:
|
||||
# - If acc stores null then NullPointerException is thrown
|
||||
#
|
||||
# * monitorexit
|
||||
# When the owner thread executes monitorexit it decrements the entry monitor count.
|
||||
# If the one turns to zero, the thread exits the monitor and the monitor
|
||||
# no longer belongs to it. Then other threads may try to gain ownership
|
||||
# of the monitor.
|
||||
#
|
||||
# It is worth noting that as result of this opcode, an exception may be thrown:
|
||||
# - If acc stores null then NullPointerException is thrown
|
||||
# - If the thread that executes monitorexit is not the monitor owner then
|
||||
# IllegalMonitorStateException is thrown
|
||||
#
|
||||
|
||||
- sig: monitorenter
|
||||
acc: in:ref
|
||||
|
||||
- sig: monitorexit
|
||||
acc: in:ref
|
||||
|
||||
+1
-3
@@ -100,7 +100,7 @@ module PandaBuiltins
|
||||
|
||||
id = 0 unless all_builtins[i - 1][:insn] == all_builtins[i][:insn]
|
||||
end
|
||||
all_builtins[all_builtins.length() - 1][:id] = id
|
||||
all_builtins[all_builtins.length() - 1][:id] = id if all_builtins.any?
|
||||
|
||||
all_builtins
|
||||
end
|
||||
@@ -214,11 +214,9 @@ end
|
||||
|
||||
module ExtBuiltins
|
||||
def self.load_ecma_builtins(data); end
|
||||
def self.load_polymorphic_builtins(data); end
|
||||
end
|
||||
|
||||
def Gen.on_require(data)
|
||||
ExtBuiltins.load_polymorphic_builtins(data)
|
||||
ExtBuiltins.load_ecma_builtins(data)
|
||||
prepared_data = prepare_data(data)
|
||||
PandaBuiltins.wrap_data(prepared_data)
|
||||
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env ruby
|
||||
# Copyright (c) 2021 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.
|
||||
|
||||
require 'optparse'
|
||||
require 'ostruct'
|
||||
require 'yaml'
|
||||
|
||||
def data_instructions(data)
|
||||
data['groups'].flat_map { |g| g['instructions'] }
|
||||
end
|
||||
|
||||
options = OpenStruct.new
|
||||
optparser = OptionParser.new do |opts|
|
||||
opts.banner = 'Usage: combine.rb [options]'
|
||||
|
||||
opts.on('-d', '--data FILE1,FILE2,...', Array, 'List of source data files in YAML format')
|
||||
opts.on('-o', '--output FILE', 'Output file (default is stdout)')
|
||||
|
||||
opts.on('-h', '--help', 'Prints this help') do
|
||||
puts opts
|
||||
exit
|
||||
end
|
||||
end
|
||||
optparser.parse!(into: options)
|
||||
|
||||
exit unless options.data
|
||||
exit if options.data.empty?
|
||||
|
||||
# TODO: Unify check with combining loop when we have assigned opcodes
|
||||
options.data.drop(1).each do |path|
|
||||
tmp_data = YAML.load_file(File.expand_path(path))
|
||||
# check that all instructions are prefixed:
|
||||
instructions = data_instructions(tmp_data)
|
||||
raise 'Plugged in instructions must be prefixed' unless instructions.reject { |i| i['prefix'] }.empty?
|
||||
end
|
||||
|
||||
# TODO: Remove when we have assigned opcodes:
|
||||
options.data = options.data.rotate # put plug-in prefixes first
|
||||
|
||||
data = YAML.load_file(File.expand_path(options.data.first))
|
||||
options.data.drop(1).each do |path|
|
||||
tmp_data = YAML.load_file(File.expand_path(path))
|
||||
%w[prefixes groups properties exceptions verification version min_version chapters].each do |attr|
|
||||
if data[attr]
|
||||
data[attr] += tmp_data[attr] if tmp_data[attr]
|
||||
else
|
||||
data[attr] = tmp_data[attr]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
output = options.output ? File.open(File.expand_path(options.output), 'w') : $stdout
|
||||
output.write(data.to_yaml)
|
||||
output.close
|
||||
+718
-359
File diff suppressed because it is too large
Load Diff
+138
-56
@@ -14,6 +14,13 @@
|
||||
require 'delegate'
|
||||
require 'ostruct'
|
||||
require 'digest'
|
||||
require 'set'
|
||||
|
||||
module Enumerable
|
||||
def stable_sort_by
|
||||
sort_by.with_index { |x, idx| [yield(x), idx] }
|
||||
end
|
||||
end
|
||||
|
||||
module Util
|
||||
module_function
|
||||
@@ -88,6 +95,11 @@ class Instruction < SimpleDelegator
|
||||
Panda.prefixes_hash[name] if name
|
||||
end
|
||||
|
||||
# Suggested handler name
|
||||
def handler_name
|
||||
opcode.upcase
|
||||
end
|
||||
|
||||
def opcode_idx
|
||||
if prefix
|
||||
dig(:opcode_idx) << 8 | prefix.opcode_idx
|
||||
@@ -161,8 +173,8 @@ class Instruction < SimpleDelegator
|
||||
!exceptions.include? 'x_none'
|
||||
end
|
||||
|
||||
def public?
|
||||
!/^builtin\./.match(mnemonic)
|
||||
def builtin?
|
||||
/^builtin\./.match(mnemonic)
|
||||
end
|
||||
|
||||
# Size of source operand
|
||||
@@ -174,6 +186,24 @@ class Instruction < SimpleDelegator
|
||||
cached def dest_op_size
|
||||
dtype[1..-1].to_i
|
||||
end
|
||||
|
||||
def namespace
|
||||
dig(:namespace) || "core"
|
||||
end
|
||||
end
|
||||
|
||||
class Prefix < SimpleDelegator
|
||||
# Suggested handler name
|
||||
def handler_name
|
||||
name.upcase
|
||||
end
|
||||
end
|
||||
|
||||
# Dummy class for invalid handlers
|
||||
class Invalid
|
||||
def handler_name
|
||||
'INVALID'
|
||||
end
|
||||
end
|
||||
|
||||
# Methods over format names
|
||||
@@ -238,7 +268,7 @@ class Operand
|
||||
end
|
||||
|
||||
@srcdst = srcdst.to_sym || :in
|
||||
types = %i[none u1 u2 i8 u8 i16 u16 i32 u32 f32 i64 u64 b64 f64 ref top any]
|
||||
types = %i[none u1 u2 i8 u8 i16 u16 i32 u32 b32 f32 i64 u64 b64 f64 ref top any]
|
||||
raise "Incorrect type #{type}" unless types.include?(type.sub('[]', '').to_sym)
|
||||
|
||||
@type = type
|
||||
@@ -279,33 +309,28 @@ end
|
||||
class DispatchTable
|
||||
# Canonical order of dispatch table consisting of
|
||||
# * non-prefixed instructions handlers
|
||||
# * invalid handlers
|
||||
# * prefix handlers that re-dispatch to prefixed instruction based on second byte of opcode_idx
|
||||
# * prefixed instructions handlers, in the order of prefixes
|
||||
# Return array with proposed handler names
|
||||
def handler_names
|
||||
names = Panda.instructions.reject(&:prefix).map { |i| instruction_handler_name(i) } +
|
||||
Panda.prefixes.map { |p| prefix_hanlder_name(p) }
|
||||
handlers = Panda.instructions.reject(&:prefix) +
|
||||
Array.new(invalid_non_prefixed_interval.size, Invalid.new) +
|
||||
Panda.prefixes.select(&:public?) +
|
||||
Array.new(invalid_prefixes_interval.size, Invalid.new) +
|
||||
Panda.prefixes.reject(&:public?) +
|
||||
Panda.instructions.select(&:prefix).stable_sort_by { |i| Panda.prefixes_hash[i.prefix.name].opcode_idx }
|
||||
|
||||
Panda.prefixes.each do |p|
|
||||
Panda.instructions.select { |i| i.prefix && (i.prefix.name == p.name) }.each do |i|
|
||||
names << instruction_handler_name(i)
|
||||
end
|
||||
end
|
||||
|
||||
names
|
||||
handlers.map(&:handler_name)
|
||||
end
|
||||
|
||||
def instruction_handler_name(insn)
|
||||
insn.opcode.upcase
|
||||
def invalid_non_prefixed_interval
|
||||
(Panda.instructions.reject(&:prefix).map(&:opcode_idx).max + 1)..(Panda.prefixes.map(&:opcode_idx).min - 1)
|
||||
end
|
||||
|
||||
def prefix_hanlder_name(prefix)
|
||||
prefix.name.upcase
|
||||
end
|
||||
|
||||
# Maximum value for primary dispatch index, i.e. the maximum value of first byte of opcode_idx
|
||||
def primary_opcode_bound
|
||||
Panda.prefixes.map(&:opcode_idx).max
|
||||
def invalid_prefixes_interval
|
||||
max_invalid_idx = Panda.prefixes.reject(&:public?).map(&:opcode_idx).min || 256
|
||||
(Panda.prefixes.select(&:public?).map(&:opcode_idx).max + 1)..(max_invalid_idx - 1)
|
||||
end
|
||||
|
||||
# Maximum value for secondary dispatch index for given prefix name
|
||||
@@ -317,8 +342,7 @@ class DispatchTable
|
||||
# Offset in dispatch table for handlers of instructions for given prefix name
|
||||
def secondary_opcode_offset(prefix)
|
||||
@prefix_data ||= prefix_data
|
||||
@first_prefixed_idx ||= first_prefixed_idx
|
||||
@first_prefixed_idx + @prefix_data[prefix.name][:delta]
|
||||
256 + @prefix_data[prefix.name][:delta]
|
||||
end
|
||||
|
||||
private
|
||||
@@ -331,9 +355,45 @@ class DispatchTable
|
||||
cur_delta += prefix_instructions_num
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def first_prefixed_idx
|
||||
Panda.instructions.reject(&:prefix).size + Panda.prefixes.size
|
||||
# Auxilary classes for opcode assignment
|
||||
class OpcodeAssigner
|
||||
def initialize
|
||||
@table = Hash.new { |h, k| h[k] = Set.new }
|
||||
@all_opcodes = Set.new(0..255)
|
||||
end
|
||||
|
||||
def consume(item)
|
||||
raise 'Cannot consume instruction without opcode' unless item.opcode_idx
|
||||
|
||||
@table[prefix(item)] << item.opcode_idx
|
||||
end
|
||||
|
||||
def yield_opcode(item)
|
||||
return item.opcode_idx if item.opcode_idx
|
||||
|
||||
opcodes = @table[prefix(item)]
|
||||
choose_opcode(opcodes)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def choose_opcode(occupied_opcodes)
|
||||
(@all_opcodes - occupied_opcodes).min
|
||||
end
|
||||
|
||||
def prefix(item)
|
||||
item.prefix.nil? ? 'non_prefixed' : item.prefix
|
||||
end
|
||||
end
|
||||
|
||||
class PrefixOpcodeAssigner < OpcodeAssigner
|
||||
private
|
||||
|
||||
# override opcodes assignment for prefixes
|
||||
def choose_opcode(occupied_opcodes)
|
||||
(@all_opcodes - occupied_opcodes).max
|
||||
end
|
||||
end
|
||||
|
||||
@@ -368,37 +428,33 @@ module Panda
|
||||
|
||||
# Hash from format names to Format instances
|
||||
cached def format_hash
|
||||
each_data_instruction_with_object([]) do |_, instruction, fmts|
|
||||
instruction.format.each do |f|
|
||||
fmts << [f, Format.new(f)]
|
||||
end
|
||||
each_data_instruction.with_object([]) do |instruction, fmts|
|
||||
fmt_name = instruction.format
|
||||
fmts << [fmt_name, Format.new(fmt_name)]
|
||||
end.to_h
|
||||
end
|
||||
|
||||
# Array of Instruction instances for every possible instruction
|
||||
cached def instructions
|
||||
opcode_idxs = Hash.new(0)
|
||||
# create separate instance for every instruction format and inherit group properties
|
||||
each_data_instruction_with_object([]) do |group, instruction, insns|
|
||||
props = group.to_h
|
||||
props.delete(:instructions)
|
||||
insn = props.merge(instruction.to_h) # instruction may override group props
|
||||
instruction.format.each do |f|
|
||||
insn[:format] = f
|
||||
prefix_key = insn[:prefix].nil? ? 'non_prefixed' : insn[:prefix]
|
||||
insn[:opcode_idx] = opcode_idxs[prefix_key]
|
||||
opcode_idxs[prefix_key] += 1
|
||||
insns << Instruction.new(OpenStruct.new(insn))
|
||||
end
|
||||
def instructions
|
||||
unless defined? @instructions
|
||||
opcodes = OpcodeAssigner.new
|
||||
tmp_public = initialize_instructions(opcodes) { |ins| !ins.opcode_idx.nil? }
|
||||
tmp_private = initialize_instructions(opcodes) { |ins| ins.opcode_idx.nil? }
|
||||
tmp = tmp_public + tmp_private
|
||||
@instructions = tmp.sort_by(&:opcode_idx)
|
||||
end
|
||||
@instructions
|
||||
end
|
||||
|
||||
cached def prefixes
|
||||
non_prefixed_num = groups.flat_map(&:instructions).reject(&:prefix).flat_map(&:format).size
|
||||
dig(:prefixes).each_with_index do |p, idx|
|
||||
p.opcode_idx = idx + non_prefixed_num
|
||||
def prefixes
|
||||
unless defined? @prefixes
|
||||
opcodes = PrefixOpcodeAssigner.new
|
||||
tmp_public = initialize_prefixes(opcodes) { |p| !p.opcode_idx.nil? }
|
||||
tmp_private = initialize_prefixes(opcodes) { |p| p.opcode_idx.nil? }
|
||||
tmp = tmp_public + tmp_private
|
||||
@prefixes = tmp.sort_by(&:opcode_idx)
|
||||
end
|
||||
dig(:prefixes)
|
||||
@prefixes
|
||||
end
|
||||
|
||||
cached def dispatch_table
|
||||
@@ -410,11 +466,6 @@ module Panda
|
||||
format_hash.values.uniq(&:pretty).sort_by(&:pretty)
|
||||
end
|
||||
|
||||
# 32-bit checksum of data YAML file
|
||||
def checksum
|
||||
Digest::MD5.hexdigest(@data.to_s).to_i(16) & 0xffffffff
|
||||
end
|
||||
|
||||
# delegating part of module
|
||||
#
|
||||
def wrap_data(data)
|
||||
@@ -441,11 +492,42 @@ module Panda
|
||||
hash
|
||||
end
|
||||
|
||||
private_class_method def each_data_instruction_with_object(object)
|
||||
groups.each_with_object(object) do |g, obj|
|
||||
private_class_method def each_data_instruction
|
||||
# create separate instance for every instruction format and inherit group properties
|
||||
@each_data_instruction ||= groups.each_with_object([]) do |g, obj|
|
||||
g.instructions.each do |i|
|
||||
yield(g, i, obj)
|
||||
props = g.to_h
|
||||
props.delete(:instructions)
|
||||
data_insn = props.merge(i.to_h) # instruction may override group props
|
||||
if data_insn[:opcode_idx] && (data_insn[:opcode_idx].size != data_insn[:format].size)
|
||||
raise 'format and opcode_idx arrays should have equal size'
|
||||
end
|
||||
|
||||
data_insn[:format].each_with_index do |f, idx|
|
||||
insn = data_insn.dup
|
||||
insn[:format] = f
|
||||
insn[:opcode_idx] = data_insn[:opcode_idx][idx] if data_insn[:opcode_idx]
|
||||
obj << OpenStruct.new(insn)
|
||||
end
|
||||
end
|
||||
end.to_enum
|
||||
end
|
||||
|
||||
private_class_method def initialize_instructions(opcodes, &block)
|
||||
each_data_instruction.select(&block).each_with_object([]) do |instruction, insns|
|
||||
instruction[:public?] = !instruction.opcode_idx.nil?
|
||||
instruction.opcode_idx = opcodes.yield_opcode(instruction)
|
||||
opcodes.consume(instruction)
|
||||
insns << Instruction.new(instruction)
|
||||
end
|
||||
end
|
||||
|
||||
private_class_method def initialize_prefixes(opcodes, &block)
|
||||
dig(:prefixes).select(&block).each_with_object([]) do |p, res|
|
||||
p[:public?] = !p.opcode_idx.nil?
|
||||
p.opcode_idx = opcodes.yield_opcode(p)
|
||||
opcodes.consume(p)
|
||||
res << Prefix.new(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ SECTIONS {
|
||||
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
|
||||
|
||||
.preinit_array : {
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
|
||||
@@ -358,4 +358,3 @@ SECTIONS {
|
||||
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "os/filesystem.h"
|
||||
#include "macros.h"
|
||||
#if defined PANDA_TARGET_MOBILE || defined PANDA_TARGET_LINUX || defined PANDA_TARGET_ARM32 ||\
|
||||
#if defined PANDA_TARGET_MOBILE || defined PANDA_TARGET_LINUX || defined PANDA_TARGET_ARM32 || \
|
||||
defined PANDA_TARGET_ARM64
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@ config("arkfile_public_config") {
|
||||
|
||||
libarkfile_sources = [
|
||||
"annotation_data_accessor.cpp",
|
||||
"ark_version.cpp",
|
||||
"file_format_version.cpp",
|
||||
"bytecode_emitter.cpp",
|
||||
"class_data_accessor.cpp",
|
||||
"code_data_accessor.cpp",
|
||||
@@ -64,7 +64,7 @@ ohos_shared_library("libarkfile") {
|
||||
":isa_gen_libarkfile_bytecode_emitter_gen_h",
|
||||
":isa_gen_libarkfile_bytecode_instruction-inl_gen_h",
|
||||
":isa_gen_libarkfile_bytecode_instruction_enum_gen_h",
|
||||
":isa_gen_libarkfile_isa_checksum_h",
|
||||
":isa_gen_libarkfile_file_format_version_h",
|
||||
":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h",
|
||||
":libarkfile_bytecode_builtin_enum_gen_h",
|
||||
":libarkfile_type_gen_h",
|
||||
@@ -90,7 +90,7 @@ ohos_static_library("libarkfile_frontend_static") {
|
||||
":isa_gen_libarkfile_bytecode_emitter_gen_h",
|
||||
":isa_gen_libarkfile_bytecode_instruction-inl_gen_h",
|
||||
":isa_gen_libarkfile_bytecode_instruction_enum_gen_h",
|
||||
":isa_gen_libarkfile_isa_checksum_h",
|
||||
":isa_gen_libarkfile_file_format_version_h",
|
||||
":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h",
|
||||
":libarkfile_bytecode_builtin_enum_gen_h",
|
||||
":libarkfile_type_gen_h",
|
||||
@@ -120,7 +120,7 @@ ark_isa_gen("isa_gen_libarkfile") {
|
||||
"bytecode_instruction-inl_gen.h.erb",
|
||||
"bytecode_emitter_def_gen.h.erb",
|
||||
"bytecode_emitter_gen.h.erb",
|
||||
"isa_checksum.h.erb",
|
||||
"file_format_version.h.erb",
|
||||
"tests/bytecode_emitter_tests_gen.h.erb",
|
||||
]
|
||||
sources = "templates" ## ark_root/templates
|
||||
|
||||
@@ -24,7 +24,7 @@ set(TEMPLATES
|
||||
bytecode_instruction-inl_gen.h.erb
|
||||
bytecode_emitter_def_gen.h.erb
|
||||
bytecode_emitter_gen.h.erb
|
||||
isa_checksum.h.erb
|
||||
file_format_version.h.erb
|
||||
tests/bytecode_emitter_tests_gen.h.erb
|
||||
)
|
||||
|
||||
@@ -69,7 +69,7 @@ set(SOURCES
|
||||
method_handle_data_accessor.cpp
|
||||
debug_info_extractor.cpp
|
||||
literal_data_accessor.cpp
|
||||
ark_version.cpp
|
||||
file_format_version.cpp
|
||||
)
|
||||
|
||||
add_library(arkfile ${PANDA_DEFAULT_LIB_TYPE} ${SOURCES})
|
||||
@@ -100,7 +100,7 @@ panda_add_gtest(
|
||||
tests/bytecode_emitter_tests.cpp
|
||||
tests/debug_info_extractor_test.cpp
|
||||
tests/panda_cache_test.cpp
|
||||
tests/ark_version_test.cpp
|
||||
tests/file_format_version_test.cpp
|
||||
LIBRARIES
|
||||
arkbase
|
||||
arkfile
|
||||
|
||||
@@ -248,6 +248,8 @@ public:
|
||||
return static_cast<unsigned>(GetOpcode()) & std::numeric_limits<uint8_t>::max();
|
||||
}
|
||||
|
||||
bool IsPrimaryOpcodeValid() const;
|
||||
|
||||
uint8_t GetSecondaryOpcode() const
|
||||
{
|
||||
// NOLINTNEXTLINE(hicpp-signed-bitwise)
|
||||
@@ -255,11 +257,6 @@ public:
|
||||
std::numeric_limits<uint8_t>::max();
|
||||
}
|
||||
|
||||
bool IsOpcodeEqual(Opcode opcode) const
|
||||
{
|
||||
return GetOpcode() == opcode;
|
||||
}
|
||||
|
||||
template <const BytecodeInstMode M = Mode>
|
||||
auto JumpTo(int32_t offset) const -> std::enable_if_t<M == BytecodeInstMode::FAST, BytecodeInst>
|
||||
{
|
||||
@@ -356,16 +353,7 @@ public:
|
||||
|
||||
bool IsTerminator() const
|
||||
{
|
||||
return HasFlag(Flags::RETURN) || HasFlag(Flags::JUMP) || IsOpcodeEqual(Opcode::THROW_V8);
|
||||
}
|
||||
|
||||
bool IsMonitor() const
|
||||
{
|
||||
if (!IsOpcodeEqual(Opcode::BUILTIN_ACC_IMM8)) {
|
||||
return false;
|
||||
}
|
||||
auto sub_opcode = static_cast<BUILTIN_ACC>(GetImm<Format::IMM8>());
|
||||
return BUILTIN_ACC::MONITORENTER_IMM8 == sub_opcode || BUILTIN_ACC::MONITOREXIT_IMM8 == sub_opcode;
|
||||
return HasFlag(Flags::RETURN) || HasFlag(Flags::JUMP) || (GetOpcode() == Opcode::THROW_V8);
|
||||
}
|
||||
|
||||
static constexpr bool HasId(Format format, size_t idx);
|
||||
|
||||
+29
-34
@@ -13,9 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ark_version.h"
|
||||
#include "file_format_version.h"
|
||||
#include "file-inl.h"
|
||||
#include "isa_checksum.h"
|
||||
#include "os/file.h"
|
||||
#include "os/mem.h"
|
||||
#include "mem/mem.h"
|
||||
@@ -36,6 +35,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
@@ -457,6 +457,19 @@ File::~File()
|
||||
AnonMemSet::GetInstance().Remove(FILENAME);
|
||||
}
|
||||
|
||||
inline std::string VersionToString(const std::array<uint8_t, File::VERSION_SIZE> &array)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
for (size_t i = 0; i < File::VERSION_SIZE - 1; ++i) {
|
||||
ss << static_cast<int>(array[i]);
|
||||
ss << ".";
|
||||
}
|
||||
ss << static_cast<int>(array[File::VERSION_SIZE - 1]);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::unique_ptr<const File> File::Open(std::string_view filename, OpenMode open_mode)
|
||||
{
|
||||
@@ -490,25 +503,23 @@ std::unique_ptr<const File> File::Open(std::string_view filename, OpenMode open_
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t isa_checksum = 0;
|
||||
if (!file.ReadAll(&isa_checksum, sizeof(uint32_t))) {
|
||||
LOG(ERROR, PANDAFILE) << "Failed to read isa's checksum of panda file '" << filename << "'";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::array<uint8_t, File::VERSION_SIZE> buf {};
|
||||
if (!file.ReadAll(&buf[0], buf.size())) {
|
||||
return nullptr;
|
||||
}
|
||||
std::array<uint8_t, File::VERSION_SIZE> min_version_local {0, 0, 0, 1};
|
||||
if (buf < min_version_local) {
|
||||
std::stringstream ss;
|
||||
ss << "Unable to open file '" << filename << "' with bytecode version " << buf[0U] << ".";
|
||||
ss << buf[1U] << "." << buf[2U] << "." << buf[3U] << ". Minimum supported version is ";
|
||||
ss << min_version_local[0U] << "." << min_version_local[1U] << "." << min_version_local[2U] << "."
|
||||
<< min_version_local[3U];
|
||||
LOG(ERROR, PANDAFILE) << ss.str();
|
||||
|
||||
if (buf < minVersion || buf > version) {
|
||||
LOG(ERROR, PANDAFILE) << "Unable to open file '" << filename
|
||||
<< "' with bytecode version " // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK)
|
||||
<< VersionToString(buf);
|
||||
if (buf < minVersion) {
|
||||
LOG(ERROR, PANDAFILE)
|
||||
<< "Minimum supported version is " // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK)
|
||||
<< VersionToString(minVersion);
|
||||
} else {
|
||||
LOG(ERROR, PANDAFILE)
|
||||
<< "Maximum supported version is " // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK)
|
||||
<< VersionToString(version);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -518,10 +529,6 @@ std::unique_ptr<const File> File::Open(std::string_view filename, OpenMode open_
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!CheckHeader(ptr, filename)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER, CPP_RULE_ID_NO_USE_NEW_UNIQUE_PTR)
|
||||
return std::unique_ptr<File>(new File(filename.data(), std::move(ptr)));
|
||||
}
|
||||
@@ -556,17 +563,13 @@ std::unique_ptr<const File> File::OpenUncompressedArchive(int fd, const std::str
|
||||
return std::unique_ptr<File>(new File(filename.data(), std::move(ptr)));
|
||||
}
|
||||
|
||||
bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename, bool check_isa_checksum)
|
||||
bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename)
|
||||
{
|
||||
auto header = reinterpret_cast<const File::Header *>(ptr.Get());
|
||||
if (header->magic != File::MAGIC) {
|
||||
LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'";
|
||||
return false;
|
||||
}
|
||||
if (check_isa_checksum && header->isa_checksum != ISA_CHECKSUM) {
|
||||
LOG(ERROR, PANDAFILE) << "Isa checksums mismatch in panda file '" << filename << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -580,10 +583,6 @@ std::unique_ptr<const File> File::OpenFromMemory(os::mem::ConstBytePtr &&ptr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!CheckHeader(ptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (header->file_size < sizeof(File::Header)) {
|
||||
LOG(ERROR, PANDAFILE) << "Invalid panda file";
|
||||
return nullptr;
|
||||
@@ -604,10 +603,6 @@ std::unique_ptr<const File> File::OpenFromMemory(os::mem::ConstBytePtr &&ptr, st
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!CheckHeader(ptr, filename)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (header->file_size < sizeof(File::Header)) {
|
||||
LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'";
|
||||
return nullptr;
|
||||
|
||||
+2
-4
@@ -44,7 +44,6 @@ public:
|
||||
struct Header {
|
||||
std::array<uint8_t, MAGIC_SIZE> magic;
|
||||
uint32_t checksum;
|
||||
uint32_t isa_checksum;
|
||||
std::array<uint8_t, VERSION_SIZE> version;
|
||||
uint32_t file_size;
|
||||
uint32_t foreign_off;
|
||||
@@ -367,10 +366,9 @@ std::unique_ptr<const panda_file::File> OpenPandaFileFromZipFILE(FILE *inputfile
|
||||
std::string_view archive_filename);
|
||||
|
||||
/*
|
||||
* Check ptr point valid panda file: magic/isa_checksum
|
||||
* Check ptr point valid panda file: magic
|
||||
*/
|
||||
bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename = "",
|
||||
bool check_isa_checksum = true);
|
||||
bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename = "");
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
extern const char *ARCHIVE_FILENAME;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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 "file_format_version.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
namespace panda::panda_file {
|
||||
|
||||
std::string GetVersion(const std::array<uint8_t, File::VERSION_SIZE> &v)
|
||||
{
|
||||
std::string versionstr;
|
||||
for (size_t i = 0; i < File::VERSION_SIZE; i++) {
|
||||
versionstr += std::to_string(v[i]);
|
||||
if (i == (File::VERSION_SIZE - 1)) {
|
||||
break;
|
||||
}
|
||||
versionstr += ".";
|
||||
}
|
||||
|
||||
return versionstr;
|
||||
}
|
||||
|
||||
} // namespace panda::panda_file
|
||||
@@ -15,11 +15,10 @@
|
||||
|
||||
#include "file_item_container.h"
|
||||
|
||||
#include "file_format_version.h"
|
||||
#include "file-inl.h"
|
||||
#include "helpers.h"
|
||||
#include "isa_checksum.h"
|
||||
#include "macros.h"
|
||||
#include "ark_version.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
@@ -586,11 +585,6 @@ bool ItemContainer::WriteHeader(Writer *writer, ssize_t *checksum_offset)
|
||||
}
|
||||
writer->CountChecksum(true);
|
||||
|
||||
uint32_t isa_checksum = ISA_CHECKSUM;
|
||||
if (!writer->Write(isa_checksum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> versionVec(std::begin(version), std::end(version));
|
||||
if (!writer->WriteBytes(versionVec)) {
|
||||
return false;
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
#define PANDA_LIBPANDAFILE_FILE_ITEMS_H_
|
||||
|
||||
#include "file.h"
|
||||
#include "file_format_version.h"
|
||||
#include "file_writer.h"
|
||||
#include "macros.h"
|
||||
#include "modifiers.h"
|
||||
#include "type.h"
|
||||
#include "ark_version.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -63,6 +63,9 @@ inline void LiteralDataAccessor::EnumerateLiteralVals(File::EntityId id, const C
|
||||
case LiteralTag::GENERATORMETHOD:
|
||||
value = static_cast<uint32_t>(helpers::Read<sizeof(uint32_t)>(&sp));
|
||||
break;
|
||||
case LiteralTag::METHODAFFILIATE:
|
||||
value = static_cast<uint16_t>(helpers::Read<sizeof(uint16_t)>(&sp));
|
||||
break;
|
||||
case LiteralTag::ACCESSOR:
|
||||
case LiteralTag::NULLVALUE:
|
||||
value = static_cast<uint8_t>(helpers::Read<sizeof(uint8_t)>(&sp));
|
||||
|
||||
@@ -37,14 +37,15 @@ enum class LiteralTag : uint8_t {
|
||||
METHOD = 0x06,
|
||||
GENERATORMETHOD = 0x07,
|
||||
ACCESSOR = 0x08,
|
||||
NULLVALUE = 0x09,
|
||||
METHODAFFILIATE = 0x09,
|
||||
ARRAY_I8 = 0x0a,
|
||||
ARRAY_I16 = 0x0b,
|
||||
ARRAY_I32 = 0x0c,
|
||||
ARRAY_I64 = 0x0d,
|
||||
ARRAY_F32 = 0x0e,
|
||||
ARRAY_F64 = 0x0f,
|
||||
ARRAY_STRING = 0x10
|
||||
ARRAY_STRING = 0x10,
|
||||
NULLVALUE = 0xff
|
||||
};
|
||||
|
||||
class LiteralDataAccessor {
|
||||
|
||||
@@ -373,3 +373,21 @@ inline bool BytecodeInst<Mode>::IsBuiltin() const
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <const BytecodeInstMode Mode>
|
||||
inline bool BytecodeInst<Mode>::IsPrimaryOpcodeValid() const
|
||||
{
|
||||
auto opcode = GetPrimaryOpcode();
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
if (((opcode >= <%= Panda::dispatch_table.invalid_non_prefixed_interval.min %>) &&
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
(opcode <= <%= Panda::dispatch_table.invalid_non_prefixed_interval.max %>)) ||
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
((opcode >= <%= Panda::dispatch_table.invalid_prefixes_interval.min %>) &&
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
(opcode <= <%= Panda::dispatch_table.invalid_prefixes_interval.max %>))) {
|
||||
// NOLINTNEXTLINE(readability-simplify-boolean-expr)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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_FILE_FORMAT_VERSION_H
|
||||
#define LIBPANDAFILE_FILE_FORMAT_VERSION_H
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "file.h"
|
||||
|
||||
namespace panda::panda_file {
|
||||
constexpr std::array<uint8_t, File::VERSION_SIZE> version {<%= Panda::version.split('.').join(', ') %>};
|
||||
constexpr std::array<uint8_t, File::VERSION_SIZE> minVersion {<%= Panda::min_version.split('.').join(', ') %>};
|
||||
|
||||
std::string GetVersion(const std::array<uint8_t, File::VERSION_SIZE> &version);
|
||||
|
||||
inline void PrintBytecodeVersion()
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "Bytecode version " << GetVersion(version) << '\n';
|
||||
ss << "Minimum supported bytecode version " << GetVersion(minVersion) << '\n';
|
||||
|
||||
std::cout << ss.str() << std::endl;
|
||||
}
|
||||
|
||||
} // namespace panda::panda_file
|
||||
|
||||
#endif
|
||||
@@ -746,4 +746,4 @@ void TestNoneFormat(Opcode opcode, std::function<void(BytecodeEmitter *)> emit)
|
||||
|
||||
#include <bytecode_emitter_tests_gen.h>
|
||||
|
||||
} // namespace panda
|
||||
} // namespace panda
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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 "file_format_version.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace panda::panda_file::test {
|
||||
TEST(File, TestGetVersion)
|
||||
{
|
||||
std::string versionstr;
|
||||
for (size_t i = 0; i < File::VERSION_SIZE; i++) {
|
||||
versionstr += std::to_string(version[i]);
|
||||
if (i == (File::VERSION_SIZE - 1)) {
|
||||
break;
|
||||
}
|
||||
versionstr += ".";
|
||||
}
|
||||
EXPECT_EQ(GetVersion(version), versionstr);
|
||||
}
|
||||
|
||||
TEST(File, GetMinVersion)
|
||||
{
|
||||
std::string versionstr;
|
||||
for (size_t i = 0; i < File::VERSION_SIZE; i++) {
|
||||
versionstr += std::to_string(minVersion[i]);
|
||||
if (i == (File::VERSION_SIZE - 1)) {
|
||||
break;
|
||||
}
|
||||
versionstr += ".";
|
||||
}
|
||||
EXPECT_EQ(GetVersion(minVersion), versionstr);
|
||||
}
|
||||
|
||||
} // namespace panda::panda_file::test
|
||||
@@ -19,9 +19,9 @@
|
||||
#include "debug_data_accessor-inl.h"
|
||||
#include "field_data_accessor-inl.h"
|
||||
#include "file.h"
|
||||
#include "file_format_version.h"
|
||||
#include "file_item_container.h"
|
||||
#include "file_writer.h"
|
||||
#include "isa_checksum.h"
|
||||
#include "helpers.h"
|
||||
#include "method_data_accessor-inl.h"
|
||||
#include "method_handle_data_accessor.h"
|
||||
@@ -95,8 +95,35 @@ TEST(ItemContainer, TestFileFormatVersionTooOld)
|
||||
|
||||
File::Header header = {};
|
||||
header.magic = File::MAGIC;
|
||||
header.isa_checksum = ISA_CHECKSUM;
|
||||
header.version = {0, 0, 0, 0};
|
||||
|
||||
auto old = std::array<uint8_t, File::VERSION_SIZE>(minVersion);
|
||||
--old[3];
|
||||
|
||||
header.version = old;
|
||||
header.file_size = sizeof(File::Header);
|
||||
|
||||
for (uint8_t b : Span<uint8_t>(reinterpret_cast<uint8_t *>(&header), sizeof(header))) {
|
||||
writer.WriteByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(File::Open(file_name), nullptr);
|
||||
}
|
||||
|
||||
TEST(ItemContainer, TestFileFormatVersionTooNew)
|
||||
{
|
||||
const std::string file_name = "test_file_format_version_too_new.abc";
|
||||
{
|
||||
ItemContainer container;
|
||||
auto writer = FileWriter(file_name);
|
||||
|
||||
File::Header header = {};
|
||||
header.magic = File::MAGIC;
|
||||
|
||||
auto new_ = std::array<uint8_t, File::VERSION_SIZE>(minVersion);
|
||||
++new_[3];
|
||||
|
||||
header.version = new_;
|
||||
header.file_size = sizeof(File::Header);
|
||||
|
||||
for (uint8_t b : Span<uint8_t>(reinterpret_cast<uint8_t *>(&header), sizeof(header))) {
|
||||
@@ -114,9 +141,9 @@ TEST(ItemContainer, TestFileFormatVersionValid)
|
||||
ItemContainer container;
|
||||
auto writer = FileWriter(file_name);
|
||||
|
||||
File::Header header = {};
|
||||
File::Header header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.magic = File::MAGIC;
|
||||
header.isa_checksum = ISA_CHECKSUM;
|
||||
header.version = {0, 0, 0, 2};
|
||||
header.file_size = sizeof(File::Header);
|
||||
|
||||
@@ -128,123 +155,6 @@ TEST(ItemContainer, TestFileFormatVersionValid)
|
||||
EXPECT_NE(File::Open(file_name), nullptr);
|
||||
}
|
||||
|
||||
TEST(ItemContainer, TestIsaChecksumMismatch)
|
||||
{
|
||||
using panda::os::file::Mode;
|
||||
using panda::os::file::Open;
|
||||
|
||||
// 1. Write panda file to disk
|
||||
|
||||
// 1.1. Create data members from ItemContainer
|
||||
|
||||
std::unordered_map<std::string, StringItem *> string_map;
|
||||
|
||||
std::map<std::string, BaseClassItem *> class_map;
|
||||
|
||||
std::unordered_map<uint32_t, ValueItem *> i_value_map;
|
||||
std::unordered_map<uint64_t, ValueItem *> l_value_map;
|
||||
std::unordered_map<float, ValueItem *> f_value_map;
|
||||
std::unordered_map<double, ValueItem *> d_value_map;
|
||||
std::unordered_map<BaseItem *, ValueItem *> id_value_map;
|
||||
|
||||
std::vector<std::unique_ptr<BaseItem>> items;
|
||||
std::vector<std::unique_ptr<BaseItem>> foreign_items;
|
||||
|
||||
// 1.2 Create a file handler
|
||||
|
||||
const std::string file_name = "test_isa_checksum_mismatch.panda";
|
||||
auto writer = FileWriter(file_name);
|
||||
|
||||
// 1.3 Body of function ItemContainer::ComputeLayout
|
||||
|
||||
uint32_t num_classes = class_map.size();
|
||||
uint32_t class_idx_offset = sizeof(File::Header);
|
||||
uint32_t cur_offset = class_idx_offset + num_classes * ID_SIZE;
|
||||
|
||||
for (auto &item : foreign_items) {
|
||||
cur_offset = RoundUp(cur_offset, item->Alignment());
|
||||
item->SetOffset(cur_offset);
|
||||
item->ComputeLayout();
|
||||
cur_offset += item->GetSize();
|
||||
}
|
||||
|
||||
for (auto &item : items) {
|
||||
if (!item->NeedsEmit()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cur_offset = RoundUp(cur_offset, item->Alignment());
|
||||
item->SetOffset(cur_offset);
|
||||
item->ComputeLayout();
|
||||
cur_offset += item->GetSize();
|
||||
}
|
||||
|
||||
uint32_t offset = cur_offset;
|
||||
|
||||
// 1.4 Body of function ItemContainer::Write
|
||||
|
||||
// Write header
|
||||
|
||||
std::vector<uint8_t> magic;
|
||||
magic.assign(File::MAGIC.cbegin(), File::MAGIC.cend());
|
||||
ASSERT_TRUE(writer.WriteBytes(magic));
|
||||
|
||||
uint32_t checksum = 0;
|
||||
ASSERT_TRUE(writer.Write(checksum));
|
||||
|
||||
uint32_t wrong_isa_checksum = 0;
|
||||
ASSERT_TRUE(writer.Write(wrong_isa_checksum));
|
||||
|
||||
std::vector<uint8_t> version {0, 0, 0, 1};
|
||||
ASSERT_TRUE(writer.WriteBytes(version));
|
||||
|
||||
ASSERT_TRUE(writer.Write(offset));
|
||||
|
||||
uint32_t foreign_offset = 0;
|
||||
if (!foreign_items.empty()) {
|
||||
foreign_offset = foreign_items.front()->GetOffset();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(writer.Write(foreign_offset));
|
||||
|
||||
uint32_t foreign_size = 0;
|
||||
if (!foreign_items.empty()) {
|
||||
size_t begin = foreign_items.front()->GetOffset();
|
||||
size_t end = foreign_items.back()->GetOffset() + foreign_items.back()->GetSize();
|
||||
|
||||
foreign_size = end - begin;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(writer.Write(foreign_size));
|
||||
ASSERT_TRUE(writer.Write<uint32_t>(class_map.size()));
|
||||
ASSERT_TRUE(writer.Write<uint32_t>(sizeof(File::Header)));
|
||||
|
||||
// Write class idx
|
||||
|
||||
for (auto &entry : class_map) {
|
||||
ASSERT_TRUE(writer.Write(entry.second->GetOffset()));
|
||||
}
|
||||
|
||||
for (auto &item : foreign_items) {
|
||||
ASSERT_TRUE(writer.Align(item->Alignment()));
|
||||
ASSERT_TRUE(item->Write(&writer));
|
||||
}
|
||||
|
||||
for (auto &item : items) {
|
||||
if (!item->NeedsEmit()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(writer.Align(item->Alignment()));
|
||||
ASSERT_TRUE(item->Write(&writer));
|
||||
}
|
||||
|
||||
// Read panda file from disk
|
||||
|
||||
auto ptr = File::Open(file_name);
|
||||
EXPECT_EQ(ptr, nullptr);
|
||||
}
|
||||
|
||||
static std::unique_ptr<const File> GetPandaFile(std::vector<uint8_t> &data)
|
||||
{
|
||||
os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(data.data()), data.size(),
|
||||
@@ -315,8 +225,7 @@ TEST(ItemContainer, TestClasses)
|
||||
|
||||
ASSERT_NE(panda_file, nullptr);
|
||||
|
||||
EXPECT_THAT(panda_file->GetHeader()->version, ::testing::ElementsAre(0, 0, 0, 1));
|
||||
EXPECT_EQ(panda_file->GetHeader()->isa_checksum, ISA_CHECKSUM);
|
||||
EXPECT_THAT(panda_file->GetHeader()->version, ::testing::ElementsAre(0, 0, 0, 2));
|
||||
EXPECT_EQ(panda_file->GetHeader()->file_size, mem_writer.GetData().size());
|
||||
EXPECT_EQ(panda_file->GetHeader()->foreign_off, 0U);
|
||||
EXPECT_EQ(panda_file->GetHeader()->foreign_size, 0U);
|
||||
|
||||
@@ -24,12 +24,7 @@ namespace panda::panda_file {
|
||||
|
||||
inline panda::panda_file::Type GetEffectiveType(const panda_file::Type &type)
|
||||
{
|
||||
auto type_id = type.GetId();
|
||||
if (type_id == panda_file::Type::TypeId::F32) {
|
||||
type_id = panda_file::Type::TypeId::F64;
|
||||
}
|
||||
|
||||
return panda_file::Type {type_id};
|
||||
return type;
|
||||
}
|
||||
|
||||
inline bool IsArrayDescriptor(const uint8_t *descriptor)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "libpandafile/file.h"
|
||||
#include "os/file.h"
|
||||
#include "os/mem.h"
|
||||
#include "isa_checksum.h"
|
||||
|
||||
#include "assembly-emitter.h"
|
||||
#include "assembly-parser.h"
|
||||
@@ -996,8 +995,6 @@ TEST(LIBZIPARCHIVE, OpenUncompressedArchiveFILE)
|
||||
// Delete the test archive, so it doesn't keep growing as we run this test
|
||||
remove(s_Test_archive_filename);
|
||||
|
||||
uint32_t *isa_checksum = reinterpret_cast<uint32_t *>(&pf_data[offsetof(panda_file::File::Header, isa_checksum)]);
|
||||
*isa_checksum = ISA_CHECKSUM;
|
||||
// ************* Create Zip file *************
|
||||
// Append a bunch of text files to the test archive
|
||||
for (i = (N - 1); i >= 0; --i) {
|
||||
|
||||
+3
-2
@@ -333,7 +333,6 @@ template("gen_intrinsics_yaml") {
|
||||
|
||||
action("$target_name") {
|
||||
script = "$ark_root/runtime/templates/gen_intrinsics_data.rb"
|
||||
|
||||
# rerun action when data file or template file update
|
||||
inputs = [ template_file ]
|
||||
inputs += invoker.data_files
|
||||
@@ -389,7 +388,7 @@ ark_isa_gen("isa_gen_libarkruntime") {
|
||||
extra_dependencies = builtin_labels
|
||||
}
|
||||
|
||||
isa = "$ark_root/isa/isa.yaml"
|
||||
isa = "$root_gen_dir/isa/isa.yaml"
|
||||
isa_api = "$ark_root/isa/isapi.rb"
|
||||
bridge_dispatch_template = "templates/bridge_dispatch.S.erb"
|
||||
bridge_archs = [
|
||||
@@ -411,6 +410,7 @@ foreach(arch, bridge_archs) {
|
||||
"templates/bridge_helpers_${arch}.rb",
|
||||
"templates/bridge_helpers_static.rb",
|
||||
]
|
||||
extra_dependencies = [ "$ark_root/isa:isa_combine" ]
|
||||
}
|
||||
|
||||
ark_gen_file("bridge_dispatch_dyn_${arch}") {
|
||||
@@ -422,6 +422,7 @@ foreach(arch, bridge_archs) {
|
||||
"templates/bridge_helpers_dynamic.rb",
|
||||
"templates/bridge_helpers_${arch}.rb",
|
||||
]
|
||||
extra_dependencies = [ "$ark_root/isa:isa_combine" ]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ panda_isa_gen(
|
||||
EXTRA_DEPENDENCIES ${builtin_headers}
|
||||
)
|
||||
|
||||
set(ISA "${PANDA_ROOT}/isa/isa.yaml")
|
||||
set(ISA "${CMAKE_BINARY_DIR}/isa/isa.yaml")
|
||||
set(ISA_API "${PANDA_ROOT}/isa/isapi.rb")
|
||||
set(BRIDGE_DISPATCH_TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/templates/bridge_dispatch.S.erb")
|
||||
set(BRIDGE_ARCHS aarch64 arm armhf amd64 x86)
|
||||
@@ -224,8 +224,8 @@ foreach(arch ${BRIDGE_ARCHS})
|
||||
REQUIRES ${ISA_API} ${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_${arch}.rb
|
||||
${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_static.rb
|
||||
)
|
||||
add_custom_target(bridge_dispatch_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_${arch}.S)
|
||||
|
||||
add_custom_target(bridge_dispatch_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_${arch}.S ${ISA})
|
||||
add_dependencies(bridge_dispatch_${arch} isa_assert)
|
||||
|
||||
panda_gen_file(
|
||||
DATAFILE ${ISA}
|
||||
@@ -233,7 +233,8 @@ foreach(arch ${BRIDGE_ARCHS})
|
||||
OUTPUTFILE ${GEN_INCLUDE_DIR}/bridge_dispatch_dyn_${arch}.S
|
||||
REQUIRES ${ISA_API} ${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_dynamic.rb ${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_${arch}.rb
|
||||
)
|
||||
add_custom_target(bridge_dispatch_dyn_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_dyn_${arch}.S)
|
||||
add_custom_target(bridge_dispatch_dyn_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_dyn_${arch}.S ${ISA})
|
||||
add_dependencies(bridge_dispatch_${arch} isa_assert)
|
||||
|
||||
endforeach()
|
||||
|
||||
|
||||
+10
-15
@@ -156,32 +156,27 @@ public:
|
||||
template <class T>
|
||||
T Read()
|
||||
{
|
||||
// The runtime alway operates with double so read double instead of float
|
||||
if constexpr (std::is_same<T, float>::value) { // NOLINT
|
||||
return static_cast<float>(*ReadPtr<double>());
|
||||
} else { // NOLINT
|
||||
return *ReadPtr<T>();
|
||||
}
|
||||
return *ReadPtr<T>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T *ReadPtr()
|
||||
{
|
||||
static_assert(!std::is_same<T, float>::value, "float variables are not supported");
|
||||
|
||||
constexpr size_t PTR_SIZE = ArchTraits<A>::POINTER_SIZE;
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
|
||||
if constexpr (std::is_same<T, double>::value) {
|
||||
if constexpr (std::is_same<T, double>::value || std::is_same<T, float>::value) {
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
|
||||
if constexpr (ExtArchTraits<A>::HARDFP) {
|
||||
const double *v;
|
||||
const T *v;
|
||||
size_t read_bytes = std::max(sizeof(T), ExtArchTraits<A>::FPR_SIZE);
|
||||
fp_arg_bytes_read_ = RoundUp(fp_arg_bytes_read_, read_bytes);
|
||||
if (fp_arg_bytes_read_ < ExtArchTraits<A>::FP_ARG_NUM_BYTES) {
|
||||
v = reinterpret_cast<const double *>(fpr_args_.data() + fp_arg_bytes_read_);
|
||||
fp_arg_bytes_read_ += sizeof(double);
|
||||
v = reinterpret_cast<const T *>(fpr_args_.data() + fp_arg_bytes_read_);
|
||||
fp_arg_bytes_read_ += read_bytes;
|
||||
} else {
|
||||
stack_args_ = AlignPtr<double>(stack_args_);
|
||||
v = reinterpret_cast<const double *>(stack_args_);
|
||||
stack_args_ += sizeof(double); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
stack_args_ = AlignPtr<T>(stack_args_);
|
||||
v = reinterpret_cast<const T *>(stack_args_);
|
||||
stack_args_ += read_bytes; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ InvokeCompiledCodeWithArgArrayDyn:
|
||||
.Linvoke_:
|
||||
// invoke the entrypoint
|
||||
blr lr
|
||||
|
||||
|
||||
sub sp, fp, 32
|
||||
ldp x19, THREAD_REG, [sp], 48
|
||||
CFI_RESTORE(THREAD_REG)
|
||||
|
||||
@@ -86,9 +86,10 @@
|
||||
strge \tmp1, [\stack_ptr], #4
|
||||
b \next_label
|
||||
|
||||
1: sub r2, r2, #SHORTY_FIRST_FLOAT
|
||||
cmp r2, #(SHORTY_NUM_FLOAT_TYPES - 1)
|
||||
bls 2f
|
||||
1: cmp r2, #SHORTY_F32
|
||||
beq 21f
|
||||
cmp r2, #SHORTY_F64
|
||||
beq 22f
|
||||
// it is a 64bit int
|
||||
// align
|
||||
bic \gpr_ptr, \gpr_ptr, #7
|
||||
@@ -104,10 +105,21 @@
|
||||
blt \next_label
|
||||
bge 3f
|
||||
|
||||
2: // it is a float
|
||||
21: // it is a float
|
||||
// determine whether there are free fp regs
|
||||
sub \tmp1, \fpr_ptr, r4
|
||||
cmp \tmp1, #64
|
||||
ldr \tmp1, [\arg_ptr]
|
||||
stmlt \fpr_ptr!, {\tmp1}
|
||||
stmge \stack_ptr!, {\tmp1}
|
||||
b \next_label
|
||||
|
||||
22: // it is a double
|
||||
// determine whether there are free fp regs
|
||||
add \fpr_ptr, \fpr_ptr, #7
|
||||
bic \fpr_ptr, \fpr_ptr, #7
|
||||
sub \tmp1, \fpr_ptr, r4
|
||||
cmp \tmp1, #64
|
||||
ldm \arg_ptr, {\tmp1, \tmp2}
|
||||
stmlt \fpr_ptr!, {\tmp1, \tmp2}
|
||||
blt \next_label
|
||||
@@ -261,7 +273,6 @@ PrepareArgStack:
|
||||
bicge sp, sp, #7
|
||||
subge sp, sp, #8
|
||||
b .Lloop_shorty
|
||||
|
||||
.Lexit:
|
||||
bic sp, sp, #7 // align sp
|
||||
sub r4, sp, r4, lsl #3
|
||||
@@ -391,25 +402,26 @@ InterpreterToCompiledCodeBridge:
|
||||
bpl .LU16
|
||||
cmp r2, #SHORTY_I8
|
||||
beq .LI8
|
||||
uxtb r0, r0
|
||||
uxtb r0, r0
|
||||
b .L32
|
||||
.LI8:
|
||||
.LI8:
|
||||
sxtb r0, r0
|
||||
b .L32
|
||||
.LI16:
|
||||
sxth r0, r0
|
||||
.LI16:
|
||||
sxth r0, r0
|
||||
b .L32
|
||||
.LU16:
|
||||
uxth r0, r0
|
||||
.LU16:
|
||||
uxth r0, r0
|
||||
.L32:
|
||||
// it is a 32bit value or reference
|
||||
str r0, [r3]
|
||||
b .Lreturn
|
||||
|
||||
.L64:
|
||||
sub r2, #SHORTY_FIRST_FLOAT
|
||||
cmp r2, #(SHORTY_NUM_FLOAT_TYPES - 1)
|
||||
vmovls.f64 r0, r1, d0
|
||||
cmp r2, #SHORTY_F64
|
||||
vmoveq.f64 r0, r1, d0
|
||||
cmp r2, #SHORTY_F32
|
||||
vmoveq.f32 r0, s0
|
||||
stm r3, {r0, r1}
|
||||
|
||||
.Lreturn:
|
||||
@@ -548,19 +560,22 @@ InvokeCompiledCodeWithArgArray:
|
||||
bpl .LU16_
|
||||
cmp r2, #SHORTY_I8
|
||||
beq .LI8_
|
||||
uxtb r0, r0
|
||||
uxtb r0, r0
|
||||
b .Lstore_result_
|
||||
.LI8_:
|
||||
.LI8_:
|
||||
sxtb r0, r0
|
||||
b .Lstore_result_
|
||||
.LI16_:
|
||||
sxth r0, r0
|
||||
.LI16_:
|
||||
sxth r0, r0
|
||||
b .Lstore_result_
|
||||
.LU16_:
|
||||
uxth r0, r0
|
||||
.LU16_:
|
||||
uxth r0, r0
|
||||
b .Lstore_result_
|
||||
.LFLOAT_:
|
||||
vmovls.f64 r0, r1, d0
|
||||
cmp r2, #SHORTY_F64
|
||||
vmoveq.f64 r0, r1, d0
|
||||
cmp r2, #SHORTY_F32
|
||||
vmoveq.f32 r0, s0
|
||||
|
||||
.Lstore_result_:
|
||||
// store the result r0,r1 into memory [r8]
|
||||
|
||||
@@ -152,7 +152,7 @@ InterpreterToCompiledCodeBridge:
|
||||
PREPARE_ARG_STACK
|
||||
|
||||
// setup regs and memory as follow
|
||||
// %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, (%esp) - insn_ptr,
|
||||
// %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, (%esp) - insn_ptr,
|
||||
// 8(%ebp) - iframe, 4(%esp) - iframe->vregs[], %edi - pointer to stack
|
||||
movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty*
|
||||
INIT_SHORTY_REG
|
||||
@@ -280,7 +280,7 @@ InterpreterToCompiledCodeBridge:
|
||||
|
||||
.Lreturn:
|
||||
leal -28(%ebp), %esp
|
||||
|
||||
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
@@ -334,10 +334,10 @@ InvokeCompiledCodeWithArgArray:
|
||||
movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty*
|
||||
INIT_SHORTY_REG
|
||||
|
||||
PREPARE_ARG_STACK
|
||||
PREPARE_ARG_STACK
|
||||
|
||||
// setup regs and memory as follow
|
||||
// %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, %esi - args[],
|
||||
// %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, %esi - args[],
|
||||
// %edi - pointer to stack
|
||||
movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty*
|
||||
INIT_SHORTY_REG
|
||||
@@ -379,7 +379,7 @@ InvokeCompiledCodeWithArgArray:
|
||||
movl %eax, (%esp)
|
||||
movl %edx, 4(%esp)
|
||||
// handle the first arg index
|
||||
PUSH_ARG %esi, %edi, %eax, %edx
|
||||
PUSH_ARG %esi, %edi, %eax, %edx
|
||||
movl (%esp), %eax
|
||||
movl 4(%esp), %edx
|
||||
|
||||
@@ -468,7 +468,7 @@ InvokeCompiledCodeWithArgArray:
|
||||
|
||||
.Lreturn_:
|
||||
leal -28(%ebp), %esp
|
||||
|
||||
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
|
||||
@@ -34,7 +34,6 @@ static Array *AllocateArray(panda::BaseClass *array_class, size_t elem_size, arr
|
||||
ThrowOutOfMemoryError("OOM when allocating array");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (LIKELY(space_type == panda::SpaceType::SPACE_TYPE_OBJECT)) {
|
||||
return static_cast<coretypes::Array *>(
|
||||
vm->GetHeapManager()->AllocateObject(array_class, size, DEFAULT_ALIGNMENT, MTManagedThread::GetCurrent()));
|
||||
|
||||
@@ -128,8 +128,8 @@ String *String::CreateFromUtf16(const uint16_t *utf16_data, uint32_t utf16_lengt
|
||||
if (can_be_compressed) {
|
||||
CopyUtf16AsMUtf8(utf16_data, string->GetDataMUtf8(), utf16_length);
|
||||
} else {
|
||||
if (memcpy_s(string->GetDataUtf16(), ComputeDataSizeUtf16(string->GetLength()), utf16_data,
|
||||
utf16_length << 1UL) != EOK) {
|
||||
if (utf16_length != 0 && memcpy_s(string->GetDataUtf16(), ComputeDataSizeUtf16(string->GetLength()), utf16_data,
|
||||
utf16_length << 1UL) != EOK) {
|
||||
LOG(FATAL, RUNTIME) << __func__ << " memcpy_s failed";
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "runtime/include/cframe.h"
|
||||
#include "runtime/include/method.h"
|
||||
#include "libpandafile/shorty_iterator.h"
|
||||
#include "utils/bit_utils.h"
|
||||
|
||||
namespace panda {
|
||||
|
||||
@@ -227,8 +228,7 @@ public:
|
||||
uint32_t vreg_num = num_args + (is_static ? 1 : 0);
|
||||
|
||||
return Range<CFrameJniMethodIterator>(
|
||||
CFrameJniMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, GPR_END_SLOT,
|
||||
FP_BEGIN_SLOT + 2, // 2
|
||||
CFrameJniMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, GPR_END_SLOT, FP_BEGIN_SLOT,
|
||||
FP_END_SLOT, STACK_BEGIN_SLOT),
|
||||
CFrameJniMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0));
|
||||
}
|
||||
@@ -242,8 +242,7 @@ public:
|
||||
{
|
||||
static_assert(arch::ExtArchTraits<Arch::AARCH32>::GPR_SIZE == 4); // 4 bytes -- register size on AARCH32
|
||||
|
||||
if (vreg_type == VRegInfo::Type::INT64 || vreg_type == VRegInfo::Type::FLOAT64 ||
|
||||
vreg_type == VRegInfo::Type::FLOAT32) {
|
||||
if (vreg_type == VRegInfo::Type::INT64 || vreg_type == VRegInfo::Type::FLOAT64) {
|
||||
return 2; // 2 slots
|
||||
}
|
||||
return 1;
|
||||
@@ -263,6 +262,11 @@ public:
|
||||
ptrdiff_t inc = GetSlotsCountForType(vreg_type_);
|
||||
ASSERT(inc == 1 || inc == 2); // 1 or 2 slots
|
||||
if (inc == 1) {
|
||||
if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
|
||||
if (vreg_type_ == VRegInfo::Type::FLOAT32) { // in this case one takes 1 slots
|
||||
return HandleHardFloat();
|
||||
}
|
||||
}
|
||||
if ((gpr_current_slot_ - 1) > gpr_end_slot_) {
|
||||
--gpr_current_slot_;
|
||||
current_slot_ = gpr_current_slot_;
|
||||
@@ -274,18 +278,8 @@ public:
|
||||
}
|
||||
} else {
|
||||
if constexpr (arch::ExtArchTraits<Arch::AARCH32>::HARDFP) {
|
||||
if (vreg_type_ == VRegInfo::Type::FLOAT32 ||
|
||||
vreg_type_ == VRegInfo::Type::FLOAT64) { // in this case one takes 2 slots
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_NESTING_LEVEL)
|
||||
if ((fp_current_slot_ - 2) > fp_end_slot_) {
|
||||
fp_current_slot_ -= 2;
|
||||
current_slot_ = fp_current_slot_;
|
||||
} else {
|
||||
stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2) - 1; // 2
|
||||
current_slot_ = stack_current_slot_;
|
||||
stack_current_slot_ -= 1;
|
||||
}
|
||||
return *this;
|
||||
if (vreg_type_ == VRegInfo::Type::FLOAT64) { // in this case one takes 2 slots
|
||||
return HandleHardDouble();
|
||||
}
|
||||
}
|
||||
gpr_current_slot_ = RoundUp(gpr_current_slot_ - 1, 2) - 1; // 2
|
||||
@@ -349,6 +343,7 @@ private:
|
||||
case panda_file::Type::TypeId::U32:
|
||||
return VRegInfo::Type::INT32;
|
||||
case panda_file::Type::TypeId::F32:
|
||||
return VRegInfo::Type::FLOAT32;
|
||||
case panda_file::Type::TypeId::F64:
|
||||
return VRegInfo::Type::FLOAT64;
|
||||
case panda_file::Type::TypeId::I64:
|
||||
@@ -364,6 +359,34 @@ private:
|
||||
return VRegInfo::Type::INT32;
|
||||
}
|
||||
|
||||
CFrameJniMethodIterator &HandleHardFloat()
|
||||
{
|
||||
ASSERT(vreg_type_ == VRegInfo::Type::FLOAT32);
|
||||
if (fp_current_slot_ > fp_end_slot_) {
|
||||
current_slot_ = fp_current_slot_;
|
||||
--fp_current_slot_;
|
||||
} else {
|
||||
--stack_current_slot_;
|
||||
current_slot_ = stack_current_slot_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CFrameJniMethodIterator &HandleHardDouble()
|
||||
{
|
||||
ASSERT(vreg_type_ == VRegInfo::Type::FLOAT64);
|
||||
fp_current_slot_ = RoundDown(static_cast<uintptr_t>(fp_current_slot_) + 1, 2U) - 1;
|
||||
if (fp_current_slot_ > fp_end_slot_) {
|
||||
current_slot_ = fp_current_slot_;
|
||||
fp_current_slot_ -= 2U;
|
||||
} else {
|
||||
stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2U) - 1;
|
||||
current_slot_ = stack_current_slot_;
|
||||
stack_current_slot_ -= 1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t vreg_index_;
|
||||
uint32_t vreg_num_;
|
||||
|
||||
@@ -53,7 +53,6 @@ inline TaggedType ReinterpretDoubleToTaggedType(double value)
|
||||
{
|
||||
return bit_cast<TaggedType>(value);
|
||||
}
|
||||
|
||||
inline double ReinterpretTaggedTypeToDouble(TaggedType value)
|
||||
{
|
||||
return bit_cast<double>(value);
|
||||
|
||||
@@ -430,7 +430,6 @@ public:
|
||||
UNREACHABLE();
|
||||
return stream;
|
||||
}
|
||||
|
||||
uint64_t GetTypeTag(interpreter::TypeTag tag) const
|
||||
{
|
||||
// return TypeTag default
|
||||
|
||||
@@ -119,6 +119,9 @@ Value Method::InvokeInterpretedCode(ManagedThread *thread, uint32_t num_actual_a
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
LOG(DEBUG, INTERPRETER) << "Invoke entry: " << GetFullName();
|
||||
|
||||
auto is_compiled = thread->IsCurrentFrameCompiled();
|
||||
thread->SetCurrentFrameIsCompiled(false);
|
||||
thread->SetCurrentFrame(frame.get());
|
||||
@@ -152,6 +155,8 @@ Value Method::InvokeInterpretedCode(ManagedThread *thread, uint32_t num_actual_a
|
||||
}
|
||||
thread->SetCurrentFrame(current_frame);
|
||||
res = GetReturnValueFromAcc(ret_type, thread->HasPendingException(), frame->GetAcc());
|
||||
|
||||
LOG(DEBUG, INTERPRETER) << "Invoke exit: " << GetFullName();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// All common ObjectHeader methods can be found here:
|
||||
// - Get/Set Mark or Class word
|
||||
// - Get size of the object header and an object itself
|
||||
|
||||
@@ -50,6 +50,11 @@ public:
|
||||
return (static_cast<unsigned>(GetInst().GetOpcode()) >> 8) & 0xff;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool IsPrimaryOpcodeValid() const
|
||||
{
|
||||
return GetInst().IsPrimaryOpcodeValid();
|
||||
}
|
||||
|
||||
void DumpVRegs()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
@@ -152,7 +157,7 @@ protected:
|
||||
|
||||
ALWAYS_INLINE void MoveToExceptionHandler()
|
||||
{
|
||||
SetOpcodeExtension(NUM_OPS + NUM_PREFIXES - 1);
|
||||
SetOpcodeExtension(UINT8_MAX + NUM_PREFIXED + 1);
|
||||
SetOpcodeExtension(GetOpcodeExtension() - GetPrimaryOpcode());
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,11 @@ public:
|
||||
return (static_cast<unsigned>(GetInst().GetOpcode()) >> 8) & 0xff;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool IsPrimaryOpcodeValid() const
|
||||
{
|
||||
return GetInst().IsPrimaryOpcodeValid();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE BytecodeInstruction GetInst() const
|
||||
{
|
||||
return state_.GetInst();
|
||||
|
||||
@@ -93,6 +93,13 @@ public:
|
||||
|
||||
#include "unimplemented_handlers-inl.h"
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleNop()
|
||||
{
|
||||
LOG_INST() << "nop";
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFldaiDyn()
|
||||
{
|
||||
@@ -177,6 +184,16 @@ public:
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFmovi()
|
||||
{
|
||||
auto imm = bit_cast<float>(this->GetInst().template GetImm<format>());
|
||||
uint16_t vd = this->GetInst().template GetVReg<format>();
|
||||
LOG_INST() << "fmovi v" << vd << ", " << imm;
|
||||
this->GetFrame()->GetVReg(vd).SetPrimitive(imm);
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFmoviWide()
|
||||
{
|
||||
@@ -241,6 +258,15 @@ public:
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFldai()
|
||||
{
|
||||
auto imm = bit_cast<float>(this->GetInst().template GetImm<format>());
|
||||
LOG_INST() << "fldai " << imm;
|
||||
this->GetAcc().SetPrimitive(imm);
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFldaiWide()
|
||||
{
|
||||
@@ -384,6 +410,13 @@ public:
|
||||
HandleBinaryOp2<format, uint64_t, math_helpers::cmp>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFcmpl()
|
||||
{
|
||||
LOG_INST() << "fcmpl ->";
|
||||
HandleBinaryOp2<format, float, math_helpers::fcmpl>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFcmplWide()
|
||||
{
|
||||
@@ -391,6 +424,13 @@ public:
|
||||
HandleBinaryOp2<format, double, math_helpers::fcmpl>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFcmpg()
|
||||
{
|
||||
LOG_INST() << "fcmpg ->";
|
||||
HandleBinaryOp2<format, float, math_helpers::fcmpg>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFcmpgWide()
|
||||
{
|
||||
@@ -524,6 +564,13 @@ public:
|
||||
HandleBinaryOp2<format, int64_t, math_helpers::Plus>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFadd2()
|
||||
{
|
||||
LOG_INST() << "fadd2 ->";
|
||||
HandleBinaryOp2<format, float, std::plus>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFadd2Wide()
|
||||
{
|
||||
@@ -545,6 +592,13 @@ public:
|
||||
HandleBinaryOp2<format, int64_t, math_helpers::Minus>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFsub2()
|
||||
{
|
||||
LOG_INST() << "fsub2 ->";
|
||||
HandleBinaryOp2<format, float, std::minus>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFsub2Wide()
|
||||
{
|
||||
@@ -566,6 +620,13 @@ public:
|
||||
HandleBinaryOp2<format, int64_t, math_helpers::Multiplies>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFmul2()
|
||||
{
|
||||
LOG_INST() << "fmul2 ->";
|
||||
HandleBinaryOp2<format, float, std::multiplies>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFmul2Wide()
|
||||
{
|
||||
@@ -573,6 +634,13 @@ public:
|
||||
HandleBinaryOp2<format, double, std::multiplies>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFdiv2()
|
||||
{
|
||||
LOG_INST() << "fdiv2 ->";
|
||||
HandleBinaryOp2<format, float, std::divides>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFdiv2Wide()
|
||||
{
|
||||
@@ -580,6 +648,13 @@ public:
|
||||
HandleBinaryOp2<format, double, std::divides>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFmod2()
|
||||
{
|
||||
LOG_INST() << "fmod2 ->";
|
||||
HandleBinaryOp2<format, float, math_helpers::fmodulus>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleFmod2Wide()
|
||||
{
|
||||
@@ -2228,174 +2303,6 @@ public:
|
||||
return panda_file::INVALID_OFFSET;
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinI32tof32()
|
||||
{ // builtin: 0x00 (acc)
|
||||
auto v = static_cast<float>(this->GetAcc().template GetAs<int32_t>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "i32tof32";
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(v));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinI64tof32()
|
||||
{ // builtin: 0x01 (acc)
|
||||
auto v = static_cast<float>(this->GetAcc().template GetAs<int64_t>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "i64tof32";
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(v));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinF64tof32()
|
||||
{ // builtin: 0x02 (acc)
|
||||
auto v = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "f64tof32";
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(v));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinMonitorenter()
|
||||
{ // builtin: 0x03 (acc)
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "monitorenter";
|
||||
|
||||
this->GetFrame()->SetAcc(this->GetAcc());
|
||||
panda::intrinsics::ObjectMonitorEnter(this->GetAcc().GetReference());
|
||||
this->GetAcc() = this->GetFrame()->GetAcc();
|
||||
|
||||
if (UNLIKELY(this->GetThread()->HasPendingException())) {
|
||||
this->MoveToExceptionHandler();
|
||||
} else {
|
||||
this->template MoveToNextInst<format, true>();
|
||||
}
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinMonitorexit()
|
||||
{ // builtin: 0x04 (acc)
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "monitorexit";
|
||||
|
||||
panda::intrinsics::ObjectMonitorExit(this->GetAcc().GetReference());
|
||||
|
||||
if (UNLIKELY(this->GetThread()->HasPendingException())) {
|
||||
this->MoveToExceptionHandler();
|
||||
} else {
|
||||
this->template MoveToNextInst<format, true>();
|
||||
}
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinFadd2f32()
|
||||
{ // builtin: 0x00 (bin2)
|
||||
auto v1 = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
auto vs = this->GetInst().template GetVReg<format>();
|
||||
auto v2 = static_cast<float>(this->GetFrame()->GetVReg(vs).template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "fadd2f32 v" << vs;
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(v1 + v2));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinFsub2f32()
|
||||
{ // builtin: 0x01 (bin2)
|
||||
auto v1 = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
auto vs = this->GetInst().template GetVReg<format>();
|
||||
auto v2 = static_cast<float>(this->GetFrame()->GetVReg(vs).template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "fsub2f32 v" << vs;
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(v1 - v2));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinFmul2f32()
|
||||
{ // builtin: 0x02 (bin2)
|
||||
auto v1 = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
auto vs = this->GetInst().template GetVReg<format>();
|
||||
auto v2 = static_cast<float>(this->GetFrame()->GetVReg(vs).template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "fmul2f32 v" << vs;
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(v1 * v2));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinFdiv2f32()
|
||||
{ // builtin: 0x03 (bin2)
|
||||
auto v1 = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
auto vs = this->GetInst().template GetVReg<format>();
|
||||
auto v2 = static_cast<float>(this->GetFrame()->GetVReg(vs).template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "fdiv2f32 v" << vs;
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(v1 / v2));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinFmod2f32()
|
||||
{ // builtin: 0x04 (bin2)
|
||||
auto v1 = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
auto vs = this->GetInst().template GetVReg<format>();
|
||||
auto v2 = static_cast<float>(this->GetFrame()->GetVReg(vs).template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "fmod2f32 v" << vs;
|
||||
|
||||
this->GetAcc().Set(static_cast<double>(std::fmod(v1, v2)));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinFcmpl2f32()
|
||||
{ // builtin: 0x05 (bin2)
|
||||
auto v1 = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
auto vs = this->GetInst().template GetVReg<format>();
|
||||
auto v2 = static_cast<float>(this->GetFrame()->GetVReg(vs).template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "fcmplf32 v" << vs;
|
||||
|
||||
this->GetAcc().Set(static_cast<int64_t>(math_helpers::fcmpl<float>()(v1, v2)));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
template <BytecodeInstruction::Format format>
|
||||
ALWAYS_INLINE void HandleBuiltinFcmpg2f32()
|
||||
{ // builtin: 0x06 (bin2)
|
||||
auto v1 = static_cast<float>(this->GetAcc().template GetAs<double>());
|
||||
auto vs = this->GetInst().template GetVReg<format>();
|
||||
auto v2 = static_cast<float>(this->GetFrame()->GetVReg(vs).template GetAs<double>());
|
||||
|
||||
LOG_INST() << "\t"
|
||||
<< "fcmpgf32 v" << vs;
|
||||
|
||||
this->GetAcc().Set(static_cast<int64_t>(math_helpers::fcmpg<float>()(v1, v2)));
|
||||
this->template MoveToNextInst<format, false>();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static bool IsCompilerEnableJit()
|
||||
{
|
||||
return !enable_instrumentation && RuntimeIfaceT::IsCompilerEnableJit();
|
||||
|
||||
@@ -21,10 +21,9 @@ HANDLE_<%= insn.opcode.upcase %>: {
|
||||
const auto builtin_id = state.GetInst().template GetImm<BytecodeInstruction::Format::<%= insn.format.upcase %>>();
|
||||
|
||||
LOG(DEBUG, INTERPRETER) << "Subdispatch: " << "<%= insn.mnemonic %>, " << builtin_id
|
||||
<< " (NUM_OPS=" << NUM_OPS << ", NUM_PREFIXES=" << NUM_PREFIXES
|
||||
<< " (NUM_PREFIXED=" << NUM_PREFIXED
|
||||
<< ", delta=" << <%= insn.delta %> << ")";
|
||||
|
||||
DISPATCH(GetDispatchTable(dispatch_table), NUM_OPS + NUM_PREFIXES + <%= insn.delta %> + builtin_id, label);
|
||||
DISPATCH(GetDispatchTable(dispatch_table), 256 + NUM_PREFIXED + 1 + <%= insn.delta %> + builtin_id, label);
|
||||
}
|
||||
% end
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) {
|
||||
PandaUniquePtr<void, decltype(method_exit_event)> method_exit(&method_exit_event, method_exit_event);
|
||||
#endif
|
||||
|
||||
static std::array<const void*, NUM_OPS + NUM_PREFIXES + NUM_BUILTINS> dispatch_table{
|
||||
static std::array<const void*, 256 + NUM_PREFIXED + 1 + NUM_BUILTINS> dispatch_table{
|
||||
% Panda::dispatch_table.handler_names.each do |name|
|
||||
&&HANDLE_<%= name %>,
|
||||
% end
|
||||
@@ -56,19 +56,22 @@ void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) {
|
||||
SetDispatchTable(dispatch_table);
|
||||
|
||||
InstructionHandlerState state(thread, pc, frame);
|
||||
|
||||
if constexpr (jump_to_eh) {
|
||||
goto EXCEPTION_HANDLER;
|
||||
}
|
||||
ASSERT(state.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>);
|
||||
ASSERT(state.IsPrimaryOpcodeValid());
|
||||
|
||||
const void *label;
|
||||
DISPATCH(GetDispatchTable(dispatch_table), state.GetPrimaryOpcode(), label);
|
||||
|
||||
% Panda::instructions.select(&:public?).each do |i|
|
||||
% Panda::instructions.reject(&:builtin?).each do |i|
|
||||
% mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join
|
||||
HANDLE_<%= Panda::dispatch_table.instruction_handler_name(i) %>: {
|
||||
InstructionHandler<RuntimeIfaceT, enable_instrumentation> handler(&state);
|
||||
HANDLE_<%= i.handler_name %>: {
|
||||
% namespace = i.namespace == 'core' ? '' : "#{i.namespace}::"
|
||||
% if i.namespace != 'core'
|
||||
#ifdef PANDA_WITH_<%= i.namespace.upcase %>
|
||||
% end
|
||||
<%= namespace %>InstructionHandler<RuntimeIfaceT, enable_instrumentation> handler(&state);
|
||||
INSTRUMENT_FRAME();
|
||||
handler.DumpVRegs();
|
||||
handler.InstrumentInstruction();
|
||||
@@ -79,25 +82,30 @@ HANDLE_<%= Panda::dispatch_table.instruction_handler_name(i) %>: {
|
||||
% if i.properties.include?('return')
|
||||
if (handler.GetFrame()->IsStackless()) {
|
||||
handler.HandleReturnStackless();
|
||||
ASSERT(handler.GetExceptionOpcode() < NUM_OPS + NUM_PREFIXES);
|
||||
ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1));
|
||||
DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
% else
|
||||
% if !i.exceptions.include?('x_none') || i.properties.include?("call") || ['ststatic', 'ldstatic', 'throw', 'lda'].include?(i.stripped_mnemonic)
|
||||
ASSERT(handler.GetExceptionOpcode() < NUM_OPS + NUM_PREFIXES);
|
||||
ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1));
|
||||
DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label);
|
||||
% else
|
||||
ASSERT(handler.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>);
|
||||
ASSERT(handler.IsPrimaryOpcodeValid());
|
||||
DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label);
|
||||
% end
|
||||
% end
|
||||
% if i.namespace != 'core'
|
||||
#endif // PANDA_WITH_<%= i.namespace.upcase %>
|
||||
% end
|
||||
}
|
||||
% end
|
||||
|
||||
HANDLE_INVALID: {
|
||||
LOG(FATAL,INTERPRETER) << "Incorrect opcode";
|
||||
}
|
||||
% Panda::prefixes.each do |p|
|
||||
HANDLE_<%= Panda::dispatch_table.prefix_hanlder_name(p) %>: {
|
||||
HANDLE_<%= p.handler_name %>: {
|
||||
const auto secondary_opcode = state.GetSecondaryOpcode();
|
||||
|
||||
LOG(DEBUG, INTERPRETER) << "Prefix subdispatch: " << "<%= p.name %>, " << secondary_opcode;
|
||||
@@ -123,7 +131,7 @@ INSTRUMENT_FRAME_HANDLER: {
|
||||
handler.InstrumentForceReturn();
|
||||
if (handler.GetFrame()->IsStackless()) {
|
||||
handler.HandleInstrumentForceReturn();
|
||||
ASSERT(handler.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>);
|
||||
ASSERT(handler.IsPrimaryOpcodeValid());
|
||||
DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label);
|
||||
} else {
|
||||
return;
|
||||
@@ -133,8 +141,7 @@ INSTRUMENT_FRAME_HANDLER: {
|
||||
handler.GetFrame()->ClearRetryInstruction();
|
||||
auto* method = handler.GetFrame()->GetMethod();
|
||||
state = InstructionHandlerState(thread, method->GetInstructions() + handler.GetFrame()->GetBytecodeOffset(), handler.GetFrame());
|
||||
|
||||
ASSERT(state.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>);
|
||||
ASSERT(state.IsPrimaryOpcodeValid());
|
||||
goto* dispatch_table[state.GetPrimaryOpcode()];
|
||||
}
|
||||
|
||||
@@ -167,7 +174,7 @@ EXCEPTION_HANDLER: {
|
||||
Span<const uint8_t> sp(handler.GetFrame()->GetMethod()->GetInstructions(), pc_offset);
|
||||
state = InstructionHandlerState(thread, sp.cend(), handler.GetFrame());
|
||||
|
||||
ASSERT(state.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>);
|
||||
ASSERT(state.IsPrimaryOpcodeValid());
|
||||
goto* dispatch_table[state.GetPrimaryOpcode()];
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,10 @@
|
||||
#define PANDA_RUNTIME_INCLUDE_ISA_CONSTANTS_GEN_H_
|
||||
|
||||
namespace panda::interpreter {
|
||||
|
||||
constexpr auto NUM_OPS = <%= Panda::instructions.size %> + 1; // +1 is for EXCEPTION_HANDLER
|
||||
constexpr auto NUM_PREFIXES = <%= Panda::prefixes.size %>;
|
||||
constexpr auto NUM_PREFIXED = <%= Panda::instructions.select(&:prefix).size %>;
|
||||
static_assert(NUM_OPS - NUM_PREFIXED + NUM_PREFIXES <= 210, "Too many first-level-dispatch opcodes in use, please review the ISA");
|
||||
|
||||
constexpr auto NUM_PREFIXED = <%= Panda::instructions.select(&:prefix).size %>;
|
||||
constexpr auto NUM_NON_PREFIXED_OPS = <%= Panda::instructions.size %> - NUM_PREFIXED + 1; // +1 is for EXCEPTION_HANDLER
|
||||
constexpr auto NUM_PREFIXES = <%= Panda::prefixes.size %>;
|
||||
static_assert(NUM_NON_PREFIXED_OPS + NUM_PREFIXES <= 210, "Too many first-level-dispatch opcodes in use, please review the ISA");
|
||||
} // namespace panda::interpreter
|
||||
|
||||
#endif // PANDA_RUNTIME_INCLUDE_ISA_CONSTANTS_GEN_H_
|
||||
|
||||
@@ -146,6 +146,13 @@ public:
|
||||
SetValue(v);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE inline void Set(float value)
|
||||
{
|
||||
ASSERT(!HasObject());
|
||||
auto v = bit_cast<int32_t>(value);
|
||||
SetValue(v);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE inline void Set(double value)
|
||||
{
|
||||
ASSERT(!HasObject());
|
||||
@@ -172,6 +179,13 @@ public:
|
||||
MarkAsPrimitive();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE inline void SetPrimitive(float value)
|
||||
{
|
||||
auto v = bit_cast<int32_t>(value);
|
||||
SetValue(v);
|
||||
MarkAsPrimitive();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE inline void SetPrimitive(double value)
|
||||
{
|
||||
auto v = bit_cast<int64_t>(value);
|
||||
@@ -188,7 +202,7 @@ public:
|
||||
ALWAYS_INLINE inline float GetFloat() const
|
||||
{
|
||||
ASSERT(!HasObject());
|
||||
return static_cast<float>(bit_cast<double>(GetValue()));
|
||||
return bit_cast<float>(Get());
|
||||
}
|
||||
|
||||
ALWAYS_INLINE inline int64_t GetLong() const
|
||||
@@ -245,6 +259,7 @@ public:
|
||||
values << "obj = " << std::hex << GetValue();
|
||||
} else {
|
||||
values << "pri = (i64) " << GetValue() << " | "
|
||||
<< "(f32) " << GetFloat() << " | "
|
||||
<< "(f64) " << GetDouble() << " | "
|
||||
<< "(hex) " << std::hex << GetValue();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Our main goal is to have similar interface for two different platforms - high-end and low-end.
|
||||
//
|
||||
// 64 bits object header for high-end devices: (64 bits pointer)
|
||||
@@ -80,7 +79,6 @@
|
||||
// |-----------------------------------------------------|--------------------------------|--------------------|
|
||||
// | Forwarding address:14 | state:11 | OOP to metadata object | GC |
|
||||
// |-----------------------------------------------------|--------------------------------|--------------------|
|
||||
|
||||
#ifndef PANDA_RUNTIME_MARK_WORD_H_
|
||||
#define PANDA_RUNTIME_MARK_WORD_H_
|
||||
|
||||
|
||||
@@ -446,7 +446,6 @@ ObjectAllocatorGen<MTMode>::~ObjectAllocatorGen()
|
||||
delete non_movable_object_allocator_;
|
||||
delete large_non_movable_object_allocator_;
|
||||
}
|
||||
|
||||
template <MTModeT MTMode>
|
||||
size_t ObjectAllocatorGen<MTMode>::GetRegularObjectMaxSize()
|
||||
{
|
||||
|
||||
@@ -206,5 +206,4 @@ inline bool FrameAllocator<AlignmenT, UseMemsetT>::Contains(void *mem)
|
||||
#undef LOG_FRAME_ALLOCATOR
|
||||
|
||||
} // namespace panda::mem
|
||||
|
||||
#endif // PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H_
|
||||
|
||||
@@ -429,7 +429,7 @@ void GC::PreStartup()
|
||||
// Add a delay GCTask.
|
||||
if ((!Runtime::GetCurrent()->IsZygote()) && (!gc_settings_.run_gc_in_place)) {
|
||||
// divide 2 to temporarily set target footprint to a high value to disable GC during App startup.
|
||||
GetPandaVm()->GetGCTrigger()->SetMinTargetFootprint(Runtime::GetOptions().GetObjectPoolSize() / 2);
|
||||
GetPandaVm()->GetGCTrigger()->SetMinTargetFootprint(Runtime::GetOptions().GetHeapSizeLimit() / 2);
|
||||
PreStartupImp();
|
||||
constexpr uint64_t DISABLE_GC_DURATION_NS = 2000 * 1000 * 1000;
|
||||
auto task = MakePandaUnique<PostForkGCTask>(GCTaskCause::STARTUP_COMPLETE_CAUSE,
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#include "runtime/timing.h"
|
||||
|
||||
namespace panda {
|
||||
|
||||
class BaseClass;
|
||||
class Class;
|
||||
class HClass;
|
||||
|
||||
@@ -230,4 +230,4 @@ private:
|
||||
|
||||
} // namespace panda::mem
|
||||
|
||||
#endif // PANDA_RUNTIME_MEM_GC_GC_STATS_H_
|
||||
#endif // PANDA_RUNTIME_MEM_GC_GC_STATS_H
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "runtime/mem/gc/gc_phase.h"
|
||||
|
||||
namespace panda {
|
||||
|
||||
class BaseClass;
|
||||
} // namespace panda
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "runtime/mem/mem_stats.h"
|
||||
|
||||
namespace panda {
|
||||
|
||||
class Class;
|
||||
} // namespace panda
|
||||
|
||||
|
||||
@@ -46,5 +46,4 @@ double MemStatsDefault::GetTotalGCPhaseTime([[maybe_unused]] GCPhase phase) cons
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace panda::mem
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "runtime/mem/mem_stats.h"
|
||||
|
||||
namespace panda {
|
||||
|
||||
class Class;
|
||||
} // namespace panda
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "runtime/mem/object_helpers-inl.h"
|
||||
|
||||
@@ -59,13 +59,22 @@ double PandaStringToD(const PandaString &str)
|
||||
return result;
|
||||
}
|
||||
|
||||
PandaString ConvertToString(Span<const uint8_t> sp)
|
||||
template <class T>
|
||||
PandaString ConvertToString(T sp)
|
||||
{
|
||||
PandaString res;
|
||||
res.reserve(sp.size());
|
||||
|
||||
// Also support ascii that great than 127, so using unsigned char here
|
||||
constexpr size_t MAX_CHAR = std::numeric_limits<unsigned char>::max();
|
||||
|
||||
for (auto c : sp) {
|
||||
if (c > MAX_CHAR) {
|
||||
return "";
|
||||
}
|
||||
res.push_back(c);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "runtime/mem/gc/bitmap.h"
|
||||
|
||||
namespace panda {
|
||||
|
||||
class ObjectHeader;
|
||||
} // namespace panda
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "global_object_storage.h"
|
||||
|
||||
#include <libpandabase/os/mutex.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ref_block.h"
|
||||
|
||||
namespace panda::mem {
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "runtime/mem/region_space.h"
|
||||
|
||||
namespace panda {
|
||||
|
||||
class ManagedThread;
|
||||
} // namespace panda
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "runtime/mem/region_space-inl.h"
|
||||
#include "runtime/mem/rem_set-inl.h"
|
||||
|
||||
|
||||
@@ -887,5 +887,4 @@ bool RunSlotsAllocator<AllocConfigT, LockConfigT>::MemPoolManager::PoolListEleme
|
||||
#undef LOG_RUNSLOTS_ALLOCATOR
|
||||
|
||||
} // namespace panda::mem
|
||||
|
||||
#endif // PANDA_RUNTIME_MEM_RUNSLOTS_ALLOCATOR_INL_H_
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_RUNTIME_OBJECT_ACCESSOR_IMPL_CPP_
|
||||
#define PANDA_RUNTIME_OBJECT_ACCESSOR_IMPL_CPP_
|
||||
// This file is included by interpreter to inline methods that defined in it.
|
||||
|
||||
+15
-10
@@ -314,25 +314,25 @@ options:
|
||||
default: true
|
||||
description: Enable/disable TLAB using for object allocations. Now, it is ignored for all GCs except GenGC. Temporary option for quick switch between modes.
|
||||
|
||||
- name: object-pool-size
|
||||
- name: heap-size-limit
|
||||
type: uint32_t
|
||||
default: 536870912
|
||||
description: Size of pool used for objects
|
||||
description: Max heap size
|
||||
|
||||
- name: internal-pool-size
|
||||
- name: internal-memory-size-limit
|
||||
type: uint64_t
|
||||
default: 2147483648
|
||||
description: Size of pool used for internal memory.
|
||||
description: Max internal memory used by the VM
|
||||
|
||||
- name: code-pool-size
|
||||
type: uint32_t
|
||||
- name: code-cache-size-limit
|
||||
type: uint64_t
|
||||
default: 33554432
|
||||
description: Size of pool used for compiled code memory
|
||||
description: The limit for compiled code size.
|
||||
|
||||
- name: compiler-pool-size
|
||||
type: uint32_t
|
||||
- name: compiler-memory-size-limit
|
||||
type: uint64_t
|
||||
default: 268435456
|
||||
description: Size of pool used for internal compiler memory
|
||||
description: Max memory used by the compiler
|
||||
|
||||
- name: print-memory-statistics
|
||||
type: bool
|
||||
@@ -547,3 +547,8 @@ options:
|
||||
type: bool
|
||||
default: false
|
||||
description: Print backtrace each time a thread gets suspended
|
||||
|
||||
- name: icu-data-path
|
||||
type: std::string
|
||||
default: "default"
|
||||
description: Path to generated icu data file
|
||||
|
||||
+2
-2
@@ -251,8 +251,8 @@ bool Runtime::Create(const RuntimeOptions &options, const std::vector<LanguageCo
|
||||
|
||||
trace::ScopedTrace scoped_trace("Runtime::Create");
|
||||
|
||||
panda::mem::MemConfig::Initialize(options.GetObjectPoolSize(), options.GetInternalPoolSize(),
|
||||
options.GetCompilerPoolSize(), options.GetCodePoolSize());
|
||||
panda::mem::MemConfig::Initialize(options.GetHeapSizeLimit(), options.GetInternalMemorySizeLimit(),
|
||||
options.GetCompilerMemorySizeLimit(), options.GetCodeCacheSizeLimit());
|
||||
PoolManager::Initialize();
|
||||
|
||||
mem::InternalAllocatorPtr internal_allocator =
|
||||
|
||||
@@ -25,6 +25,8 @@ def get_format_for(insn)
|
||||
end
|
||||
|
||||
def get_call_insns()
|
||||
return Panda::instructions.select {|insn| ((insn.properties.include? "call" or insn.stripped_mnemonic == "initobj") and !(insn.properties.include? "dynamic"))}
|
||||
Panda::instructions.reject(&:prefix).select do |insn|
|
||||
((insn.properties.include?("call") || insn.stripped_mnemonic == "initobj") && !(insn.properties.include? "dynamic"))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -69,52 +69,17 @@ def get_ret_type(type)
|
||||
end
|
||||
|
||||
def get_effective_type(type)
|
||||
@effective_type_map ||= {
|
||||
'void' => 'void',
|
||||
'u1' => 'uint8_t',
|
||||
'i8' => 'int8_t',
|
||||
'u8' => 'uint8_t',
|
||||
'i16' => 'int16_t',
|
||||
'u16' => 'uint16_t',
|
||||
'i32' => 'int32_t',
|
||||
'u32' => 'uint32_t',
|
||||
'i64' => 'int64_t',
|
||||
'u64' => 'uint64_t',
|
||||
'f32' => 'double',
|
||||
'f64' => 'double',
|
||||
'any' => ['int64_t', 'int64_t'],
|
||||
'acc' => ['int64_t', 'int64_t'],
|
||||
'string_id' => 'uint32_t',
|
||||
'method_id' => 'uint32_t',
|
||||
}
|
||||
@effective_type_map[type] || get_object_type(type)
|
||||
get_type(type)
|
||||
end
|
||||
|
||||
def get_ret_effective_type(type)
|
||||
@ret_effective_type_map ||= {
|
||||
'void' => 'void',
|
||||
'u1' => 'uint8_t',
|
||||
'i8' => 'int8_t',
|
||||
'u8' => 'uint8_t',
|
||||
'i16' => 'int16_t',
|
||||
'u16' => 'uint16_t',
|
||||
'i32' => 'int32_t',
|
||||
'u32' => 'uint32_t',
|
||||
'i64' => 'int64_t',
|
||||
'u64' => 'uint64_t',
|
||||
'f32' => 'double',
|
||||
'f64' => 'double',
|
||||
'any' => 'DecodedTaggedValue',
|
||||
'string_id' => 'uint32_t',
|
||||
'method_id' => 'uint32_t',
|
||||
'acc' => 'DecodedTaggedValue',
|
||||
}
|
||||
@ret_effective_type_map[type] || get_object_type(type)
|
||||
get_ret_type(type)
|
||||
end
|
||||
|
||||
class Intrinsic < SimpleDelegator
|
||||
def need_abi_wrapper?
|
||||
signature.ret == 'f32' || signature.args.include?('f32')
|
||||
Object.send(:get_ret_type, signature.ret) != Object.send(:get_ret_effective_type, signature.ret) ||
|
||||
signature.args.any? { |arg| Object.send(:get_ret_type, arg) != Object.send(:get_ret_effective_type, arg) }
|
||||
end
|
||||
|
||||
def enum_name
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
|
||||
% first_nonvoid = PandaFile::types.select {|type| type.name != "void"}.first.code
|
||||
% first_32 = PandaFile::types.select {|type| type.width && type.width == 32}.first.code
|
||||
% last_int32 = PandaFile::types.select {|type| type.width && type.width == 32 && type.properties.include?("integral") }.last.code
|
||||
% first_64 = PandaFile::types.select {|type| (type.width && type.width == 64) || type.properties.include?("float") }.first.code
|
||||
% last_int32 = PandaFile::types.select {|type| type.width && type.width == 32 && type.properties.include?("integral")}.last.code
|
||||
% first_64 = PandaFile::types.select {|type| (type.width && type.width == 64)}.first.code
|
||||
% first_float = PandaFile::types.select {|type| type.properties.include?("float") }.first.code
|
||||
% num_32_and_larger = PandaFile::types.select {|type| type.width && type.width >= 32 || type.properties.include?("float") || type.name == "reference" || type.name == "tagged" }.length
|
||||
% num_32_and_larger = PandaFile::types.select {|type| type.width && type.width >= 32 || type.name == "reference" || type.name == "tagged" }.length
|
||||
% num_float_types = PandaFile::types.select {|type| type.properties.include?("float") }.length
|
||||
% num_64bit_types = PandaFile::types.select {|type| (type.width && type.width == 64) || type.properties.include?("float") }.length
|
||||
% num_64bit_types = PandaFile::types.select {|type| (type.width && type.width == 64)}.length
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define SHORTY_FIRST_NONVOID 0x<%= first_nonvoid.to_s(16) %>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
@@ -38,7 +38,7 @@
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define SHORTY_LAST_INT32 0x<%= last_int32.to_s(16) %>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define SHORTY_FIRST_64 0x<%= first_64.to_s(16) %> // in the runtime all 32bit floats extends to doubles
|
||||
#define SHORTY_FIRST_64 0x<%= first_64.to_s(16) %>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define SHORTY_FIRST_FLOAT 0x<%= first_float.to_s(16) %>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
|
||||
// Autogenerated file -- DO NOT EDIT!
|
||||
|
||||
#ifndef PANDA_RUNTIME_UNIMPLEMENTED_INTRINSICS_INL_H_
|
||||
#define PANDA_RUNTIME_UNIMPLEMENTED_INTRINSICS_INL_H_
|
||||
|
||||
% unimplemented = %w(
|
||||
% )
|
||||
% intrinsics_hash = Runtime::intrinsics.map { |i| [i.name, i] }.to_h
|
||||
@@ -32,3 +35,5 @@
|
||||
<%= body %>
|
||||
}
|
||||
% end
|
||||
|
||||
#endif // PANDA_RUNTIME_UNIMPLEMENTED_INTRINSICS_INL_H_
|
||||
|
||||
@@ -19,4 +19,54 @@
|
||||
.global InvokeHelper
|
||||
.type InvokeHelper, %function
|
||||
InvokeHelper:
|
||||
CFI_STARTPROC
|
||||
CFI_DEF_CFA(sp, 0)
|
||||
|
||||
// setup regs as follow
|
||||
// r4 - gprs, r5 - fprs, r6 - stack args, r7 - number of stack args, r8 - thread
|
||||
|
||||
push {r4 - r8, fp, lr}
|
||||
CFI_ADJUST_CFA_OFFSET(28)
|
||||
CFI_REL_OFFSET(lr, 24)
|
||||
CFI_REL_OFFSET(fp, 20)
|
||||
mov fp, sp
|
||||
CFI_DEF_CFA_REGISTER(fp)
|
||||
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
mov r6, r2
|
||||
mov r7, r3
|
||||
ldr r8, [sp, #28]
|
||||
|
||||
sub sp, sp, #4
|
||||
push {THREAD_REG}
|
||||
CFI_ADJUST_CFA_OFFSET(8)
|
||||
CFI_REL_OFFSET(THREAD_REG, 0)
|
||||
mov THREAD_REG, r8
|
||||
|
||||
ldmia r4!, {r0 - r3}
|
||||
vldmia r5!, {d0 - d7}
|
||||
|
||||
sub sp, sp, r7, lsl #2
|
||||
bic sp, sp, #7
|
||||
mov r8, sp
|
||||
1: cmp r7, #0
|
||||
beq .Linvoke
|
||||
ldr r4, [r6], #4
|
||||
str r4, [r8], #4
|
||||
sub r7, r7, #1
|
||||
b 1b
|
||||
|
||||
.Linvoke:
|
||||
ldr lr, [r0, #METHOD_COMPILED_ENTRY_POINT_OFFSET]
|
||||
blx lr
|
||||
|
||||
mov sp, fp
|
||||
ldr THREAD_REG, [sp, #-8]
|
||||
CFI_RESTORE(THREAD_REG)
|
||||
pop {r4 - r8, fp, lr}
|
||||
CFI_ADJUST_CFA_OFFSET(-28)
|
||||
CFI_RESTORE(lr)
|
||||
CFI_RESTORE(fp)
|
||||
bx lr
|
||||
CFI_ENDPROC
|
||||
|
||||
@@ -46,7 +46,7 @@ protected:
|
||||
seed_ = 123456U;
|
||||
#endif
|
||||
RuntimeOptions options;
|
||||
options.SetObjectPoolSize(64_MB);
|
||||
options.SetHeapSizeLimit(64_MB);
|
||||
options.SetShouldLoadBootPandaFiles(false);
|
||||
options.SetShouldInitializeIntrinsics(false);
|
||||
options.SetGcType("epsilon");
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
options.SetShouldLoadBootPandaFiles(false);
|
||||
options.SetShouldInitializeIntrinsics(false);
|
||||
options.SetGcType("epsilon");
|
||||
options.SetObjectPoolSize(64_MB);
|
||||
options.SetHeapSizeLimit(64_MB);
|
||||
Runtime::Create(options);
|
||||
thread_ = panda::MTManagedThread::GetCurrent();
|
||||
thread_->ManagedCodeBegin();
|
||||
|
||||
@@ -1346,7 +1346,7 @@ static void TestArray()
|
||||
if constexpr (component_type_id == panda_file::Type::TypeId::REFERENCE) {
|
||||
emitter.LdaObj(4);
|
||||
} else if constexpr (component_type_id == panda_file::Type::TypeId::F32) {
|
||||
emitter.FldaiWide(bit_cast<int64_t>(static_cast<double>(STORE_VALUE)));
|
||||
emitter.Fldai(bit_cast<int32_t>(STORE_VALUE));
|
||||
} else if constexpr (component_type_id == panda_file::Type::TypeId::F64) {
|
||||
emitter.FldaiWide(bit_cast<int64_t>(STORE_VALUE));
|
||||
} else {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define PANDA_RUNTIME_TESTS_INVOKATION_HELPER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include "bridge/bridge.h"
|
||||
#include "include/thread.h"
|
||||
@@ -34,13 +35,50 @@ auto GetInvokeHelper()
|
||||
return reinterpret_cast<Fn>(const_cast<void *>(GetInvokeHelperImpl()));
|
||||
}
|
||||
|
||||
inline void WriteArg(arch::ArgWriter<RUNTIME_ARCH> *) {}
|
||||
inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *, size_t) {}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline void WriteArg(arch::ArgWriter<RUNTIME_ARCH> *writer, T arg, Args... args)
|
||||
inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *writer, size_t nfloats, T arg, Args... args);
|
||||
|
||||
template <typename... Args>
|
||||
inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *writer, size_t nfloats, float arg, Args... args)
|
||||
{
|
||||
writer->Write(arg);
|
||||
WriteArg(writer, args...);
|
||||
WriteArgImpl(writer, nfloats + 1, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline void WriteArgImpl(arch::ArgWriter<RUNTIME_ARCH> *writer, size_t nfloats, T arg, Args... args)
|
||||
{
|
||||
if (RUNTIME_ARCH == Arch::AARCH32 && std::is_same_v<double, T>) {
|
||||
// JIT compiler doesn't pack floats according armhf ABI. So in the following case:
|
||||
//
|
||||
// void foo(f32 a0, f64 a1, f32 a2)
|
||||
//
|
||||
// Arguments will be passed in the following registers:
|
||||
// a0 - s0
|
||||
// a1 - d1
|
||||
// a2 - s4
|
||||
//
|
||||
// But according to armhf ABI a0 and a2 should be packed into d0:
|
||||
// a0 - s0
|
||||
// a1 - d1
|
||||
// a2 - s1
|
||||
//
|
||||
// So write additional float if necessary to prevent packing
|
||||
if ((nfloats & 0x1) != 0) {
|
||||
nfloats += 1;
|
||||
writer->Write(0.0f);
|
||||
}
|
||||
}
|
||||
writer->Write(arg);
|
||||
WriteArgImpl(writer, nfloats, args...);
|
||||
}
|
||||
|
||||
template <class T, typename... Args>
|
||||
inline void WriteArg(arch::ArgWriter<RUNTIME_ARCH> *writer, T arg, Args... args)
|
||||
{
|
||||
WriteArgImpl(writer, 0, arg, args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
MethodTest()
|
||||
{
|
||||
RuntimeOptions options;
|
||||
options.SetObjectPoolSize(128_MB);
|
||||
options.SetHeapSizeLimit(128_MB);
|
||||
options.SetShouldLoadBootPandaFiles(false);
|
||||
options.SetShouldInitializeIntrinsics(false);
|
||||
options.SetGcType("epsilon");
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
{
|
||||
options_.SetShouldLoadBootPandaFiles(false);
|
||||
options_.SetShouldInitializeIntrinsics(false);
|
||||
options_.SetObjectPoolSize(256_MB);
|
||||
options_.SetHeapSizeLimit(256_MB);
|
||||
Runtime::Create(options_);
|
||||
thread_ = panda::MTManagedThread::GetCurrent();
|
||||
thread_->ManagedCodeBegin();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user