From 571dbbbb9d55603c2030791ade3bde5b5c89cf0e Mon Sep 17 00:00:00 2001 From: pannous Date: Tue, 10 Dec 2024 11:25:59 +0100 Subject: [PATCH] NEW LIST with std::shared_ptr items; --- source/List.h | 200 ++++++++++++++++++----- source/Map.h | 3 +- source/Util.h | 2 +- source/own_merge/binary-reader-linker.cc | 2 +- source/own_merge/binary-writer.cc | 2 + source/own_merge/common.cc | 15 +- source/own_merge/common.h | 4 +- source/own_merge/ir.h | 22 ++- source/own_merge/wasm-link.h | 98 ++++++----- source/tests.cpp | 42 ++++- source/wasm_emitter.cpp | 9 +- source/wasm_linker.cpp | 4 +- 12 files changed, 293 insertions(+), 110 deletions(-) diff --git a/source/List.h b/source/List.h index cc3264b4..19d4c861 100644 --- a/source/List.h +++ b/source/List.h @@ -7,7 +7,7 @@ #include // OK in WASM! -#define LIST_DEFAULT_CAPACITY 100 // todo grow doesn't work, BREAKS SYSTEM! +#define LIST_DEFAULT_CAPACITY 10 // todo grow doesn't work, BREAKS SYSTEM! #define LIST_MAX_CAPACITY 0x1000000000l // debug only! #include "Util.h" @@ -34,17 +34,20 @@ void heapSort(S arr[], int n, float (valuator)(S &)); template void heapSort(S arr[], int n); +#include // ⚠️ references to List items are NOT safe during list construction due to List::grow() ( invalid / forbidden ) template class List { public: + + std::shared_ptr items; +// S *items = 0;// 32bit pointers in wasm! In C++ References cannot be put into an array, if you try you get int header = array_header_32;// wasn't this moved down ? Type _type{};// reflection on template class S int size_ = 0; int capacity = LIST_DEFAULT_CAPACITY;// grow() by factor 2 internally on demand // previous entries must be aligned to int64! - S *items = 0;// 32bit pointers in wasm! In C++ References cannot be put into an array, if you try you get // List error: 'items' declared as a pointer to a reference of type // todo item references are UNSAFE after grow() @@ -55,13 +58,12 @@ class List { // capacity = size; // items = (S *) calloc(size, sizeof(S)); // } - - List(size_t size = LIST_DEFAULT_CAPACITY) { - capacity = size; - items = (S *) calloc(size, sizeof(S)); + List(size_t initial_size = LIST_DEFAULT_CAPACITY) : size_(initial_size) { + if (initial_size > 0) { + items = std::make_unique(initial_size); + } } - List(const List &old) : items(old.items) { // todo: memcopy? size_ = old.size_; } @@ -135,13 +137,17 @@ class List { // check_silent(count < LIST_MAX_CAPACITY) size_ = count; if (share) - items = args; + items = std::shared_ptr(args, [](S *p) { delete[] p; }); else { - if (capacity < size_ or not items) { - items = (S *) calloc(size_ + 1, sizeof(S)); - capacity = size_; + // Create a new array and copy elements + items = std::shared_ptr(new S[count], std::default_delete()); + // Use memcpy for trivially copyable types + if constexpr (std::is_trivially_copyable::value) { + std::memcpy(items.get(), args, count * sizeof(S)); + } else + for (int i = 0; i < count; ++i) { + items[i] = args[i]; } - memcpy((void *) items, (void *) args, count * sizeof(S)); } } @@ -172,16 +178,19 @@ class List { void grow() { // warn("grow"); auto new_size = capacity * 2; -// check_silent(new_size < LIST_MAX_CAPACITY); - S *neu = (S *) alloc(new_size, sizeof(S)); - memcpy((void *) neu, (void *) items, capacity * sizeof(S)); - if (items)free(items); // EXC_BAD_ACCESS (code=2, address=0x250000002d) -// warn("⚠️ List.grow memcpy messes with existing references! -// Todo: add List / wrap S with shared_pointer ?"); -// indeed List FUCKS UP just by growing even without references -// malloc: Heap corruption detected, free list is damaged - items = neu; - capacity = new_size; + resize(new_size); +// +// if (new_size < 0)error("List capacity overflow"); +//// check_silent(new_size < LIST_MAX_CAPACITY); +// S *neu = (S *) alloc(new_size, sizeof(S)); +// memcpy((void *) neu, (void *) items, capacity * sizeof(S)); +// if (items)free(items); // EXC_BAD_ACCESS (code=2, address=0x250000002d) +//// warn("⚠️ List.grow memcpy messes with existing references! +//// Todo: add List / wrap S with shared_pointer ?"); +//// indeed List FUCKS UP just by growing even without references +//// malloc: Heap corruption detected, free list is damaged +// items = neu; +// capacity = new_size; } S &add(S s) { @@ -214,7 +223,7 @@ class List { S &operator[](uint64 index) const { if (index < 0 or index >= size_) /* and const means not auto_grow*/ - error("List index out of range : %d > %d"s % (int64) index % size_); + error("List index out of range : %d > %d"s % (int64) index % size_); return items[index]; } @@ -250,11 +259,11 @@ class List { } S *begin() const { - return items; + return items.get(); } S *end() const { - return &items[size_]; + return items.get() + size_; } @@ -285,18 +294,18 @@ class List { heapSort(items, size_, comparator); } - List &sort(bool (comparator)(S &, S &)) { - heapSort(items, size_, comparator); + List &sort(bool (*comparator)(S &, S &)) { + heapSort(items.get(), size_, comparator); // Use raw pointer from unique_ptr return *this; } List &sort(float (valuator)(S &a)) { - heapSort(items, size_, valuator); + heapSort(items.get(), size_, valuator); return *this; } List &sort() { - heapSort(items, size_); + heapSort(items.get(), size_); return *this; } @@ -321,8 +330,8 @@ class List { } void clear() { - free(items); - items = (S *) alloc(LIST_DEFAULT_CAPACITY, sizeof(S)); + items.reset(); // Release the current memory managed by unique_ptr + items = std::make_unique(LIST_DEFAULT_CAPACITY); // Allocate new memory size_ = 0; } @@ -332,11 +341,21 @@ class List { memmove(items + pos, items + pos + 1, size_ - pos); size_--; } - bool remove(short position) { - if (position < 0 or size_ <= 0 or position >= size_)return false; - memmove((void *) (items + position), (void *) (items + position + 1), (size_ - position) * sizeof(S)); - size_--; + if (position < 0 || size_ <= 0 || position >= size_) return false; + + if constexpr (std::is_trivially_copyable::value) { + // Use memmove for trivially copyable types + std::memmove(items.get() + position, items.get() + position + 1, (size_ - position - 1) * sizeof(S)); + } else { + // Use a loop for non-trivially copyable types + for (size_t i = position; i < size_ - 1; ++i) { + items[i] = std::move(items[i + 1]); // Move assignment for safety + } + // Explicitly destroy the last object + items[size_ - 1].~S(); + } + --size_; return true; } @@ -384,11 +403,11 @@ class List { } - S *find(bool (*lambda)(S *)) { - for (S *s: *this) - if (lambda(s))return s; - return 0; - } + S *find(bool (*lambda)(S *)) { + for (S *s: *this) + if (lambda(s))return s; + return 0; + } String join(String string) { String s; @@ -424,9 +443,15 @@ class List { return last(); } - void resize(long new_size) { - if (new_size >= capacity) - grow(); + void resize(size_t new_size) { + std::shared_ptr new_items(new S[new_size], std::default_delete()); + // Copy old items to new_items (up to the smaller of old and new sizes) + if (items) { + for (size_t i = 0; i < new_size; ++i) { + new_items[i] = std::move(items[i]); + } + } + items = new_items; size_ = new_size; } @@ -449,7 +474,7 @@ class List { // } S *data() const { - return items; + return items.get(); } S &first() { @@ -472,6 +497,93 @@ class List { // insert(item); add(item); } + + +private: + + static void heapSort(S *arr, size_t n) { + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + for (int i = n - 1; i > 0; i--) { + std::swap(arr[0], arr[i]); + heapify(arr, i, 0); + } + } + + + static void heapSort(S *arr, size_t n, bool (*comparator)(S &, S &)) { + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i, comparator); + + for (int i = n - 1; i > 0; i--) { + std::swap(arr[0], arr[i]); + heapify(arr, i, 0, comparator); + } + } + + static void heapSort(S *arr, size_t n, float (*valuator)(S &)) { + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i, valuator); + + for (int i = n - 1; i > 0; i--) { + std::swap(arr[0], arr[i]); + heapify(arr, i, 0, valuator); + } + } + + + static void heapify(S *arr, size_t n, size_t i) { + size_t largest = i; // Initialize largest as root + size_t left = 2 * i + 1; + size_t right = 2 * i + 2; + + if (left < n && arr[left] > arr[largest]) + largest = left; + + if (right < n && arr[right] > arr[largest]) + largest = right; + + if (largest != i) { + std::swap(arr[i], arr[largest]); + heapify(arr, n, largest); + } + } + + + static void heapify(S *arr, size_t n, size_t i, bool (*comparator)(S &, S &)) { + size_t largest = i; // Initialize largest as root + size_t left = 2 * i + 1; + size_t right = 2 * i + 2; + + if (left < n && comparator(arr[left], arr[largest])) + largest = left; + + if (right < n && comparator(arr[right], arr[largest])) + largest = right; + + if (largest != i) { + std::swap(arr[i], arr[largest]); + heapify(arr, n, largest, comparator); + } + } + + static void heapify(S *arr, size_t n, size_t i, float (*valuator)(S &)) { + size_t largest = i; // Initialize largest as root + size_t left = 2 * i + 1; + size_t right = 2 * i + 2; + + if (left < n && valuator(arr[left]) > valuator(arr[largest])) + largest = left; + + if (right < n && valuator(arr[right]) > valuator(arr[largest])) + largest = right; + + if (largest != i) { + std::swap(arr[i], arr[largest]); + heapify(arr, n, largest, valuator); + } + } }; void print(List list); diff --git a/source/Map.h b/source/Map.h index 76d93387..e42849eb 100644 --- a/source/Map.h +++ b/source/Map.h @@ -26,10 +26,9 @@ template class Map { public: // todo careful Map eq int capacity = MAP_INITIAL_CAPACITY;// initial + int _size = 0; S *keys = (S *) calloc(sizeof(S), capacity); T *values = (T *) calloc(sizeof(T), capacity); - int _size = 0; - int map_header = map_header_32; [[maybe_unused]] T defaulty; diff --git a/source/Util.h b/source/Util.h index 30d550c8..374204b0 100644 --- a/source/Util.h +++ b/source/Util.h @@ -101,7 +101,7 @@ typedef const char *chars; typedef byte *bytes; // silent ++ -#define check_silent(test) if(!(test)){printf("\nNOT PASSING %s\n",#test);backtrace_line()} +#define check_silent(test, ...) if(!(test)){printf("\nNOT PASSING %s\n",#test);backtrace_line()} //#define check_is(α, β) if((α)!=(β)){printf("%s != %s :\n",#α,#β);print(α);print(" != ");print(β);backtrace_line()} #define check_is(α, β) if((α)!=(β)){printf("%s != %s :\n",#α,#β);print(α);print(" != ");print(β);backtrace_exit();} diff --git a/source/own_merge/binary-reader-linker.cc b/source/own_merge/binary-reader-linker.cc index 6a4935e0..e431d513 100644 --- a/source/own_merge/binary-reader-linker.cc +++ b/source/own_merge/binary-reader-linker.cc @@ -296,7 +296,7 @@ namespace wabt { read_options.read_debug_names = true; read_options.fail_on_custom_section_error = false; read_options.stop_on_first_error = false; - return ReadBinary(input_info->data.items, input_info->data.size_, &reader, + return ReadBinary(input_info->data.items.get(), input_info->data.size_, &reader, (const ReadBinaryOptions) read_options); // return ReadBinary(input_info->data.items, input_info->data.size(), &reader, (const ReadBinaryOptions) read_options); diff --git a/source/own_merge/binary-writer.cc b/source/own_merge/binary-writer.cc index cb496e75..dedb0844 100644 --- a/source/own_merge/binary-writer.cc +++ b/source/own_merge/binary-writer.cc @@ -106,6 +106,7 @@ namespace wabt { fprintf(stderr, "%s:%d: allocation failed\n", __FILE__, __LINE__) struct RelocSection { + RelocSection() = default; RelocSection(const char *name, Index index) : name(name), section_index(index) {} @@ -116,6 +117,7 @@ namespace wabt { class Symbol { public: + Symbol() = default; struct Function { static const SymbolType type = SymbolType::Function; Index index; diff --git a/source/own_merge/common.cc b/source/own_merge/common.cc index f9e7e7c6..561dcf77 100644 --- a/source/own_merge/common.cc +++ b/source/own_merge/common.cc @@ -41,9 +41,9 @@ String StringPrintf(const char *format, ...) { List buffer(len); va_end(args); - vsnprintf(buffer.items, len, format, args_copy); + vsnprintf(buffer.items.get(), len, format, args_copy); va_end(args_copy); - return String(buffer.items, (int) len - 1); + return String(buffer.items.get(), (int) len - 1); } #pragma clang diagnostic pop @@ -53,6 +53,13 @@ namespace wabt { Reloc::Reloc(RelocType type, Offset offset, Index index, int32_t addend) : type(type), offset(offset), index(index), addend(addend) {} + + // Default constructor for List + Reloc::Reloc() : type(RelocType::First), + offset(0), + index(0), + addend(0) {} + const char *g_kind_name[] = {"func", "table", "memory", "global", "tag"}; // WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_kind_name) == kExternalKindCount); @@ -86,7 +93,7 @@ namespace wabt { } size_t old_size = out_data->size(); out_data->resize(old_size + bytes_read); - memcpy(out_data->items + old_size, buffer, bytes_read); + memcpy(out_data->items.get() + old_size, buffer, bytes_read); } } @@ -135,7 +142,7 @@ namespace wabt { } out_data->resize(size); - if (size != 0 && fread(out_data->items, size, 1, infile) != 1) { + if (size != 0 && fread(out_data->items.get(), size, 1, infile) != 1) { fprintf(stderr, "%s: fread failed: %s\n", filename_cstr, strerror(errno)); fclose(infile); return Result::Error; diff --git a/source/own_merge/common.h b/source/own_merge/common.h index fe5aac83..77a75736 100644 --- a/source/own_merge/common.h +++ b/source/own_merge/common.h @@ -369,7 +369,9 @@ namespace wabt { static const int kRelocTypeCount = WABT_ENUM_COUNT(RelocType); struct Reloc { - Reloc(RelocType, size_t offset, Index index, int32_t addend = 0); + Reloc(); + + Reloc(RelocType, size_t offset, Index index, int32_t addend = 0); RelocType type; size_t offset; diff --git a/source/own_merge/ir.h b/source/own_merge/ir.h index 90cb911f..1f68c096 100644 --- a/source/own_merge/ir.h +++ b/source/own_merge/ir.h @@ -35,7 +35,10 @@ //#include "string-view.h" namespace wabt { + class Expr; + typedef List ExprList; +// class ExprList; struct Module; enum class VarType { @@ -463,7 +466,7 @@ namespace wabt { public: WABT_DISALLOW_COPY_AND_ASSIGN(Expr); - Expr() = delete; +// Expr() = delete; virtual ~Expr() = default; @@ -471,8 +474,18 @@ namespace wabt { Location loc; - protected: - explicit Expr(ExprType type, const Location &loc = Location()) + Expr() = default; + + Expr(std::nullptr_t) {} +// private: + // Private default constructor + +// friend class List; // Allow List to access the default constructor +// friend class Expr; // Allow ExprList to access the default constructor +// friend class ExprMixin<>; + // Protected default constructor + + explicit Expr(ExprType type, const Location &loc = Location()) : loc(loc), type_(type) {} ExprType type_; @@ -958,7 +971,8 @@ namespace wabt { public: WABT_DISALLOW_COPY_AND_ASSIGN(ModuleField); - ModuleField() = delete; + ModuleField() = default; +// ModuleField() = delete; virtual ~ModuleField() = default; diff --git a/source/own_merge/wasm-link.h b/source/own_merge/wasm-link.h index 385c99c5..449651f2 100644 --- a/source/own_merge/wasm-link.h +++ b/source/own_merge/wasm-link.h @@ -26,24 +26,27 @@ #include "../List.h" namespace wabt { - namespace link { + namespace link { - class LinkerInputBinary; + class LinkerInputBinary; + + struct Export { + ExternalKind kind; + String name; + Index index; + }; - struct Export { - ExternalKind kind; - String name; - Index index; - }; + struct ExportInfo { + ExportInfo() = default; - struct ExportInfo { - ExportInfo(const Export *export_, LinkerInputBinary *binary) : export_(export_), binary(binary) {} - const Export *export_; - LinkerInputBinary *binary; - }; + ExportInfo(const Export *export_, LinkerInputBinary *binary) : export_(export_), binary(binary) {} - struct FunctionImport { + const Export *export_; + LinkerInputBinary *binary; + }; + + struct FunctionImport { String module_name; String name; Index type_index; @@ -54,40 +57,47 @@ namespace wabt { Index index;// implicit in list, but needed to link duplicate imports Index foreign_index;// after link to foreign export ExportInfo *linked_function; + + FunctionImport() = default; // Default constructor }; - struct GlobalImport { - String module_name; - String name; - wabt::Type type; - bool mutable_; - bool active = true; - LinkerInputBinary *foreign_binary; - int foreign_index; + struct GlobalImport { + String module_name; + String name; + wabt::Type type; + bool mutable_; + bool active = true; + LinkerInputBinary *foreign_binary; + int foreign_index; int relocated_global_index; - }; - struct DataSegment { - Index memory_index; - Address64 offset; - const uint8_t *data; - size_t size; - }; + GlobalImport() = default; // Default constructor + }; + + struct DataSegment { + Index memory_index; + Address64 offset; + const uint8_t *data; + size_t size; + DataSegment() = default; // Default constructor + }; - struct Func { -// Var type_var; + struct Func { Index index;// code index String name;// set later in name section Index type_index;// => -// wabt::FuncSignature sig; + + Func() = default; // Default constructor }; - struct Section { + struct Section { WABT_DISALLOW_COPY_AND_ASSIGN(Section); Section(); +// Section() = default; // Default constructor + ~Section(); /* The binary to which this section belongs */ @@ -103,35 +113,35 @@ namespace wabt { size_t payload_increase;// after reloc LEB inserts /* For known sections, the count of the number of elements in the section */ - Index count; + Index count; - union { + union { /* DATA section data */ List *data_segments; /* MEMORY section data */ uint64_t initial; - } data; + } data; - /* The offset at which this section appears within the combined output section. */ - size_t output_payload_offset; - }; + /* The offset at which this section appears within the combined output section. */ + size_t output_payload_offset; + }; typedef List
SectionPtrVector; - class LinkerInputBinary { - public: - WABT_DISALLOW_COPY_AND_ASSIGN(LinkerInputBinary); + class LinkerInputBinary { + public: + WABT_DISALLOW_COPY_AND_ASSIGN(LinkerInputBinary); LinkerInputBinary(const char *filename, List &data); - Index RelocateFuncIndex(Index findex); + Index RelocateFuncIndex(Index findex); Index RelocateTypeIndex(Index index) const; Index RelocateMemoryIndex(Index memory_index) const; - Index RelocateGlobalIndex(Index index); + Index RelocateGlobalIndex(Index index); Index RelocateTable(Index findex) const; @@ -174,7 +184,7 @@ namespace wabt { bool needs_relocate{};// keep runtime untouched! }; - } // namespace link + } // namespace link } // namespace wabt #endif /* WABT_LINK_H_ */ diff --git a/source/tests.cpp b/source/tests.cpp index 91b9d4f0..1bd2acca 100644 --- a/source/tests.cpp +++ b/source/tests.cpp @@ -20,6 +20,34 @@ #include "WitReader.h" #include "types/Number.h" +template +void testListGrowth() { + List list; // List even better! + for (int i = 0; i < 1000; i++) { + list.add(*new S()); + } + check_eq(list.size(), 1000); + for (int i = 0; i < 10; i++) { // 20 => growth by 2^20!!! + list.grow(); + } + check(list.capacity > 100000); +} + +void testListGrowthWithStrings() { + List list; + for (int i = 0; i < 1000; i++) { + list.add(String(i)); + } + check_eq(list.size(), 1000); + check_eq(list[999], new String(999)); + for (int i = 0; i < 10; i++) { + list.grow();// lots of deep copy!! + } + check(list.capacity > 100000); + check_eq(list[999], new String(999)); +} + + //void testDwarf(); //void testSourceMap(); void testAssert() { @@ -3533,11 +3561,19 @@ void pleaseFix() { // 2022-12-28 : 3 sec WITH runtime_emit, wasmedge on M1 WOW ALL TESTS PASSING // ⚠️ CANNOT USE assert_emit in WASM! ONLY via void testRun(); void testCurrent() { +// List axx = {1, 2, 3}; // testNamedDataSections(); - assert_is("1 2 3", Node(1, 2, 3, 0)) - +// testListGrowth();// pointer to a reference error + assert_emit("x='abcde';x#4='f';x[3]", 'f'); + + testListGrowth(); + testListGrowth(); + testListGrowth(); + testListGrowth(); + testListGrowth(); +// testListGrowth(); + testListGrowthWithStrings(); testForLoops(); - testParamizedKeys(); testAutoSmarty(); testArguments(); // testSinus(); diff --git a/source/wasm_emitter.cpp b/source/wasm_emitter.cpp index 50b86671..7d3e9abc 100644 --- a/source/wasm_emitter.cpp +++ b/source/wasm_emitter.cpp @@ -743,9 +743,10 @@ Code emitWasmArray(Node &node, Function &context) { return code; } -// just register the name for custom section here +// just register the name for custom section here, one per each data-object like string, array, object, … +// only for debugging so add strip option void addNamedDataSegment(int pointer, Node &node) { - String name = "data"; + String name = "data"; // todo add type and counter, e.g. string-1, string-2, … array-1, … if (not node.name.empty()) name = node.name; else if (node.parent and not node.parent->name.empty()) @@ -754,7 +755,7 @@ void addNamedDataSegment(int pointer, Node &node) { // { // todo: end this segment even if next one not named. named_data_segments++; data_segment_offsets.add(pointer); - data_segment_names.add(name); + data_segment_names.add(name); // only for debugging so add strip option // todo: un-redundant: // referenceIndices.insert_or_assign(node.name, pointer); // referenceDataIndices.insert_or_assign(node.name, pointer + array_header_length); @@ -3717,7 +3718,7 @@ Code emitDataSections() { // needs memory section too! // todo: WHY cant it start at 0? wx todo: module offset + module data length datas.addByte(0x0b);// mode: active? auto size_of_data = end - offset; - check(size_of_data >= 0, "data segment beyound end"); + check_silent(size_of_data >= 0, "data segment beyound end"); datas.addInt(size_of_data); const Code &actual_data = Code((bytes) data + offset, size_of_data); datas.add(actual_data);// now comes the actual data encodeVector()? nah manual here! diff --git a/source/wasm_linker.cpp b/source/wasm_linker.cpp index 98914813..eaa903e2 100644 --- a/source/wasm_linker.cpp +++ b/source/wasm_linker.cpp @@ -405,7 +405,7 @@ Section::~Section() { LinkerInputBinary::LinkerInputBinary(const char *filename, List &data) : name(filename), - data(data.items, data.size_, false), + data(data.items.get(), data.size_, false), // size(data.size_), active_function_imports(0), active_global_imports(0), @@ -938,8 +938,8 @@ bool Linker::WriteCombinedSection(SectionType section_code, const SectionPtrVect struct FuncInfo { + FuncInfo() = default; FuncInfo(const Func *export_, LinkerInputBinary *binary) : func(export_), binary(binary) {} - const Func *func{}; LinkerInputBinary *binary{}; };