mirror of
https://github.com/open-goal/jak-project
synced 2026-09-08 20:02:39 -04:00
[Decompiler] Replace type hint system and improve variable types. (#320)
* get gkernel and gkernel-h at least somewhat working in the offline tests * strip comments from json * switch hints to casts. online tests passing, offline passing up to gkernel * variable retyping is added * fix up casts in lets * update
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "decompiler/analysis/final_output.h"
|
||||
#include "decompiler/analysis/insert_lets.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "common/util/json_util.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "third-party/json.hpp"
|
||||
|
||||
@@ -67,6 +68,43 @@ void FormRegressionTest::TestData::add_string_at_label(const std::string& label_
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::string>, std::unordered_map<std::string, LocalVarOverride>>
|
||||
parse_var_json(const std::string& str) {
|
||||
if (str.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> args;
|
||||
std::unordered_map<std::string, LocalVarOverride> var_overrides;
|
||||
|
||||
auto j = parse_commented_json(str);
|
||||
|
||||
auto arg = j.find("args");
|
||||
if (arg != j.end()) {
|
||||
for (auto& x : arg.value()) {
|
||||
args.push_back(x);
|
||||
}
|
||||
}
|
||||
|
||||
auto var = j.find("vars");
|
||||
if (var != j.end()) {
|
||||
for (auto& vkv : var->get<std::unordered_map<std::string, nlohmann::json>>()) {
|
||||
LocalVarOverride override;
|
||||
if (vkv.second.is_string()) {
|
||||
override.name = vkv.second.get<std::string>();
|
||||
} else if (vkv.second.is_array()) {
|
||||
override.name = vkv.second[0].get<std::string>();
|
||||
override.type = vkv.second[1].get<std::string>();
|
||||
} else {
|
||||
throw std::runtime_error("Invalid function var override.");
|
||||
}
|
||||
var_overrides[vkv.first] = override;
|
||||
}
|
||||
}
|
||||
|
||||
return {args, var_overrides};
|
||||
}
|
||||
|
||||
std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
const std::string& code,
|
||||
const TypeSpec& function_type,
|
||||
@@ -74,7 +112,8 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
bool allow_pairs,
|
||||
const std::string& method_name,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings,
|
||||
const std::unordered_map<int, std::vector<TypeHint>>& hints) {
|
||||
const std::unordered_map<int, std::vector<TypeCast>>& casts,
|
||||
const std::string& var_map_json) {
|
||||
dts->type_prop_settings.locked = true;
|
||||
dts->type_prop_settings.reset();
|
||||
dts->type_prop_settings.allow_pair = allow_pairs;
|
||||
@@ -112,7 +151,7 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
test->func.ir2.atomic_ops_succeeded = true;
|
||||
test->func.ir2.env.set_end_var(test->func.ir2.atomic_ops->end_op().return_var());
|
||||
|
||||
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, hints, {}));
|
||||
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, casts, {}));
|
||||
|
||||
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
|
||||
|
||||
@@ -133,8 +172,9 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
test->func.ir2.top_form->collect_vars(vars, true);
|
||||
|
||||
if (do_expressions) {
|
||||
auto config = parse_var_json(var_map_json);
|
||||
bool success = convert_to_expressions(test->func.ir2.top_form, *test->func.ir2.form_pool,
|
||||
test->func, *dts);
|
||||
test->func, config.first, config.second, *dts);
|
||||
|
||||
EXPECT_TRUE(success);
|
||||
if (!success) {
|
||||
@@ -167,9 +207,11 @@ void FormRegressionTest::test(const std::string& code,
|
||||
bool allow_pairs,
|
||||
const std::string& method_name,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings,
|
||||
const std::unordered_map<int, std::vector<TypeHint>>& hints) {
|
||||
const std::unordered_map<int, std::vector<TypeCast>>& casts,
|
||||
const std::string& var_map_json) {
|
||||
auto ts = dts->parse_type_spec(type);
|
||||
auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings, hints);
|
||||
auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings, casts,
|
||||
var_map_json);
|
||||
ASSERT_TRUE(test);
|
||||
auto expected_form =
|
||||
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
|
||||
@@ -193,9 +235,10 @@ void FormRegressionTest::test_final_function(
|
||||
const std::string& expected,
|
||||
bool allow_pairs,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings,
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints) {
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeCast>>& casts,
|
||||
const std::string& var_map_json) {
|
||||
auto ts = dts->parse_type_spec(type);
|
||||
auto test = make_function(code, ts, true, allow_pairs, "", strings, hints);
|
||||
auto test = make_function(code, ts, true, allow_pairs, "", strings, casts, var_map_json);
|
||||
ASSERT_TRUE(test);
|
||||
auto expected_form =
|
||||
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
|
||||
@@ -211,20 +254,22 @@ void FormRegressionTest::test_final_function(
|
||||
EXPECT_TRUE(expected_form == actual_form);
|
||||
}
|
||||
|
||||
std::unordered_map<int, std::vector<decompiler::TypeHint>> FormRegressionTest::parse_hint_json(
|
||||
std::unordered_map<int, std::vector<decompiler::TypeCast>> FormRegressionTest::parse_cast_json(
|
||||
const std::string& in) {
|
||||
std::unordered_map<int, std::vector<decompiler::TypeHint>> out;
|
||||
auto hints = nlohmann::json::parse(in);
|
||||
for (auto& hint : hints) {
|
||||
auto idx = hint.at(0).get<int>();
|
||||
for (size_t i = 1; i < hint.size(); i++) {
|
||||
auto& assignment = hint.at(i);
|
||||
TypeHint type_hint;
|
||||
type_hint.reg = Register(assignment.at(0).get<std::string>());
|
||||
type_hint.type_name = assignment.at(1).get<std::string>();
|
||||
out[idx].push_back(type_hint);
|
||||
std::unordered_map<int, std::vector<decompiler::TypeCast>> out;
|
||||
auto casts = nlohmann::json::parse(in);
|
||||
|
||||
for (auto& cast : casts) {
|
||||
auto idx_range = parse_json_optional_integer_range(cast.at(0));
|
||||
for (auto idx : idx_range) {
|
||||
TypeCast type_cast;
|
||||
type_cast.atomic_op_idx = idx;
|
||||
type_cast.reg = Register(cast.at(1));
|
||||
type_cast.type_name = cast.at(2).get<std::string>();
|
||||
out[idx].push_back(type_cast);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
|
||||
namespace decompiler {
|
||||
struct TypeHint;
|
||||
struct TypeCast;
|
||||
}
|
||||
|
||||
class FormRegressionTest : public ::testing::Test {
|
||||
@@ -34,7 +34,8 @@ class FormRegressionTest : public ::testing::Test {
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {},
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints = {});
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeCast>>& casts = {},
|
||||
const std::string& var_map_json = "");
|
||||
|
||||
void test(const std::string& code,
|
||||
const std::string& type,
|
||||
@@ -43,7 +44,8 @@ class FormRegressionTest : public ::testing::Test {
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {},
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints = {});
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeCast>>& casts = {},
|
||||
const std::string& var_map_json = "");
|
||||
|
||||
void test_no_expr(const std::string& code,
|
||||
const std::string& type,
|
||||
@@ -51,19 +53,20 @@ class FormRegressionTest : public ::testing::Test {
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {},
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints = {}) {
|
||||
test(code, type, expected, false, allow_pairs, method_name, strings, hints);
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeCast>>& casts = {},
|
||||
const std::string& var_map_json = "") {
|
||||
test(code, type, expected, false, allow_pairs, method_name, strings, casts, var_map_json);
|
||||
}
|
||||
|
||||
void test_with_expr(
|
||||
const std::string& code,
|
||||
const std::string& type,
|
||||
const std::string& expected,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {},
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints = {}) {
|
||||
test(code, type, expected, true, allow_pairs, method_name, strings, hints);
|
||||
void test_with_expr(const std::string& code,
|
||||
const std::string& type,
|
||||
const std::string& expected,
|
||||
bool allow_pairs = false,
|
||||
const std::string& method_name = "",
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {},
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeCast>>& casts = {},
|
||||
const std::string& var_map_json = "") {
|
||||
test(code, type, expected, true, allow_pairs, method_name, strings, casts, var_map_json);
|
||||
}
|
||||
|
||||
void test_final_function(
|
||||
@@ -72,7 +75,8 @@ class FormRegressionTest : public ::testing::Test {
|
||||
const std::string& expected,
|
||||
bool allow_pairs = false,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings = {},
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints = {});
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeCast>>& casts = {},
|
||||
const std::string& var_map_json = "");
|
||||
|
||||
std::unordered_map<int, std::vector<decompiler::TypeHint>> parse_hint_json(const std::string& in);
|
||||
std::unordered_map<int, std::vector<decompiler::TypeCast>> parse_cast_json(const std::string& in);
|
||||
};
|
||||
@@ -235,7 +235,10 @@
|
||||
(let ((obj-type (-> obj type))
|
||||
(end-type object)
|
||||
)
|
||||
(until (begin (set! obj-type (-> obj-type parent)) (= obj-type end-type))
|
||||
(until (begin
|
||||
(set! obj-type (-> obj-type parent))
|
||||
(= obj-type end-type)
|
||||
)
|
||||
(if (= obj-type parent-type)
|
||||
(return #t)
|
||||
)
|
||||
@@ -247,11 +250,10 @@
|
||||
;; definition for function type-type?
|
||||
(defun type-type? ((child-type type) (parent-type type))
|
||||
(let ((end-type object))
|
||||
(until
|
||||
(begin
|
||||
(set! child-type (-> child-type parent))
|
||||
(or (= child-type end-type) (zero? child-type))
|
||||
)
|
||||
(until (begin
|
||||
(set! child-type (-> child-type parent))
|
||||
(or (= child-type end-type) (zero? child-type))
|
||||
)
|
||||
(if (= child-type parent-type)
|
||||
(return #t)
|
||||
)
|
||||
@@ -834,7 +836,7 @@
|
||||
)
|
||||
(else
|
||||
(dotimes (s5-9 (-> obj length))
|
||||
(format #t "~T [~D] ~D~%" s5-9 (-> obj s5-9))
|
||||
(format #t "~T [~D] ~D~%" s5-9 (-> (the-as (array int32) obj) s5-9))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -844,12 +846,12 @@
|
||||
(cond
|
||||
((= (-> obj content-type) float)
|
||||
(dotimes (s5-10 (-> obj length))
|
||||
(format #t "~T [~D] ~f~%" s5-10 (-> obj s5-10))
|
||||
(format #t "~T [~D] ~f~%" s5-10 (-> (the-as (array float) obj) s5-10))
|
||||
)
|
||||
)
|
||||
(else
|
||||
(dotimes (s5-11 (-> obj length))
|
||||
(format #t "~T [~D] ~A~%" s5-11 (-> obj s5-11))
|
||||
(format #t "~T [~D] ~A~%" s5-11 (-> (the-as (array basic) obj) s5-11))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1111,9 +1113,10 @@
|
||||
)
|
||||
#f
|
||||
)
|
||||
((or (not in-goal-mem) (begin (let ((v1-10 #x8000))
|
||||
(.daddu v1-11 v1-10 s7-0)
|
||||
)
|
||||
((or (not in-goal-mem) (begin
|
||||
(let ((v1-10 #x8000))
|
||||
(.daddu v1-11 v1-10 s7-0)
|
||||
)
|
||||
(< (the-as uint obj) (the-as uint v1-11))
|
||||
)
|
||||
)
|
||||
@@ -1283,9 +1286,10 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
((begin (let ((v1-47 #x8000))
|
||||
(.daddu v1-48 v1-47 s7-0)
|
||||
)
|
||||
((begin
|
||||
(let ((v1-47 #x8000))
|
||||
(.daddu v1-48 v1-47 s7-0)
|
||||
)
|
||||
(< (the-as uint obj) (the-as uint v1-48))
|
||||
)
|
||||
(if
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; definition of type kernel-context
|
||||
(deftype kernel-context (basic)
|
||||
((prevent-from-run uint32 :offset-assert 4)
|
||||
(require-for-run uint32 :offset-assert 8)
|
||||
(allow-to-run uint32 :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process basic :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(low-memory-message basic :offset-assert 44)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x30
|
||||
:flag-assert #x900000030
|
||||
)
|
||||
|
||||
;; definition for method 3 of type kernel-context
|
||||
(defmethod inspect kernel-context ((obj kernel-context))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tprevent-from-run: ~D~%" (-> obj prevent-from-run))
|
||||
(format #t "~Trequire-for-run: ~D~%" (-> obj require-for-run))
|
||||
(format #t "~Tallow-to-run: ~D~%" (-> obj allow-to-run))
|
||||
(format #t "~Tnext-pid: ~D~%" (-> obj next-pid))
|
||||
(format #t "~Tfast-stack-top: #x~X~%" (-> obj fast-stack-top))
|
||||
(format #t "~Tcurrent-process: ~A~%" (-> obj current-process))
|
||||
(format #t "~Trelocating-process: ~A~%" (-> obj relocating-process))
|
||||
(format #t "~Trelocating-min: #x~X~%" (-> obj relocating-min))
|
||||
(format #t "~Trelocating-max: #x~X~%" (-> obj relocating-max))
|
||||
(format #t "~Trelocating-offset: ~D~%" (-> obj relocating-offset))
|
||||
(format #t "~Tlow-memory-message: ~A~%" (-> obj low-memory-message))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type thread
|
||||
(deftype thread (basic)
|
||||
((name basic :offset-assert 4)
|
||||
(process process :offset-assert 8)
|
||||
(previous thread :offset-assert 12)
|
||||
(suspend-hook (function cpu-thread none) :offset-assert 16)
|
||||
(resume-hook (function cpu-thread none) :offset-assert 20)
|
||||
(pc pointer :offset-assert 24)
|
||||
(sp pointer :offset-assert 28)
|
||||
(stack-top pointer :offset-assert 32)
|
||||
(stack-size int32 :offset-assert 36)
|
||||
)
|
||||
:method-count-assert 12
|
||||
:size-assert #x28
|
||||
:flag-assert #xc00000028
|
||||
(:methods
|
||||
(stack-size-set! (_type_ int) none 9)
|
||||
(thread-suspend (_type_) none 10)
|
||||
(thread-resume (_type_) none 11)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type thread
|
||||
(defmethod inspect thread ((obj thread))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tname: ~A~%" (-> obj name))
|
||||
(format #t "~Tprocess: ~A~%" (-> obj process))
|
||||
(format #t "~Tprevious: ~A~%" (-> obj previous))
|
||||
(format #t "~Tsuspend-hook: ~A~%" (-> obj suspend-hook))
|
||||
(format #t "~Tresume-hook: ~A~%" (-> obj resume-hook))
|
||||
(format #t "~Tpc: #x~X~%" (-> obj pc))
|
||||
(format #t "~Tsp: #x~X~%" (-> obj sp))
|
||||
(format #t "~Tstack-top: #x~X~%" (-> obj stack-top))
|
||||
(format #t "~Tstack-size: ~D~%" (-> obj stack-size))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type cpu-thread
|
||||
(deftype cpu-thread (thread)
|
||||
((rreg uint64 7 :offset-assert 40)
|
||||
(freg float 8 :offset-assert 96)
|
||||
(stack uint8 :dynamic :offset-assert 128)
|
||||
)
|
||||
:method-count-assert 12
|
||||
:size-assert #x80
|
||||
:flag-assert #xc00000080
|
||||
(:methods
|
||||
(new (symbol type process symbol int pointer) _type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type cpu-thread
|
||||
(defmethod inspect cpu-thread ((obj cpu-thread))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tname: ~A~%" (-> obj name))
|
||||
(format #t "~Tprocess: ~A~%" (-> obj process))
|
||||
(format #t "~Tprevious: ~A~%" (-> obj previous))
|
||||
(format #t "~Tsuspend-hook: ~A~%" (-> obj suspend-hook))
|
||||
(format #t "~Tresume-hook: ~A~%" (-> obj resume-hook))
|
||||
(format #t "~Tpc: #x~X~%" (-> obj pc))
|
||||
(format #t "~Tsp: #x~X~%" (-> obj sp))
|
||||
(format #t "~Tstack-top: #x~X~%" (-> obj stack-top))
|
||||
(format #t "~Tstack-size: ~D~%" (-> obj stack-size))
|
||||
(format #t "~Trreg[8] @ #x~X~%" (-> obj rreg))
|
||||
(format #t "~Tfreg[6] @ #x~X~%" (&-> obj freg 2))
|
||||
(format #t "~Tstack[0] @ #x~X~%" (-> obj stack))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type dead-pool
|
||||
(deftype dead-pool (process-tree)
|
||||
()
|
||||
:method-count-assert 16
|
||||
:size-assert #x20
|
||||
:flag-assert #x1000000020
|
||||
(:methods
|
||||
(new (symbol type int int basic) _type_ 0)
|
||||
(get-process (_type_ type int) process 14)
|
||||
(return-process (_type_ process) none 15)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type dead-pool
|
||||
(defmethod inspect dead-pool ((obj dead-pool))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tname: ~A~%" (-> obj name))
|
||||
(format #t "~Tmask: ~D~%" (-> obj mask))
|
||||
(format #t "~Tparent: #x~X~%" (-> obj parent))
|
||||
(format #t "~Tbrother: #x~X~%" (-> obj brother))
|
||||
(format #t "~Tchild: #x~X~%" (-> obj child))
|
||||
(format #t "~Tppointer: #x~X~%" (-> obj ppointer))
|
||||
(format #t "~Tself: ~A~%" (-> obj self))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type dead-pool-heap-rec
|
||||
(deftype dead-pool-heap-rec (structure)
|
||||
((process process :offset-assert 0)
|
||||
(prev dead-pool-heap-rec :offset-assert 4)
|
||||
(next dead-pool-heap-rec :offset-assert 8)
|
||||
)
|
||||
:pack-me
|
||||
:method-count-assert 9
|
||||
:size-assert #xc
|
||||
:flag-assert #x90000000c
|
||||
)
|
||||
|
||||
;; definition for method 3 of type dead-pool-heap-rec
|
||||
(defmethod inspect dead-pool-heap-rec ((obj dead-pool-heap-rec))
|
||||
(format #t "[~8x] ~A~%" obj 'dead-pool-heap-rec)
|
||||
(format #t "~Tprocess: ~A~%" (-> obj process))
|
||||
(format #t "~Tprev: #<dead-pool-heap-rec @ #x~X>~%" (-> obj prev))
|
||||
(format #t "~Tnext: #<dead-pool-heap-rec @ #x~X>~%" (-> obj next))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type dead-pool-heap
|
||||
(deftype dead-pool-heap (dead-pool)
|
||||
((allocated-length int32 :offset-assert 32)
|
||||
(compact-time uint32 :offset-assert 36)
|
||||
(compact-count-targ uint32 :offset-assert 40)
|
||||
(compact-count uint32 :offset-assert 44)
|
||||
(fill-percent float :offset-assert 48)
|
||||
(first-gap dead-pool-heap-rec :offset-assert 52)
|
||||
(first-shrink dead-pool-heap-rec :offset-assert 56)
|
||||
(heap kheap :inline :offset-assert 64)
|
||||
(alive-list dead-pool-heap-rec :inline :offset-assert 80)
|
||||
(last dead-pool-heap-rec :offset 84)
|
||||
(dead-list dead-pool-heap-rec :inline :offset-assert 92)
|
||||
(process-list dead-pool-heap-rec :inline :dynamic :offset-assert 104)
|
||||
)
|
||||
:method-count-assert 27
|
||||
:size-assert #x68
|
||||
:flag-assert #x1b00000068
|
||||
(:methods
|
||||
(new (symbol type basic int int) _type_ 0)
|
||||
(compact (dead-pool-heap int) none 16)
|
||||
(shrink-heap (dead-pool-heap process) dead-pool-heap 17)
|
||||
(churn (dead-pool-heap int) none 18)
|
||||
(memory-used (dead-pool-heap) int 19)
|
||||
(memory-total (dead-pool-heap) int 20)
|
||||
(gap-size (dead-pool-heap dead-pool-heap-rec) int 21)
|
||||
(gap-location (dead-pool-heap dead-pool-heap-rec) pointer 22)
|
||||
(find-gap (dead-pool-heap dead-pool-heap-rec) dead-pool-heap-rec 23)
|
||||
(find-gap-by-size (dead-pool-heap int) dead-pool-heap-rec 24)
|
||||
(memory-free (dead-pool-heap) int 25)
|
||||
(compact-time (dead-pool-heap) uint 26)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type dead-pool-heap
|
||||
;; INFO: this function exists in multiple non-identical object files
|
||||
(defmethod inspect dead-pool-heap ((obj dead-pool-heap))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tname: ~A~%" (-> obj name))
|
||||
(format #t "~Tmask: ~D~%" (-> obj mask))
|
||||
(format #t "~Tparent: #x~X~%" (-> obj parent))
|
||||
(format #t "~Tbrother: #x~X~%" (-> obj brother))
|
||||
(format #t "~Tchild: #x~X~%" (-> obj child))
|
||||
(format #t "~Tppointer: #x~X~%" (-> obj ppointer))
|
||||
(format #t "~Tself: ~A~%" (-> obj self))
|
||||
(format #t "~Tallocated-length: ~D~%" (-> obj allocated-length))
|
||||
(format #t "~Tcompact-time: ~D~%" (-> obj compact-time))
|
||||
(format #t "~Tcompact-count-targ: ~D~%" (-> obj compact-count-targ))
|
||||
(format #t "~Tcompact-count: ~D~%" (-> obj compact-count))
|
||||
(format #t "~Tfill-percent: ~f~%" (-> obj fill-percent))
|
||||
(format #t "~Tfirst-gap: #<dead-pool-heap-rec @ #x~X>~%" (-> obj first-gap))
|
||||
(format
|
||||
#t
|
||||
"~Tfirst-shrink: #<dead-pool-heap-rec @ #x~X>~%"
|
||||
(-> obj first-shrink)
|
||||
)
|
||||
(format #t "~Theap: #<kheap @ #x~X>~%" (-> obj heap))
|
||||
(format #t "~Talive-list: #<dead-pool-heap-rec @ #x~X>~%" (-> obj alive-list))
|
||||
(format #t "~Tlast: #<dead-pool-heap-rec @ #x~X>~%" (-> obj alive-list prev))
|
||||
(format #t "~Tdead-list: #<dead-pool-heap-rec @ #x~X>~%" (-> obj dead-list))
|
||||
(format #t "~Tprocess-list[0] @ #x~X~%" (-> obj process-list))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type catch-frame
|
||||
(deftype catch-frame (stack-frame)
|
||||
((sp int32 :offset-assert 12)
|
||||
(ra int32 :offset-assert 16)
|
||||
(freg float 10 :offset-assert 20)
|
||||
(rreg uint128 7 :offset-assert 64)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #xb0
|
||||
:flag-assert #x9000000b0
|
||||
(:methods
|
||||
(new (symbol type symbol function (pointer uint64)) object 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type catch-frame
|
||||
(defmethod inspect catch-frame ((obj catch-frame))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tname: ~A~%" (-> obj name))
|
||||
(format #t "~Tnext: ~A~%" (-> obj next))
|
||||
(format #t "~Tsp: #x~X~%" (-> obj sp))
|
||||
(format #t "~Tra: #x~X~%" (-> obj ra))
|
||||
(format #t "~Tfreg[6] @ #x~X~%" (-> obj freg))
|
||||
(format #t "~Trreg[8] @ #x~X~%" (&-> obj freg 7))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type protect-frame
|
||||
(deftype protect-frame (stack-frame)
|
||||
((exit (function object) :offset-assert 12)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
(:methods
|
||||
(new (symbol type (function object)) protect-frame 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type protect-frame
|
||||
(defmethod inspect protect-frame ((obj protect-frame))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tname: ~A~%" (-> obj name))
|
||||
(format #t "~Tnext: ~A~%" (-> obj next))
|
||||
(format #t "~Texit: ~A~%" (-> obj exit))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type handle
|
||||
(deftype handle (uint64)
|
||||
((process (pointer process) :offset 0 :size 32)
|
||||
(pid int32 :offset 32 :size 32)
|
||||
(u64 uint64 :offset 0 :size 64)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; definition for method 3 of type handle
|
||||
(defmethod inspect handle ((obj handle))
|
||||
(format #t "[~8x] ~A~%" obj 'handle)
|
||||
(format #t "~Tprocess: #x~X~%" (shr (shl (the-as int obj) 32) 32))
|
||||
(format #t "~Tpid: ~D~%" (sar (the-as int obj) 32))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition for method 2 of type handle
|
||||
;; WARN: Unsupported inline assembly instruction kind - [5]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [73]
|
||||
(defmethod print handle ((obj handle))
|
||||
(local-vars (a2-0 int) (s7-0 none))
|
||||
(if (nonzero? obj)
|
||||
(let ((t9-0 format)
|
||||
(a0-1 #t)
|
||||
(a1-0 "#<handle :process ~A :pid ~D>")
|
||||
(v1-0 obj)
|
||||
)
|
||||
(.subu a2-0 (the-as handle v1-0) s7-0)
|
||||
(let ((a2-1 (and (nonzero? a2-0) (begin
|
||||
(.sllv a2-2 (the-as handle v1-0) r0-0)
|
||||
(let ((a3-0 (-> a2-2 0)))
|
||||
(set!
|
||||
a2-1
|
||||
(if (= (sar v1-0 32) (-> a3-0 pid))
|
||||
a3-0
|
||||
)
|
||||
)
|
||||
)
|
||||
(let ((v1-2 a2-1))
|
||||
)
|
||||
a2-1
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(t9-0 a0-1 a1-0 a2-1 (sar (the-as int obj) 32))
|
||||
)
|
||||
)
|
||||
(format #t "#<handle :process 0 :pid 0>")
|
||||
)
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type state
|
||||
(deftype state (protect-frame)
|
||||
((code function :offset-assert 16)
|
||||
(trans (function object) :offset-assert 20)
|
||||
(post function :offset-assert 24)
|
||||
(enter (function object object object object object object object) :offset-assert 28)
|
||||
(event (function basic int basic event-message-block object) :offset-assert 32)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x24
|
||||
:flag-assert #x900000024
|
||||
(:methods
|
||||
(new (symbol type basic function (function object) (function object object object object object object object) (function object) (function basic int basic event-message-block object)) _type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type state
|
||||
(defmethod inspect state ((obj state))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tname: ~A~%" (-> obj name))
|
||||
(format #t "~Tnext: ~A~%" (-> obj next))
|
||||
(format #t "~Texit: ~A~%" (-> obj exit))
|
||||
(format #t "~Tcode: ~A~%" (-> obj code))
|
||||
(format #t "~Ttrans: ~A~%" (-> obj trans))
|
||||
(format #t "~Tpost: ~A~%" (-> obj post))
|
||||
(format #t "~Tenter: ~A~%" (-> obj enter))
|
||||
(format #t "~Tevent: ~A~%" (-> obj event))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type event-message-block
|
||||
(deftype event-message-block (structure)
|
||||
((to basic :offset-assert 0)
|
||||
(from basic :offset-assert 4)
|
||||
(num-params int32 :offset-assert 8)
|
||||
(message basic :offset-assert 12)
|
||||
(param uint64 7 :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x48
|
||||
:flag-assert #x900000048
|
||||
)
|
||||
|
||||
;; definition for method 3 of type event-message-block
|
||||
(defmethod inspect event-message-block ((obj event-message-block))
|
||||
(format #t "[~8x] ~A~%" obj 'event-message-block)
|
||||
(format #t "~Tto: ~A~%" (-> obj to))
|
||||
(format #t "~Tfrom: ~A~%" (-> obj from))
|
||||
(format #t "~Tnum-params: ~D~%" (-> obj num-params))
|
||||
(format #t "~Tmessage: ~A~%" (-> obj message))
|
||||
(format #t "~Tparam[7] @ #x~X~%" (-> obj param))
|
||||
obj
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(let ((v0-11 0))
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -410,7 +410,7 @@ TEST_F(FormRegressionTest, SimpleLoopMergeCheck) {
|
||||
" lw v0, -2(a0)\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function pair int)";
|
||||
std::string type = "(function object int)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 0)\n"
|
||||
|
||||
@@ -2273,15 +2273,17 @@ TEST_F(FormRegressionTest, ExprPrintName) {
|
||||
" (string= (the-as string arg0) (the-as string arg1))\n"
|
||||
" )\n"
|
||||
" ((and (= (-> arg0 type) string) (= (-> arg1 type) symbol))\n"
|
||||
" (string= (the-as string arg0) (-> (+ 65336 (the-as int arg1)) 0))\n"
|
||||
" (string= (the-as string arg0) (the-as string (-> (the-as (pointer uint32) (+ 65336 "
|
||||
"(the-as int arg1))))))\n"
|
||||
" )\n"
|
||||
" ((and (= (-> arg1 type) string) (= (-> arg0 type) symbol))\n"
|
||||
" (string= (the-as string arg1) (-> (+ 65336 (the-as int arg0)) 0))\n"
|
||||
" (string= (the-as string arg1) (the-as string (-> (the-as (pointer uint32) (+ 65336 "
|
||||
"(the-as int arg0))))))\n"
|
||||
" )\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {},
|
||||
parse_hint_json("[\t\t[24, [\"a1\", \"symbol\"]],\n"
|
||||
"\t\t[39, [\"a0\", \"symbol\"]]]"));
|
||||
parse_cast_json("[\t\t[24, \"a1\", \"symbol\"],\n"
|
||||
"\t\t[39, \"a0\", \"symbol\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprProfileBarMethod9) {
|
||||
|
||||
@@ -690,21 +690,21 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
{"L336", "~A"},
|
||||
{"L335", " ~A"},
|
||||
{"L334", ")"}},
|
||||
parse_hint_json("["
|
||||
"\t\t[23, [\"gp\", \"(array int32)\"]],\n"
|
||||
"\t\t[43, [\"gp\", \"(array uint32)\"]],\n"
|
||||
"\t\t[63, [\"gp\", \"(array int64)\"]],\n"
|
||||
"\t\t[83, [\"gp\", \"(array uint64)\"]],\n"
|
||||
"\t\t[102, [\"gp\", \"(array int8)\"]],\n"
|
||||
"\t\t[121, [\"gp\", \"(array uint8)\"]],\n"
|
||||
"\t\t[141, [\"gp\", \"(array int16)\"]],\n"
|
||||
"\t\t[161, [\"gp\", \"(array uint16)\"]],\n"
|
||||
"\t\t[186, [\"gp\", \"(array uint128)\"]],\n"
|
||||
"\t\t[204, [\"gp\", \"(array int32)\"]],\n"
|
||||
"\t\t[223, [\"gp\", \"(array float)\"]],\n"
|
||||
"\t\t[232, [\"gp\", \"(array float)\"]],\n"
|
||||
"\t\t[249, [\"gp\", \"(array basic)\"]],\n"
|
||||
"\t\t[258, [\"gp\", \"(array basic)\"]]]"));
|
||||
parse_cast_json("["
|
||||
"\t\t[23, \"gp\", \"(array int32)\"],\n"
|
||||
"\t\t[43, \"gp\", \"(array uint32)\"],\n"
|
||||
"\t\t[63, \"gp\", \"(array int64)\"],\n"
|
||||
"\t\t[83, \"gp\", \"(array uint64)\"],\n"
|
||||
"\t\t[102, \"gp\", \"(array int8)\"],\n"
|
||||
"\t\t[121, \"gp\", \"(array uint8)\"],\n"
|
||||
"\t\t[141, \"gp\", \"(array int16)\"],\n"
|
||||
"\t\t[161, \"gp\", \"(array uint16)\"],\n"
|
||||
"\t\t[186, \"gp\", \"(array uint128)\"],\n"
|
||||
"\t\t[204, \"gp\", \"(array int32)\"],\n"
|
||||
"\t\t[223, \"gp\", \"(array float)\"],\n"
|
||||
"\t\t[232, \"gp\", \"(array float)\"],\n"
|
||||
"\t\t[249, \"gp\", \"(array basic)\"],\n"
|
||||
"\t\t[258, \"gp\", \"(array basic)\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
@@ -1238,7 +1238,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" (else\n"
|
||||
" (dotimes\n"
|
||||
" (s5-9 (-> arg0 length))\n"
|
||||
" (format #t \"~T [~D] ~D~%\" s5-9 (-> arg0 s5-9))\n"
|
||||
" (format #t \"~T [~D] ~D~%\" s5-9 (-> (the-as (array int32) arg0) s5-9))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
@@ -1272,18 +1272,18 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
{"L327", "~T [~D] #x~X~%"},
|
||||
{"L326", "~T [~D] ~f~%"},
|
||||
{"L325", "~T [~D] ~A~%"}},
|
||||
parse_hint_json("[\t\t[44, [\"gp\", \"(array int32)\"]],\n"
|
||||
"\t\t[62, [\"gp\", \"(array uint32)\"]],\n"
|
||||
"\t\t[80, [\"gp\", \"(array int64)\"]],\n"
|
||||
"\t\t[98, [\"gp\", \"(array uint64)\"]],\n"
|
||||
"\t\t[115, [\"gp\", \"(array int8)\"]],\n"
|
||||
"\t\t[132, [\"gp\", \"(array int8)\"]],\n"
|
||||
"\t\t[150, [\"gp\", \"(array int16)\"]],\n"
|
||||
"\t\t[168, [\"gp\", \"(array uint16)\"]],\n"
|
||||
"\t\t[191, [\"gp\", \"(array uint128)\"]],\n"
|
||||
"\t\t[204, [\"gp\", \"(array int32)\"]],\n"
|
||||
"\t\t[226, [\"gp\", \"(array float)\"]],\n"
|
||||
"\t\t[243, [\"gp\", \"(array basic)\"]]]"));
|
||||
parse_cast_json("[\t\t[44, \"gp\", \"(array int32)\"],\n"
|
||||
"\t\t[62, \"gp\", \"(array uint32)\"],\n"
|
||||
"\t\t[80, \"gp\", \"(array int64)\"],\n"
|
||||
"\t\t[98, \"gp\", \"(array uint64)\"],\n"
|
||||
"\t\t[115, \"gp\", \"(array int8)\"],\n"
|
||||
"\t\t[132, \"gp\", \"(array int8)\"],\n"
|
||||
"\t\t[150, \"gp\", \"(array int16)\"],\n"
|
||||
"\t\t[168, \"gp\", \"(array uint16)\"],\n"
|
||||
"\t\t[191, \"gp\", \"(array uint128)\"],\n"
|
||||
"\t\t[207, \"gp\", \"(array int32)\"],\n"
|
||||
"\t\t[226, \"gp\", \"(array float)\"],\n"
|
||||
"\t\t[243, \"gp\", \"(array basic)\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprValid) {
|
||||
@@ -2387,7 +2387,7 @@ TEST_F(FormRegressionTest, ExprStringToInt) {
|
||||
" (>= (the-as uint 70) (-> a0-3 0))\n"
|
||||
" )\n"
|
||||
" (set! v0-0 (+ (+ (-> a0-3 0) -55) (the-as uint (shl v0-0 4))))\n"
|
||||
" (let ((a1-14 v0-0)))\n"
|
||||
" (let ((a1-14 (the-as uint v0-0))))\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (cond\n"
|
||||
@@ -2396,11 +2396,11 @@ TEST_F(FormRegressionTest, ExprStringToInt) {
|
||||
" (>= (the-as uint 102) (-> a0-3 0))\n"
|
||||
" )\n"
|
||||
" (set! v0-0 (+ (+ (-> a0-3 0) -87) (the-as uint (shl v0-0 4))))\n"
|
||||
" (let ((a1-20 v0-0)))\n"
|
||||
" (let ((a1-20 (the-as uint v0-0))))\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (set! v0-0 (+ (+ (-> a0-3 0) -48) (the-as uint (shl v0-0 4))))\n"
|
||||
" (let ((a1-23 v0-0)))\n"
|
||||
" (let ((a1-23 (the-as uint v0-0))))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
||||
@@ -323,7 +323,7 @@ TEST_F(FormRegressionTest, ExprMethod0Thread) {
|
||||
" sw t0, 32(v0)\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function symbol type process symbol int pointer thread)";
|
||||
std::string type = "(function symbol type process symbol int pointer cpu-thread)";
|
||||
std::string expected =
|
||||
"(let\n"
|
||||
" ((v0-0\n"
|
||||
@@ -339,19 +339,21 @@ TEST_F(FormRegressionTest, ExprMethod0Thread) {
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) type) arg1)\n"
|
||||
" (set! (-> v0-0 name) arg3)\n"
|
||||
" (set! (-> v0-0 process) arg2)\n"
|
||||
" (set! (-> v0-0 sp) arg5)\n"
|
||||
" (set! (-> v0-0 stack-top) arg5)\n"
|
||||
" (set! (-> v0-0 previous) (-> arg2 top-thread))\n"
|
||||
" (set! (-> arg2 top-thread) v0-0)\n"
|
||||
" (set! (-> v0-0 suspend-hook) (method-of-object v0-0 thread-suspend))\n"
|
||||
" (set! (-> v0-0 resume-hook) (method-of-object v0-0 thread-resume))\n"
|
||||
" (set! (-> v0-0 stack-size) arg4)\n"
|
||||
" v0-0\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) name) arg3)\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) process) arg2)\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) sp) arg5)\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) stack-top) arg5)\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) previous) (-> arg2 top-thread))\n"
|
||||
" (set! (-> arg2 top-thread) (the-as cpu-thread v0-0))\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) suspend-hook) (method-of-object (the-as cpu-thread "
|
||||
"v0-0) thread-suspend))\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) resume-hook) (method-of-object (the-as cpu-thread "
|
||||
"v0-0) thread-resume))\n"
|
||||
" (set! (-> (the-as cpu-thread v0-0) stack-size) arg4)\n"
|
||||
" (the-as cpu-thread v0-0)\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "cpu-thread", {},
|
||||
parse_hint_json("[[13, [\"v0\", \"cpu-thread\"]]]"));
|
||||
parse_cast_json("[[[13, 28], \"v0\", \"cpu-thread\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprMethod5CpuThread) {
|
||||
@@ -635,36 +637,37 @@ TEST_F(FormRegressionTest, ExprMethod0Process) {
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> (the-as process v0-0) name) arg2)\n"
|
||||
" (set! (-> v0-0 status) (quote dead))\n"
|
||||
" (set! (-> v0-0 pid) 0)\n"
|
||||
" (set! (-> v0-0 pool) #f)\n"
|
||||
" (set! (-> v0-0 allocated-length) arg3)\n"
|
||||
" (set! (-> v0-0 top-thread) #f)\n"
|
||||
" (set! (-> v0-0 main-thread) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) status) (quote dead))\n"
|
||||
" (set! (-> (the-as process v0-0) pid) 0)\n"
|
||||
" (set! (-> (the-as process v0-0) pool) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) allocated-length) arg3)\n"
|
||||
" (set! (-> (the-as process v0-0) top-thread) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) main-thread) #f)\n"
|
||||
" (let\n"
|
||||
" ((v1-5 (-> v0-0 stack)))\n"
|
||||
" (set! (-> v0-0 heap-cur) v1-5)\n"
|
||||
" (set! (-> v0-0 heap-base) v1-5)\n"
|
||||
" ((v1-5 (-> (the-as process v0-0) stack)))\n"
|
||||
" (set! (-> (the-as process v0-0) heap-cur) v1-5)\n"
|
||||
" (set! (-> (the-as process v0-0) heap-base) v1-5)\n"
|
||||
" )\n"
|
||||
" (set! (-> v0-0 heap-top) (&-> v0-0 stack (-> v0-0 allocated-length)))\n"
|
||||
" (set! (-> v0-0 stack-frame-top) (-> v0-0 heap-top))\n"
|
||||
" (set! (-> v0-0 stack-frame-top) #f)\n"
|
||||
" (set! (-> v0-0 state) #f)\n"
|
||||
" (set! (-> v0-0 next-state) #f)\n"
|
||||
" (set! (-> v0-0 entity) #f)\n"
|
||||
" (set! (-> v0-0 trans-hook) #f)\n"
|
||||
" (set! (-> v0-0 post-hook) #f)\n"
|
||||
" (set! (-> v0-0 event-hook) #f)\n"
|
||||
" (set! (-> v0-0 parent) #f)\n"
|
||||
" (set! (-> v0-0 brother) #f)\n"
|
||||
" (set! (-> v0-0 child) #f)\n"
|
||||
" (set! (-> v0-0 self) v0-0)\n"
|
||||
" (set! (-> v0-0 ppointer) (&-> v0-0 self))\n"
|
||||
" v0-0\n"
|
||||
" (set! (-> (the-as process v0-0) heap-top) (&-> (the-as process v0-0) stack (-> (the-as "
|
||||
"process v0-0) allocated-length)))\n"
|
||||
" (set! (-> (the-as process v0-0) stack-frame-top) (-> (the-as process v0-0) heap-top))\n"
|
||||
" (set! (-> (the-as process v0-0) stack-frame-top) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) state) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) next-state) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) entity) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) trans-hook) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) post-hook) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) event-hook) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) parent) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) brother) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) child) #f)\n"
|
||||
" (set! (-> (the-as process v0-0) self) (the-as process v0-0))\n"
|
||||
" (set! (-> (the-as process v0-0) ppointer) (&-> (the-as process v0-0) self))\n"
|
||||
" (the-as process v0-0)\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "process", {},
|
||||
parse_hint_json("[\t\t[12, [\"a0\", \"int\"]],\n"
|
||||
"\t\t[13, [\"v0\", \"process\"]]]"));
|
||||
parse_cast_json("[\t\t[12, \"a0\", \"int\"],\n"
|
||||
"\t\t[[13, 43], \"v0\", \"process\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprInspectProcessHeap) {
|
||||
@@ -720,18 +723,19 @@ TEST_F(FormRegressionTest, ExprInspectProcessHeap) {
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (let\n"
|
||||
" ((s5-0 (&+ (-> arg0 heap-base) 4)))\n"
|
||||
" ((obj (the-as basic (&+ (-> arg0 heap-base) 4))))\n"
|
||||
" (while\n"
|
||||
" (< (the-as int s5-0) (the-as int (-> arg0 heap-cur)))\n"
|
||||
" (inspect (the-as basic s5-0))\n"
|
||||
" (+! (the-as int s5-0) (logand -16 (+ (asize-of s5-0) 15)))\n"
|
||||
" (< (the-as int obj) (the-as int (-> arg0 heap-cur)))\n"
|
||||
" (inspect obj)\n"
|
||||
" (+! (the-as int obj) (logand -16 (+ (asize-of obj) 15)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {},
|
||||
parse_hint_json("[\t\t[4, [\"s5\", \"basic\"]],\n"
|
||||
"\t\t[17, [\"s5\", \"int\"]]]"));
|
||||
parse_cast_json("[\t\t[[4,11], \"s5\", \"basic\"],\n"
|
||||
"\t\t[[17,20], \"s5\", \"int\"]]"),
|
||||
"{\"vars\":{\"s5-0\":[\"obj\", \"basic\"]}}");
|
||||
}
|
||||
|
||||
// note: skipped method 3 process
|
||||
@@ -1049,50 +1053,50 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPool) {
|
||||
std::string type = "(function dead-pool type int process)";
|
||||
// todo - why does one work but not the other??
|
||||
std::string expected =
|
||||
"(let\n"
|
||||
" ((s4-0 (-> arg0 child)))\n"
|
||||
"(let ((s4-0 (the-as object (-> arg0 child))))\n"
|
||||
" (when\n"
|
||||
" (and (not s4-0) *debug-segment* (!= arg0 *debug-dead-pool*))\n"
|
||||
" (and\n"
|
||||
" (not (the-as (pointer process-tree) s4-0))\n"
|
||||
" *debug-segment*\n"
|
||||
" (!= arg0 *debug-dead-pool*)\n"
|
||||
" )\n"
|
||||
" (set! s4-0 (get-process *debug-dead-pool* arg1 arg2))\n"
|
||||
" (if\n"
|
||||
" s4-0\n"
|
||||
" (let\n"
|
||||
" ((t9-1 format)\n"
|
||||
" (a0-2 0)\n"
|
||||
" (a1-2\n"
|
||||
" \"WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%\"\n"
|
||||
" )\n"
|
||||
" (a2-1 arg1)\n"
|
||||
" (v1-6 s4-0)\n"
|
||||
" )\n"
|
||||
" (t9-1\n"
|
||||
" a0-2\n"
|
||||
" a1-2\n"
|
||||
" a2-1\n"
|
||||
" (if v1-6 (-> (the-as (pointer process-tree) v1-6) 0 self))\n"
|
||||
" (if (the-as process s4-0)\n"
|
||||
" (let ((t9-1 format)\n"
|
||||
" (a0-2 0)\n"
|
||||
" (a1-2\n"
|
||||
" \"WARNING: ~A ~A had to be allocated from the debug pool, because ~A was "
|
||||
"empty.~%\"\n"
|
||||
" )\n"
|
||||
" (a2-1 arg1)\n"
|
||||
" (v1-6 (the-as process s4-0))\n"
|
||||
" )\n"
|
||||
" (t9-1 a0-2 a1-2 a2-1 (if (the-as process v1-6)\n"
|
||||
" (-> (the-as (pointer process-tree) v1-6) 0 self)\n"
|
||||
" )\n"
|
||||
" (-> arg0 name)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (the-as\n"
|
||||
" process\n"
|
||||
" (cond\n"
|
||||
" (s4-0\n"
|
||||
" (set! (-> (the-as (pointer process-tree) s4-0) 0 type) arg1)\n"
|
||||
" (-> s4-0 0)\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (format\n"
|
||||
" 0\n"
|
||||
" \"WARNING: ~A ~A could not be allocated, because ~A was empty.~%\"\n"
|
||||
" arg1\n"
|
||||
" (if s4-0 (-> s4-0 0 self))\n"
|
||||
" (-> arg0 name)\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (the-as process (cond\n"
|
||||
" (s4-0\n"
|
||||
" (set! (-> (the-as (pointer process-tree) s4-0) 0 type) arg1)\n"
|
||||
" (-> (the-as (pointer process-tree) s4-0) 0)\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (format\n"
|
||||
" 0\n"
|
||||
" \"WARNING: ~A ~A could not be allocated, because ~A was empty.~%\"\n"
|
||||
" arg1\n"
|
||||
" (if (the-as (pointer process-tree) s4-0)\n"
|
||||
" (-> (the-as (pointer process-tree) s4-0) 0 self)\n"
|
||||
" )\n"
|
||||
" (-> arg0 name)\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )";
|
||||
|
||||
@@ -1101,8 +1105,8 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPool) {
|
||||
func, type, expected, false, "dead-pool",
|
||||
{{"L315", "WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%"},
|
||||
{"L314", "WARNING: ~A ~A could not be allocated, because ~A was empty.~%"}},
|
||||
parse_hint_json("[\t\t[24, [\"v1\", \"(pointer process-tree)\"]],\n"
|
||||
"\t\t[30, [\"s4\", \"(pointer process-tree)\"]]]"));
|
||||
parse_cast_json("[\t\t[24, \"v1\", \"(pointer process-tree)\"],\n"
|
||||
"\t\t[[30,39], \"s4\", \"(pointer process-tree)\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprMethod15DeadPool) {
|
||||
@@ -1226,7 +1230,7 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) {
|
||||
std::string type = "(function symbol type basic int int dead-pool-heap)";
|
||||
std::string expected =
|
||||
"(let\n"
|
||||
" ((v0-0\n"
|
||||
" ((obj\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
@@ -1240,46 +1244,48 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) {
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> v0-0 name) arg2)\n"
|
||||
" (set! (-> v0-0 mask) 256)\n"
|
||||
" (set! (-> v0-0 allocated-length) arg3)\n"
|
||||
" (set! (-> v0-0 parent) #f)\n"
|
||||
" (set! (-> v0-0 brother) #f)\n"
|
||||
" (set! (-> v0-0 child) #f)\n"
|
||||
" (set! (-> v0-0 self) v0-0)\n"
|
||||
" (set! (-> v0-0 ppointer) (&-> v0-0 self))\n"
|
||||
" (set! (-> obj name) arg2)\n"
|
||||
" (set! (-> obj mask) 256)\n"
|
||||
" (set! (-> obj allocated-length) arg3)\n"
|
||||
" (set! (-> obj parent) #f)\n"
|
||||
" (set! (-> obj brother) #f)\n"
|
||||
" (set! (-> obj child) #f)\n"
|
||||
" (set! (-> obj self) obj)\n"
|
||||
" (set! (-> obj ppointer) (&-> obj self))\n"
|
||||
" (let\n"
|
||||
" ((v1-4 arg3))\n"
|
||||
" (while\n"
|
||||
" (nonzero? v1-4)\n"
|
||||
" (+! v1-4 -1)\n"
|
||||
" (let\n"
|
||||
" ((a0-4 (-> v0-0 process-list v1-4)))\n"
|
||||
" ((a0-4 (-> obj process-list v1-4)))\n"
|
||||
" (set! (-> a0-4 process) *null-process*)\n"
|
||||
" (set! (-> a0-4 next) (-> v0-0 process-list (+ v1-4 1)))\n"
|
||||
" (set! (-> a0-4 next) (-> obj process-list (+ v1-4 1)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> v0-0 dead-list next) (-> v0-0 process-list))\n"
|
||||
" (set! (-> v0-0 alive-list process) #f)\n"
|
||||
" (set! (-> v0-0 process-list (+ arg3 -1) next) #f)\n"
|
||||
" (set! (-> v0-0 alive-list prev) (-> v0-0 alive-list))\n"
|
||||
" (set! (-> v0-0 alive-list next) #f)\n"
|
||||
" (set! (-> v0-0 alive-list process) #f)\n"
|
||||
" (set! (-> v0-0 first-gap) (-> v0-0 alive-list))\n"
|
||||
" (set! (-> v0-0 first-shrink) #f)\n"
|
||||
" (set! (-> obj dead-list next) (-> obj process-list))\n"
|
||||
" (set! (-> obj alive-list process) #f)\n"
|
||||
" (set! (-> obj process-list (+ arg3 -1) next) #f)\n"
|
||||
" (set! (-> obj alive-list prev) (-> obj alive-list))\n"
|
||||
" (set! (-> obj alive-list next) #f)\n"
|
||||
" (set! (-> obj alive-list process) #f)\n"
|
||||
" (set! (-> obj first-gap) (-> obj alive-list))\n"
|
||||
" (set! (-> obj first-shrink) #f)\n"
|
||||
" (set!\n"
|
||||
" (-> v0-0 heap base)\n"
|
||||
" (logand -16 (the-as int (&+ (+ (the-as int v0-0) 115) (* 12 arg3))))\n"
|
||||
" (-> obj heap base)\n"
|
||||
" (logand -16 (+ (+ (the-as int obj) 115) (* 12 arg3)))\n"
|
||||
" )\n"
|
||||
" (set! (-> v0-0 heap current) (-> v0-0 heap base))\n"
|
||||
" (set! (-> v0-0 heap top) (&+ (-> v0-0 heap base) arg4))\n"
|
||||
" (set! (-> v0-0 heap top-base) (-> v0-0 heap top))\n"
|
||||
" v0-0\n"
|
||||
" (set! (-> obj heap current) (-> obj heap base))\n"
|
||||
" (set! (-> obj heap top) (&+ (-> obj heap base) arg4))\n"
|
||||
" (set! (-> obj heap top-base) (-> obj heap top))\n"
|
||||
" obj\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "dead-pool-heap", {},
|
||||
parse_hint_json("[\t\t[60, [\"v0\", \"int\"]],\n"
|
||||
"\t\t[61, [\"a0\", \"pointer\"], [\"v0\", \"dead-pool-heap\"]]]"));
|
||||
test_with_expr(
|
||||
func, type, expected, false, "dead-pool-heap", {},
|
||||
parse_cast_json("[\t\t[60, \"v0\", \"int\"],\n"
|
||||
"\t\t[61, \"a0\", \"pointer\"], [61, \"v0\", \"dead-pool-heap\"]]"),
|
||||
"{\"vars\":{\"v0-0\":[\"obj\", \"dead-pool-heap\"]}}");
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprMethod22DeadPoolHeap) {
|
||||
@@ -1399,9 +1405,9 @@ TEST_F(FormRegressionTest, ExprMethod21DeadPoolHeap) {
|
||||
" )\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {},
|
||||
parse_hint_json("[\t\t[5, [\"v1\", \"pointer\"]],\n"
|
||||
"\t\t[13, [\"a0\", \"pointer\"]],\n"
|
||||
"\t\t[25, [\"v1\", \"pointer\"]]]"));
|
||||
parse_cast_json("[\t\t[5, \"v1\", \"pointer\"],\n"
|
||||
"\t\t[13, \"a0\", \"pointer\"],\n"
|
||||
"\t\t[25, \"v1\", \"pointer\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprMethod3DeadPoolHeap) {
|
||||
@@ -1595,7 +1601,7 @@ TEST_F(FormRegressionTest, ExprMethod5DeadPoolHeap) {
|
||||
std::string type = "(function dead-pool-heap int)";
|
||||
std::string expected = "(+ (- -4 (the-as int arg0)) (-> arg0 heap top))";
|
||||
test_with_expr(func, type, expected, false, "", {},
|
||||
parse_hint_json("[[3, [\"v1\", \"int\"], [\"a0\", \"int\"]]]"));
|
||||
parse_cast_json("[[3, \"v1\", \"int\"], [3, \"a0\", \"int\"]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, ExprMethod19DeadPoolHeap) {
|
||||
@@ -1979,7 +1985,7 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPoolHeap) {
|
||||
std::string type = "(function dead-pool-heap type int process)";
|
||||
std::string expected =
|
||||
"(let\n"
|
||||
" ((s4-0 (-> arg0 dead-list next)) (s3-0 #f))\n"
|
||||
" ((s4-0 (-> arg0 dead-list next)) (s3-0 (the-as process #f)))\n"
|
||||
" (let\n"
|
||||
" ((s1-0 (find-gap-by-size arg0 (+ (-> process size) (the-as uint arg2)))))\n"
|
||||
" (cond\n"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
(count uint32)
|
||||
(pad uint8 12))
|
||||
(:methods
|
||||
(new ((allocation symbol) (type-to-make type) (init-count int)) _type_ 0)
|
||||
(new (symbol type int) _type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -9,15 +9,14 @@
|
||||
|
||||
namespace {
|
||||
// the object files to test
|
||||
const std::unordered_set<std::string> g_object_files_to_decompile = {
|
||||
"gcommon",
|
||||
"gstring-h",
|
||||
};
|
||||
const std::unordered_set<std::string> g_object_files_to_decompile = {"gcommon", "gstring-h",
|
||||
"gkernel-h", "gkernel"};
|
||||
|
||||
// the object files to check against a reference in test/decompiler/reference
|
||||
const std::vector<std::string> g_object_files_to_check_against_reference = {
|
||||
"gcommon", // NOTE: this file needs work, but adding it for now just to test the framework.
|
||||
"gstring-h"};
|
||||
"gstring-h", "gkernel-h",
|
||||
/*"gkernel"*/};
|
||||
|
||||
// the functions we expect the decompiler to skip
|
||||
const std::unordered_set<std::string> expected_skip_in_decompiler = {
|
||||
@@ -34,6 +33,7 @@ const std::unordered_set<std::string> expected_skip_in_decompiler = {
|
||||
"return-from-thread-dead", // kernel -> user
|
||||
"return-from-thread", // kernel -> user
|
||||
"return-from-exception", // ps2 exception -> ps2 user
|
||||
"run-function-in-process", // temp while stack vars aren't supported.
|
||||
// pskernel
|
||||
"kernel-check-hardwired-addresses", // ps2 ee kernel debug hook
|
||||
"kernel-read-function", // ps2 ee kernel debug hook
|
||||
@@ -47,25 +47,50 @@ const std::unordered_set<std::string> skip_in_compiling = {
|
||||
//////////////////////
|
||||
|
||||
// these functions are not implemented by the compiler in OpenGOAL, but are in GOAL.
|
||||
"abs", "ash", "min", "max", "lognor",
|
||||
"abs",
|
||||
"ash",
|
||||
"min",
|
||||
"max",
|
||||
"lognor",
|
||||
// weird PS2 specific debug registers:
|
||||
"breakpoint-range-set!",
|
||||
// these require 128-bit integers. We want these eventually, but disabling for now to focus
|
||||
// on more important issues.
|
||||
"(method 3 vec4s)", "(method 2 vec4s)", "qmem-copy<-!", "qmem-copy->!", "(method 2 array)",
|
||||
"(method 3 vec4s)",
|
||||
"(method 2 vec4s)",
|
||||
"qmem-copy<-!",
|
||||
"qmem-copy->!",
|
||||
"(method 2 array)",
|
||||
"(method 3 array)",
|
||||
// does weird stuff with the type system.
|
||||
"print", "printl", "inspect",
|
||||
"print",
|
||||
"printl",
|
||||
"inspect",
|
||||
// inline assembly
|
||||
"valid?"};
|
||||
"valid?",
|
||||
|
||||
//////////////////////
|
||||
// GKERNEL-H
|
||||
//////////////////////
|
||||
// bitfields, possibly inline assembly
|
||||
"(method 2 handle)",
|
||||
};
|
||||
|
||||
// The decompiler does not attempt to insert forward definitions, as this would be part of an
|
||||
// unimplemented full-program type analysis pass. For now, we manually specify all functions
|
||||
// that should have a forward definition here.
|
||||
const std::string g_forward_type_defs =
|
||||
// used out of order
|
||||
"(define-extern name= (function basic basic symbol))\n"
|
||||
// todo - check if recursive?
|
||||
"(define-extern fact (function int int))";
|
||||
// recursive
|
||||
"(define-extern fact (function int int))\n"
|
||||
// gkernel-h
|
||||
"(declare-type process basic)\n"
|
||||
"(declare-type stack-frame basic)\n"
|
||||
"(declare-type state basic)\n"
|
||||
"(declare-type cpu-thread basic)\n"
|
||||
"(declare-type dead-pool basic)\n"
|
||||
"(declare-type event-message-block structure)\n";
|
||||
|
||||
// default location for the data. It can be changed with a command line argument.
|
||||
std::string g_iso_data_path = "";
|
||||
@@ -252,7 +277,7 @@ TEST_F(OfflineDecompilation, TypeAnalysis) {
|
||||
int failed_count = 0;
|
||||
db->for_each_function([&](decompiler::Function& func, int, decompiler::ObjectFileData&) {
|
||||
if (!func.suspected_asm) {
|
||||
if (!func.ir2.env.has_type_analysis()) {
|
||||
if (!func.ir2.env.has_type_analysis() || !func.ir2.types_succeeded) {
|
||||
lg::error("Function {} failed types", func.guessed_name.to_string());
|
||||
failed_count++;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "common/util/Trie.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/all_jak1_symbols.h"
|
||||
#include "common/util/json_util.h"
|
||||
#include "common/util/Range.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -38,4 +40,41 @@ TEST(CommonUtil, Trie) {
|
||||
EXPECT_FALSE(test.lookup("path1") == nullptr);
|
||||
EXPECT_TRUE(test.lookup("path-") == nullptr);
|
||||
EXPECT_FALSE(test.lookup("path1-k") == nullptr);
|
||||
}
|
||||
|
||||
TEST(CommonUtil, StripComments) {
|
||||
std::string test_input =
|
||||
R"(
|
||||
test "asdf /* y */ /////a\"bcd"
|
||||
///////// commented out!
|
||||
// /* also commented out
|
||||
|
||||
/* this is a block comment "with an unterminated string.
|
||||
*/ and its done
|
||||
)";
|
||||
|
||||
std::string test_expected =
|
||||
R"(
|
||||
test "asdf /* y */ /////a\"bcd"
|
||||
|
||||
|
||||
|
||||
and its done
|
||||
)";
|
||||
|
||||
EXPECT_EQ(strip_cpp_style_comments(test_input), test_expected);
|
||||
}
|
||||
|
||||
TEST(CommonUtil, RangeIterator) {
|
||||
std::vector<int> result = {}, expected_result = {4, 5, 6, 7};
|
||||
|
||||
for (auto x : Range<int>(4, 8)) {
|
||||
result.push_back(x);
|
||||
}
|
||||
|
||||
EXPECT_EQ(result, expected_result);
|
||||
EXPECT_TRUE(Range<int>().empty());
|
||||
EXPECT_FALSE(Range<int>(3, 4).empty());
|
||||
EXPECT_EQ(1, Range<int>(3, 4).size());
|
||||
EXPECT_EQ(4, Range<int>(4, 8).size());
|
||||
}
|
||||
Reference in New Issue
Block a user