1+ // Copyright Danyil Melnytskyi 2025-Present
2+ //
3+ // Distributed under the Boost Software License, Version 1.0.
4+ // (See accompanying file LICENSE or copy at
5+ // http://www.boost.org/LICENSE_1_0.txt)
6+
17#include < base/language/precompiled.hpp>
28#include < run_time/AttachA_CXX.hpp>
39#include < run_time/library/bytes.hpp>
4-
10+ #include < run_time/util/tools.hpp>
11+ #include < util/exceptions.hpp>
512using namespace art ;
613
714namespace language_parsers {
8-
9-
1015 template <class T >
1116 T read_value (files::FileHandle& file) {
1217 T value;
@@ -26,45 +31,254 @@ namespace language_parsers {
2631 return ustring ((char *)string_value.data (), string_value.size ());
2732 }
2833
34+ list_array<ustring> read_type_string (files::FileHandle& file) {
35+ uint64_t size = read_value<uint64_t >(file);
36+ list_array<ustring> res;
37+ res.reserve (size);
38+ for (uint64_t i = 0 ; i < size; i++)
39+ res.push_back (read_string (file));
40+ return res;
41+ }
42+
43+ ValueMeta read_value_meta (files::FileHandle& file) {
44+ union tttt_ {
45+ struct {
46+ VType type;
47+ uint8_t use_gc : 1 ;
48+ uint8_t allow_edit : 1 ;
49+ uint8_t as_ref : 1 ;
50+ uint32_t val_len;
51+ };
52+
53+ uint32_t raw;
54+
55+ tttt_ (uint32_t r)
56+ : raw (r) {}
57+ } res (read_value<uint32_t >(file));
58+
59+ return ValueMeta (res.type , res.use_gc , res.allow_edit , res.val_len , res.as_ref );
60+ }
61+
62+ ValueItem readAny (files::FileHandle& file) {
63+ auto data_res = read_byte_arr (file);
64+ size_t read_pointer = 0 ;
65+ auto res = art::reader::readAny (data_res, data_res.size (), read_pointer);
66+ if (read_pointer != data_res.size ())
67+ throw InvalidEncodingException (" Value size mismatch, readed less bytes than encoded" );
68+ return std::move (res);
69+ }
70+
71+ // symbol, decl, hash
72+ std::tuple<ustring, FuncHandle::inner_handle*, size_t > read_function (files::FileHandle& file) {
73+ ustring symbol = read_string (file);
74+ ustring cross_compiler_version = read_string (file);
75+ std::vector<uint8_t > _opcode = read_byte_arr (file);
76+ bool is_cheap = read_value<bool >(file);
77+ uint64_t hash = art::hash<uint8_t >()(_opcode.data (), _opcode.size ());
78+ return {symbol, new FuncHandle::inner_handle (std::move (_opcode), is_cheap, cross_compiler_version.empty () ? nullptr : new ustring (cross_compiler_version)), hash};
79+ }
80+
81+ VirtualTable read_type_info (files::FileHandle& file) {
82+ uint64_t structure_bytes = read_value<uint64_t >(file);
83+ bool allow_auto_copy;
84+
85+
86+ list_array<MethodInfo> methods;
87+ list_array<ValueInfo> values;
88+ art::shared_ptr<FuncEnvironment> destructor;
89+ art::shared_ptr<FuncEnvironment> copy;
90+ art::shared_ptr<FuncEnvironment> move;
91+ art::shared_ptr<FuncEnvironment> compare;
92+ art::shared_ptr<FuncEnvironment> constructor;
93+ {
94+ union ttttt_ {
95+ struct {
96+ bool declared_destructor;
97+ bool declared_copy;
98+ bool declared_move;
99+ bool declared_compare;
100+ bool declared_constructor;
101+ bool allow_auto_copy;
102+ };
103+
104+ uint64_t raw;
105+
106+ ttttt_ (uint64_t r)
107+ : raw (r) {}
108+ } flags (read_value<uint64_t >(file));
109+
110+ allow_auto_copy = flags.allow_auto_copy ;
111+ if (flags.declared_destructor )
112+ destructor = new FuncEnvironment (std::get<1 >(read_function (file)), true );
113+ if (flags.declared_copy )
114+ copy = new FuncEnvironment (std::get<1 >(read_function (file)), true );
115+ if (flags.declared_move )
116+ move = new FuncEnvironment (std::get<1 >(read_function (file)), true );
117+ if (flags.declared_compare )
118+ compare = new FuncEnvironment (std::get<1 >(read_function (file)), true );
119+ if (flags.declared_constructor )
120+ constructor = new FuncEnvironment (std::get<1 >(read_function (file)), true );
121+ }
122+
123+ {
124+ uint64_t methods_count = read_value<uint64_t >(file);
125+ methods.reserve (methods_count);
126+ for (uint64_t i = 0 ; i < methods_count; i++) {
127+ auto [name, decl, hash] = read_function (file);
128+ art::shared_ptr<FuncEnvironment> method = new FuncEnvironment (decl, true );
129+ ClassAccess access = read_value<ClassAccess>(file);
130+ art::ustring owner_name = read_string (file);
131+ list_array<ValueMeta> return_values;
132+ list_array<list_array<std::pair<ValueMeta, art::ustring>>> arguments;
133+ list_array<MethodTag> tags;
134+ {
135+ uint64_t return_values_count = read_value<uint64_t >(file);
136+ return_values.reserve (return_values_count);
137+ for (uint64_t j = 0 ; j < return_values_count; j++)
138+ return_values.push_back (read_value_meta (file));
139+ }
140+ {
141+ uint64_t arguments_count = read_value<uint64_t >(file);
142+ arguments.reserve (arguments_count);
143+ for (uint64_t j = 0 ; j < arguments_count; j++) {
144+ list_array<std::pair<ValueMeta, art::ustring>> argument_variant;
145+ uint64_t argument_variant_count = read_value<uint64_t >(file);
146+ argument_variant.reserve (argument_variant_count);
147+ for (uint64_t n = 0 ; n < argument_variant_count; n++) {
148+ auto meta = read_value_meta (file);
149+ argument_variant.push_back ({meta, read_string (file)});
150+ }
151+ arguments.push_back (std::move (argument_variant));
152+ }
153+ }
154+ {
155+ uint64_t tags_count = read_value<uint64_t >(file);
156+ tags.reserve (tags_count);
157+ for (uint64_t j = 0 ; j < tags_count; j++) {
158+ MethodTag tag;
159+ tag.name = read_string (file);
160+ tag.enviro = new FuncEnvironment (std::get<1 >(read_function (file)), true );
161+ tag.value = readAny (file);
162+ tags.push_back (std::move (tag));
163+ }
164+ }
165+ methods.push_back (MethodInfo (name, method, access, std::move (return_values), std::move (arguments), std::move (tags), owner_name));
166+ }
167+ }
168+ {
169+ uint64_t values_count = read_value<uint64_t >(file);
170+ values.reserve (values_count);
171+ for (uint64_t i = 0 ; i < values_count; i++) {
172+ ustring name = read_string (file);
173+ size_t offset = read_value<uint64_t >(file);
174+ ValueMeta type = read_value_meta (file);
175+ uint16_t bit_used = read_value<uint16_t >(file);
176+ uint8_t bit_offset = read_value<uint8_t >(file);
177+ bool inlined = read_value<bool >(file);
178+ bool allow_abstract_assign = read_value<bool >(file);
179+ ClassAccess access = read_value<ClassAccess>(file);
180+ list_array<ValueTag> tags;
181+ {
182+ uint64_t tags_count = read_value<uint64_t >(file);
183+ tags.reserve (tags_count);
184+ for (uint64_t j = 0 ; j < tags_count; j++) {
185+ MethodTag tag;
186+ tag.name = read_string (file);
187+ tag.enviro = new FuncEnvironment (std::get<1 >(read_function (file)), true );
188+ tag.value = readAny (file);
189+ tags.push_back (std::move (tag));
190+ }
191+ }
192+ bool zero_after_cleanup = read_value<bool >(file);
193+ values.push_back (ValueInfo (name, offset, type, bit_used, bit_offset, inlined, allow_abstract_assign, access, tags, zero_after_cleanup));
194+ }
195+ }
196+
197+ char mode = read_value<char >(file);
198+ switch (mode) {
199+ case ' s' :
200+ return AttachAVirtualTable::create (methods, values, destructor, copy, move, compare, structure_bytes, allow_auto_copy, constructor);
201+ case ' d' : {
202+ auto res = new AttachADynamicVirtualTable (methods, values, destructor, copy, move, compare, structure_bytes, allow_auto_copy);
203+ res->constructor = constructor;
204+ return res;
205+ }
206+ default :
207+ throw InvalidEncodingException (" Unrecognized virtual table type: " + std::string (1 , mode));
208+ }
209+ }
210+
29211 patch_list precompiled::handle_init (files::FileHandle& file) {
30212 lock_guard guard (mutex);
31213 patch_list build_patch_list;
32- auto local_functions = declared_functions[file.get_path ()];
33- std::unordered_set<ustring, hash<ustring>> readed_functions;
34- uint64_t _functions_count;
35- file.read_fixed ((uint8_t *)&_functions_count, (uint32_t )sizeof (uint64_t ));
36- _functions_count = bytes::convert_endian<bytes::Endian::little>(_functions_count);
37- for (uint64_t i = 0 ; i < _functions_count; i++) {
38- ustring symbol = read_string (file);
39- ustring cross_compiler_version = read_string (file);
40- std::vector<uint8_t > _opcode = read_byte_arr (file);
41- bool is_cheap = read_value<bool >(file);
42-
43- if (symbol.starts_with (' \2 ' )) {
44- CXX::cxxCall (new FuncEnvironment (std::move (_opcode), true , false , cross_compiler_version.empty () ? nullptr : new ustring (cross_compiler_version)));
45- continue ;
46- }
214+ auto & local_functions = declared_functions[file.get_path ()];
215+ auto & local_types = declared_types[file.get_path ()];
216+ {
217+ std::unordered_set<ustring, hash<ustring>> readed_functions;
218+ uint64_t _functions_count = read_value<uint64_t >(file);
219+ for (uint64_t i = 0 ; i < _functions_count; i++) {
220+ auto [symbol, decl, hash] = read_function (file);
47221
48- uint64_t hash = art::hash<uint8_t >()(_opcode.data (), _opcode.size ());
222+ if (symbol.starts_with (' \2 ' )) {
223+ CXX::cxxCall (new FuncEnvironment (decl, true ));
224+ continue ;
225+ }
49226
227+ readed_functions.insert (symbol);
228+ auto it = local_functions.find (symbol);
229+ if (it == local_functions.end ())
230+ local_functions[symbol] = hash;
231+ else if (it->second == hash)
232+ continue ;
50233
51- readed_functions.insert (symbol);
52- auto it = local_functions.find (symbol);
53- if (it == local_functions.end ())
54- local_functions[symbol] = hash;
55- else if (it->second == hash)
56- continue ;
234+ if (symbol.starts_with (' \3 ' )) {
235+ CXX::cxxCall (new FuncEnvironment (decl, true ));
236+ continue ;
237+ }
57238
58- build_patch_list.emplace_back (symbol, new FuncHandle::inner_handle (std::move (_opcode), is_cheap, cross_compiler_version.empty () ? nullptr : new ustring (cross_compiler_version)));
239+ build_patch_list.define_function (symbol, decl);
240+ }
241+
242+ list_array<art::ustring> functions;
243+ for (auto & it : local_functions) {
244+ if (!readed_functions.contains (it.first )) {
245+ build_patch_list.undefine_function (it.first );
246+ functions.push_back (it.first );
247+ }
248+ }
249+ functions.for_each ([&](const art::ustring& symbol) {
250+ local_functions.erase (symbol);
251+ });
59252 }
253+ {
254+ std::unordered_set<list_array<art::ustring>, hash<list_array<art::ustring>>> readed_types;
255+ uint64_t _types_count = read_value<uint64_t >(file);
256+ for (uint64_t i = 0 ; i < _types_count; i++) {
257+ auto type_namespace = read_type_string (file);
258+ uint64_t hash = read_value<uint64_t >(file);
259+ auto type_d = read_type_info (file);
60260
61- std::remove_if (local_functions.begin (), local_functions.end (), [&](decltype (local_functions)::value_type& it) {
62- if (!readed_functions.contains (it.first )) {
63- build_patch_list.emplace_back (it.first , nullptr );
64- return true ;
261+ readed_types.insert (type_namespace);
262+ auto it = local_types.find (type_namespace);
263+ if (it == local_types.end ())
264+ local_types[type_namespace] = hash;
265+ else if (it->second == hash)
266+ continue ;
267+ build_patch_list.define_type (type_namespace, std::move (type_d));
65268 }
66- return false ;
67- });
269+
270+
271+ list_array<list_array<art::ustring>> functions;
272+ for (auto & it : local_types) {
273+ if (!readed_types.contains (it.first )) {
274+ build_patch_list.undefine_type (it.first );
275+ functions.push_back (it.first );
276+ }
277+ }
278+ functions.for_each ([&](const list_array<art::ustring>& symbol) {
279+ local_types.erase (symbol);
280+ });
281+ }
68282 return build_patch_list;
69283 }
70284
@@ -91,9 +305,10 @@ namespace language_parsers {
91305 patch_list precompiled::handle_removed (const ustring& removed) {
92306 lock_guard guard (mutex);
93307 patch_list build_patch_list;
94- auto local_functions = declared_functions[removed];
95- for (auto & it : local_functions)
96- build_patch_list.emplace_back (it.first , nullptr );
308+ for (auto & it : declared_functions[removed])
309+ build_patch_list.undefine_function (it.first );
310+ for (auto & it : declared_types[removed])
311+ build_patch_list.undefine_type (it.first );
97312 declared_functions.erase (removed);
98313 return build_patch_list;
99314 }
0 commit comments