tranfi 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +177 -0
- package/NOTICE +8 -0
- package/README.md +443 -51
- package/app/assets/{index-pDFMluyz.js → index-BIAIKnrp.js} +1 -1
- package/app/index.html +1 -1
- package/binding.gyp +55 -3
- package/csrc/arena.c +7 -5
- package/csrc/batch.c +818 -71
- package/csrc/buffer.c +84 -8
- package/csrc/cJSON.c +262 -19
- package/csrc/cJSON.h +17 -1
- package/csrc/codec_csv.c +1074 -181
- package/csrc/codec_jsonl.c +830 -118
- package/csrc/codec_table.c +108 -78
- package/csrc/codec_text.c +286 -68
- package/csrc/compiler.c +31 -3
- package/csrc/config.h +21 -0
- package/csrc/dsl.c +4722 -485
- package/csrc/expr.c +363 -55
- package/csrc/expr.h +2 -0
- package/csrc/internal.h +316 -27
- package/csrc/ir.c +65 -18
- package/csrc/ir.h +41 -0
- package/csrc/ir_schema.c +20 -5
- package/csrc/ir_serialize.c +68 -6
- package/csrc/ir_sql.c +796 -185
- package/csrc/ir_validate.c +462 -6
- package/csrc/json_path.c +210 -0
- package/csrc/main.c +879 -30
- package/csrc/memory_estimate.c +477 -0
- package/csrc/op_acf.c +171 -21
- package/csrc/op_across.c +477 -0
- package/csrc/op_anomaly.c +167 -32
- package/csrc/op_assert.c +761 -0
- package/csrc/op_bin.c +168 -29
- package/csrc/op_cast.c +383 -55
- package/csrc/op_clip.c +30 -19
- package/csrc/op_date_trunc.c +208 -34
- package/csrc/op_datetime.c +259 -77
- package/csrc/op_derive.c +65 -97
- package/csrc/op_diff.c +146 -30
- package/csrc/op_ewma.c +149 -30
- package/csrc/op_explode.c +124 -26
- package/csrc/op_fill_down.c +125 -53
- package/csrc/op_fill_null.c +176 -31
- package/csrc/op_filter.c +89 -40
- package/csrc/op_frequency.c +571 -43
- package/csrc/op_grep.c +36 -18
- package/csrc/op_group_agg.c +1790 -119
- package/csrc/op_hash.c +48 -15
- package/csrc/op_head.c +21 -86
- package/csrc/op_interpolate.c +268 -62
- package/csrc/op_join.c +2700 -182
- package/csrc/op_json_extract.c +227 -0
- package/csrc/op_json_filter.c +384 -0
- package/csrc/op_json_flatten.c +293 -0
- package/csrc/op_json_schema.c +503 -0
- package/csrc/op_label_encode.c +328 -53
- package/csrc/op_lag.c +181 -0
- package/csrc/op_lead.c +141 -89
- package/csrc/op_normalize.c +363 -79
- package/csrc/op_onehot.c +345 -73
- package/csrc/op_pivot.c +1546 -162
- package/csrc/op_quarantine.c +189 -0
- package/csrc/op_registry.c +2062 -166
- package/csrc/op_rename.c +41 -50
- package/csrc/op_replace.c +270 -118
- package/csrc/op_rleid.c +297 -0
- package/csrc/op_rowid.c +559 -0
- package/csrc/op_sample.c +80 -23
- package/csrc/op_schema.c +1341 -0
- package/csrc/op_schema_infer.c +252 -0
- package/csrc/op_select.c +265 -65
- package/csrc/op_set.c +3449 -0
- package/csrc/op_skip.c +30 -87
- package/csrc/op_sort.c +670 -124
- package/csrc/op_source_name.c +120 -0
- package/csrc/op_split.c +65 -28
- package/csrc/op_split_data.c +41 -9
- package/csrc/op_stack.c +178 -222
- package/csrc/op_stats.c +206 -110
- package/csrc/op_step.c +217 -55
- package/csrc/op_tail.c +21 -12
- package/csrc/op_tee.c +338 -0
- package/csrc/op_top.c +260 -53
- package/csrc/op_trim.c +48 -19
- package/csrc/op_unique.c +1193 -150
- package/csrc/op_unpivot.c +100 -66
- package/csrc/op_validate.c +601 -24
- package/csrc/op_window.c +492 -51
- package/csrc/path_policy.c +85 -0
- package/csrc/pipeline.c +872 -99
- package/csrc/recipes.c +3 -1
- package/csrc/report.c +73 -30
- package/csrc/selector.c +1097 -0
- package/csrc/size_utils.c +352 -0
- package/csrc/spill.c +317 -0
- package/csrc/spill.h +21 -0
- package/csrc/tranfi.h +169 -1
- package/csrc/transform.h +209 -0
- package/csrc/transform_api.c +2237 -0
- package/csrc/transform_categorical.c +923 -0
- package/csrc/transform_internal.h +472 -0
- package/csrc/transform_json.c +3812 -0
- package/csrc/transform_numeric.c +1966 -0
- package/csrc/transform_sha256.c +154 -0
- package/csrc/transform_wasm.h +162 -0
- package/csrc/transform_wasm_api.c +1373 -0
- package/csrc/wasm_api.c +70 -9
- package/napi_api.c +219 -11
- package/napi_transform.c +1648 -0
- package/napi_transform.h +8 -0
- package/package.json +27 -11
- package/scripts/install-native.js +76 -0
- package/scripts/prepack.js +64 -0
- package/scripts/sync-csrc.js +23 -0
- package/src/cli.js +81 -41
- package/src/engines/duckdb.js +45 -12
- package/src/index.js +661 -42
- package/src/memory_policy.js +411 -0
- package/src/native.js +1 -5
- package/src/pipeline.js +454 -31
- package/src/recipe_json.js +80 -0
- package/src/server.js +10 -8
- package/src/transform.js +403 -0
- package/src/transform_error.js +10 -0
- package/src/wasm.js +6 -4
- package/wasm/index.js +498 -10
- package/wasm/tranfi_core.js +0 -0
- package/wasm/transform.js +1156 -0
- package/wasm/worker.js +786 -0
- package/csrc/plan.c +0 -206
|
@@ -0,0 +1,1373 @@
|
|
|
1
|
+
/* Checked standalone wasm32 shim for the generic prepared-transform API. */
|
|
2
|
+
|
|
3
|
+
#include "transform_wasm.h"
|
|
4
|
+
|
|
5
|
+
#include "transform.h"
|
|
6
|
+
#include "transform_internal.h"
|
|
7
|
+
|
|
8
|
+
#include <stdatomic.h>
|
|
9
|
+
#include <stddef.h>
|
|
10
|
+
#include <stdint.h>
|
|
11
|
+
#include <stdlib.h>
|
|
12
|
+
#include <string.h>
|
|
13
|
+
|
|
14
|
+
#ifdef __EMSCRIPTEN__
|
|
15
|
+
#include <emscripten.h>
|
|
16
|
+
#include <emscripten/heap.h>
|
|
17
|
+
#include <emscripten/em_js.h>
|
|
18
|
+
#define TF_WASM_EXPORT EMSCRIPTEN_KEEPALIVE
|
|
19
|
+
EM_JS(int, tf_wasm_transform_host_cancel_poll, (uint32_t slot), {
|
|
20
|
+
var poll = Module['tfTransformCancelPoll'];
|
|
21
|
+
return typeof poll === 'function' && poll(slot) ? 1 : 0;
|
|
22
|
+
});
|
|
23
|
+
#else
|
|
24
|
+
#define TF_WASM_EXPORT
|
|
25
|
+
static uint8_t *tf_wasm_test_heap_base;
|
|
26
|
+
static uint32_t tf_wasm_test_heap_size;
|
|
27
|
+
static int tf_wasm_transform_host_cancel_poll(uint32_t slot) {
|
|
28
|
+
(void)slot;
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
void tf_wasm_transform_test_set_heap(void *base, uint32_t size) {
|
|
32
|
+
tf_wasm_test_heap_base = (uint8_t *)base;
|
|
33
|
+
tf_wasm_test_heap_size = size;
|
|
34
|
+
}
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
_Static_assert(sizeof(tf_wasm_field_view_v1) == 32,
|
|
38
|
+
"wasm32 field descriptor drift");
|
|
39
|
+
_Static_assert(sizeof(tf_wasm_schema_view_v1) == 20,
|
|
40
|
+
"wasm32 schema descriptor drift");
|
|
41
|
+
_Static_assert(sizeof(tf_wasm_column_view_v1) == 36,
|
|
42
|
+
"wasm32 column descriptor drift");
|
|
43
|
+
_Static_assert(sizeof(tf_wasm_table_view_v1) == 24,
|
|
44
|
+
"wasm32 table descriptor drift");
|
|
45
|
+
_Static_assert(sizeof(tf_wasm_dense_info_v1) == 28,
|
|
46
|
+
"wasm32 dense info drift");
|
|
47
|
+
_Static_assert(sizeof(tf_wasm_schema_field_info_v1) == 20,
|
|
48
|
+
"wasm32 schema field info drift");
|
|
49
|
+
_Static_assert(sizeof(tf_transform_limits_v1) == 184,
|
|
50
|
+
"transform limits wire layout drift");
|
|
51
|
+
|
|
52
|
+
#define TF_WASM_SLOT_COUNT 65536u
|
|
53
|
+
#define TF_WASM_TYPE_SHIFT 28u
|
|
54
|
+
#define TF_WASM_GENERATION_SHIFT 16u
|
|
55
|
+
#define TF_WASM_TYPE_MASK 0x0fu
|
|
56
|
+
#define TF_WASM_GENERATION_MASK 0x0fffu
|
|
57
|
+
#define TF_WASM_SLOT_MASK 0xffffu
|
|
58
|
+
|
|
59
|
+
typedef struct tf_wasm_cancel_token {
|
|
60
|
+
atomic_uint references;
|
|
61
|
+
atomic_int requested;
|
|
62
|
+
uint32_t host_poll_slot;
|
|
63
|
+
} tf_wasm_cancel_token;
|
|
64
|
+
|
|
65
|
+
typedef struct tf_wasm_owned_bytes {
|
|
66
|
+
uint8_t *data;
|
|
67
|
+
size_t len;
|
|
68
|
+
} tf_wasm_owned_bytes;
|
|
69
|
+
|
|
70
|
+
typedef struct tf_wasm_owned_dense {
|
|
71
|
+
tf_owned_dense_v1 value;
|
|
72
|
+
} tf_wasm_owned_dense;
|
|
73
|
+
|
|
74
|
+
typedef struct tf_wasm_handle_slot {
|
|
75
|
+
void *pointer;
|
|
76
|
+
tf_wasm_cancel_token *token;
|
|
77
|
+
uint32_t *dtypes;
|
|
78
|
+
uint64_t max_live_handles;
|
|
79
|
+
uint64_t max_retired_slots;
|
|
80
|
+
uint64_t max_allocation_bytes;
|
|
81
|
+
size_t column_count;
|
|
82
|
+
uint16_t generation;
|
|
83
|
+
uint16_t next_free;
|
|
84
|
+
uint8_t type;
|
|
85
|
+
uint8_t retired;
|
|
86
|
+
} tf_wasm_handle_slot;
|
|
87
|
+
|
|
88
|
+
typedef struct tf_wasm_schema_owner {
|
|
89
|
+
tf_schema_view_v1 view;
|
|
90
|
+
tf_field_view_v1 *fields;
|
|
91
|
+
uint32_t *dtypes;
|
|
92
|
+
size_t count;
|
|
93
|
+
} tf_wasm_schema_owner;
|
|
94
|
+
|
|
95
|
+
typedef struct tf_wasm_table_owner {
|
|
96
|
+
tf_table_view_v1 view;
|
|
97
|
+
tf_column_view_v1 *columns;
|
|
98
|
+
} tf_wasm_table_owner;
|
|
99
|
+
|
|
100
|
+
static tf_wasm_handle_slot tf_wasm_slots[TF_WASM_SLOT_COUNT];
|
|
101
|
+
static uint32_t tf_wasm_next_virgin_slot = 1;
|
|
102
|
+
static uint16_t tf_wasm_free_slot_head;
|
|
103
|
+
static uint64_t tf_wasm_live_handles;
|
|
104
|
+
static uint64_t tf_wasm_retired_slots;
|
|
105
|
+
|
|
106
|
+
static int tf_wasm_has_available_slot(void) {
|
|
107
|
+
return tf_wasm_free_slot_head != 0
|
|
108
|
+
|| tf_wasm_next_virgin_slot < TF_WASM_SLOT_COUNT;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static uint32_t tf_wasm_take_available_slot(void) {
|
|
112
|
+
uint32_t index;
|
|
113
|
+
if (tf_wasm_free_slot_head != 0) {
|
|
114
|
+
index = tf_wasm_free_slot_head;
|
|
115
|
+
tf_wasm_free_slot_head = tf_wasm_slots[index].next_free;
|
|
116
|
+
tf_wasm_slots[index].next_free = 0;
|
|
117
|
+
return index;
|
|
118
|
+
}
|
|
119
|
+
if (tf_wasm_next_virgin_slot >= TF_WASM_SLOT_COUNT) return 0;
|
|
120
|
+
index = tf_wasm_next_virgin_slot;
|
|
121
|
+
++tf_wasm_next_virgin_slot;
|
|
122
|
+
return index;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static tf_transform_code tf_wasm_preflight_handle(
|
|
126
|
+
const tf_transform_limits_v1 *limits) {
|
|
127
|
+
if (!limits) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
128
|
+
if (tf_wasm_live_handles >= limits->max_live_handles
|
|
129
|
+
|| tf_wasm_retired_slots > limits->max_retired_handle_slots
|
|
130
|
+
|| !tf_wasm_has_available_slot())
|
|
131
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
132
|
+
return TF_TRANSFORM_OK;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static uint64_t tf_wasm_heap_size(void) {
|
|
136
|
+
#ifdef __EMSCRIPTEN__
|
|
137
|
+
return (uint64_t)emscripten_get_heap_size();
|
|
138
|
+
#else
|
|
139
|
+
return (uint64_t)tf_wasm_test_heap_size;
|
|
140
|
+
#endif
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
static uint8_t *tf_wasm_heap_span(uint32_t offset, uint32_t len) {
|
|
144
|
+
uint64_t end;
|
|
145
|
+
if (len == 0) {
|
|
146
|
+
if (offset == 0) return NULL;
|
|
147
|
+
end = (uint64_t)offset;
|
|
148
|
+
} else {
|
|
149
|
+
if (offset == 0) return NULL;
|
|
150
|
+
end = (uint64_t)offset + (uint64_t)len;
|
|
151
|
+
}
|
|
152
|
+
if (end > tf_wasm_heap_size()) return NULL;
|
|
153
|
+
#ifdef __EMSCRIPTEN__
|
|
154
|
+
return (uint8_t *)(uintptr_t)offset;
|
|
155
|
+
#else
|
|
156
|
+
if (!tf_wasm_test_heap_base) return NULL;
|
|
157
|
+
return tf_wasm_test_heap_base + offset;
|
|
158
|
+
#endif
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static int tf_wasm_read(uint32_t offset, void *out, uint32_t len) {
|
|
162
|
+
uint8_t *source;
|
|
163
|
+
if (len == 0) return 1;
|
|
164
|
+
source = tf_wasm_heap_span(offset, len);
|
|
165
|
+
if (!source || !out) return 0;
|
|
166
|
+
memcpy(out, source, len);
|
|
167
|
+
return 1;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
static int tf_wasm_write(uint32_t offset, const void *value, uint32_t len) {
|
|
171
|
+
uint8_t *destination;
|
|
172
|
+
if (len == 0) return 1;
|
|
173
|
+
destination = tf_wasm_heap_span(offset, len);
|
|
174
|
+
if (!destination || !value) return 0;
|
|
175
|
+
memcpy(destination, value, len);
|
|
176
|
+
return 1;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static int tf_wasm_write_u32(uint32_t offset, uint32_t value) {
|
|
180
|
+
return tf_wasm_write(offset, &value, (uint32_t)sizeof(value));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static int tf_wasm_spans_overlap(
|
|
184
|
+
uint32_t first, uint32_t first_len,
|
|
185
|
+
uint32_t second, uint32_t second_len) {
|
|
186
|
+
uint64_t first_end = (uint64_t)first + first_len;
|
|
187
|
+
uint64_t second_end = (uint64_t)second + second_len;
|
|
188
|
+
return first_len != 0 && second_len != 0
|
|
189
|
+
&& (uint64_t)first < second_end && (uint64_t)second < first_end;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static tf_transform_code tf_wasm_prepare_error(uint32_t error_offset) {
|
|
193
|
+
if (!tf_wasm_heap_span(error_offset, 4))
|
|
194
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
195
|
+
return tf_wasm_write_u32(error_offset, 0)
|
|
196
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static tf_transform_code tf_wasm_prepare_outputs(
|
|
200
|
+
uint32_t output_offset, uint32_t error_offset) {
|
|
201
|
+
if (tf_wasm_spans_overlap(output_offset, 4, error_offset, 4)
|
|
202
|
+
|| !tf_wasm_heap_span(output_offset, 4)
|
|
203
|
+
|| !tf_wasm_heap_span(error_offset, 4))
|
|
204
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
205
|
+
if (!tf_wasm_write_u32(output_offset, 0)
|
|
206
|
+
|| !tf_wasm_write_u32(error_offset, 0))
|
|
207
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
208
|
+
return TF_TRANSFORM_OK;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static uint32_t tf_wasm_make_handle(
|
|
212
|
+
uint8_t type, uint16_t generation, uint16_t slot) {
|
|
213
|
+
return ((uint32_t)type << TF_WASM_TYPE_SHIFT)
|
|
214
|
+
| ((uint32_t)generation << TF_WASM_GENERATION_SHIFT)
|
|
215
|
+
| (uint32_t)slot;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
static tf_wasm_handle_slot *tf_wasm_get_slot(
|
|
219
|
+
uint32_t handle, uint8_t expected_type) {
|
|
220
|
+
uint8_t type = (uint8_t)((handle >> TF_WASM_TYPE_SHIFT) & TF_WASM_TYPE_MASK);
|
|
221
|
+
uint16_t generation = (uint16_t)(
|
|
222
|
+
(handle >> TF_WASM_GENERATION_SHIFT) & TF_WASM_GENERATION_MASK);
|
|
223
|
+
uint16_t index = (uint16_t)(handle & TF_WASM_SLOT_MASK);
|
|
224
|
+
tf_wasm_handle_slot *slot;
|
|
225
|
+
if (handle == 0 || index == 0 || generation == 0 || type == 0)
|
|
226
|
+
return NULL;
|
|
227
|
+
if (expected_type != 0 && type != expected_type) return NULL;
|
|
228
|
+
slot = &tf_wasm_slots[index];
|
|
229
|
+
if (!slot->pointer || slot->retired || slot->type != type
|
|
230
|
+
|| slot->generation != generation) return NULL;
|
|
231
|
+
return slot;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
static void tf_wasm_token_retain(tf_wasm_cancel_token *token) {
|
|
235
|
+
if (token) (void)atomic_fetch_add_explicit(
|
|
236
|
+
&token->references, 1u, memory_order_relaxed);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
static void tf_wasm_token_release(tf_wasm_cancel_token *token) {
|
|
240
|
+
if (token && atomic_fetch_sub_explicit(
|
|
241
|
+
&token->references, 1u, memory_order_acq_rel) == 1u) free(token);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static int tf_wasm_cancel_poll(void *user) {
|
|
245
|
+
tf_wasm_cancel_token *token = (tf_wasm_cancel_token *)user;
|
|
246
|
+
if (!token) return 0;
|
|
247
|
+
if (atomic_load_explicit(&token->requested, memory_order_acquire) != 0)
|
|
248
|
+
return 1;
|
|
249
|
+
return token->host_poll_slot != TF_WASM_TRANSFORM_NO_HOST_CANCEL
|
|
250
|
+
&& tf_wasm_transform_host_cancel_poll(token->host_poll_slot) != 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static void tf_wasm_destroy_pointer(uint8_t type, void *pointer) {
|
|
254
|
+
if (!pointer) return;
|
|
255
|
+
if (type == TF_WASM_HANDLE_RECIPE) {
|
|
256
|
+
tf_transform_recipe *value = (tf_transform_recipe *)pointer;
|
|
257
|
+
tf_transform_recipe_destroy(&value);
|
|
258
|
+
} else if (type == TF_WASM_HANDLE_ANALYZER) {
|
|
259
|
+
tf_transform_analyzer *value = (tf_transform_analyzer *)pointer;
|
|
260
|
+
tf_transform_analyzer_destroy(&value);
|
|
261
|
+
} else if (type == TF_WASM_HANDLE_PLAN) {
|
|
262
|
+
tf_transform_plan *value = (tf_transform_plan *)pointer;
|
|
263
|
+
tf_transform_plan_destroy(&value);
|
|
264
|
+
} else if (type == TF_WASM_HANDLE_APPLY) {
|
|
265
|
+
tf_transform_apply *value = (tf_transform_apply *)pointer;
|
|
266
|
+
tf_transform_apply_destroy(&value);
|
|
267
|
+
} else if (type == TF_WASM_HANDLE_ERROR) {
|
|
268
|
+
tf_transform_error *value = (tf_transform_error *)pointer;
|
|
269
|
+
tf_transform_error_destroy(&value);
|
|
270
|
+
} else if (type == TF_WASM_HANDLE_OWNED_BYTES) {
|
|
271
|
+
tf_wasm_owned_bytes *value = (tf_wasm_owned_bytes *)pointer;
|
|
272
|
+
tf_transform_bytes_free(&value->data, &value->len);
|
|
273
|
+
free(value);
|
|
274
|
+
} else if (type == TF_WASM_HANDLE_OWNED_DENSE) {
|
|
275
|
+
tf_wasm_owned_dense *value = (tf_wasm_owned_dense *)pointer;
|
|
276
|
+
tf_owned_dense_free(&value->value);
|
|
277
|
+
free(value);
|
|
278
|
+
} else if (type == TF_WASM_HANDLE_CANCEL_TOKEN) {
|
|
279
|
+
tf_wasm_token_release((tf_wasm_cancel_token *)pointer);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
static tf_transform_code tf_wasm_install_handle(
|
|
284
|
+
uint8_t type, void *pointer, tf_wasm_cancel_token *token,
|
|
285
|
+
const uint32_t *dtypes, size_t column_count,
|
|
286
|
+
const tf_transform_limits_v1 *limits, uint32_t *out) {
|
|
287
|
+
uint32_t *dtype_copy = NULL;
|
|
288
|
+
uint32_t index = 0;
|
|
289
|
+
if (!pointer || !limits || !out || type == 0 || type > 8)
|
|
290
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
291
|
+
if (tf_wasm_live_handles >= limits->max_live_handles
|
|
292
|
+
|| tf_wasm_retired_slots > limits->max_retired_handle_slots)
|
|
293
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
294
|
+
if (column_count != 0) {
|
|
295
|
+
uint64_t bytes = (uint64_t)column_count * sizeof(*dtype_copy);
|
|
296
|
+
if (!dtypes || bytes > SIZE_MAX || bytes > limits->max_allocation_bytes)
|
|
297
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
298
|
+
dtype_copy = (uint32_t *)malloc((size_t)bytes);
|
|
299
|
+
if (!dtype_copy) return TF_TRANSFORM_ALLOCATION;
|
|
300
|
+
memcpy(dtype_copy, dtypes, (size_t)bytes);
|
|
301
|
+
}
|
|
302
|
+
index = tf_wasm_take_available_slot();
|
|
303
|
+
if (index == 0) {
|
|
304
|
+
free(dtype_copy);
|
|
305
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
306
|
+
}
|
|
307
|
+
tf_wasm_handle_slot *slot = &tf_wasm_slots[index];
|
|
308
|
+
if (slot->generation == 0) slot->generation = 1;
|
|
309
|
+
slot->pointer = pointer;
|
|
310
|
+
slot->token = token;
|
|
311
|
+
slot->dtypes = dtype_copy;
|
|
312
|
+
slot->column_count = column_count;
|
|
313
|
+
slot->type = type;
|
|
314
|
+
slot->max_live_handles = limits->max_live_handles;
|
|
315
|
+
slot->max_retired_slots = limits->max_retired_handle_slots;
|
|
316
|
+
slot->max_allocation_bytes = limits->max_allocation_bytes;
|
|
317
|
+
tf_wasm_token_retain(token);
|
|
318
|
+
++tf_wasm_live_handles;
|
|
319
|
+
*out = tf_wasm_make_handle(type, slot->generation, (uint16_t)index);
|
|
320
|
+
return TF_TRANSFORM_OK;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
static tf_transform_code tf_wasm_read_limits(
|
|
324
|
+
uint32_t offset, tf_transform_limits_v1 *out,
|
|
325
|
+
tf_transform_error **error) {
|
|
326
|
+
tf_transform_limits_v1 raw;
|
|
327
|
+
if (offset == 0) return tf_transform_limits_init_safe_v1(out, sizeof(*out));
|
|
328
|
+
if (!tf_wasm_read(offset, &raw, (uint32_t)sizeof(raw)))
|
|
329
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
330
|
+
return tf_transform_copy_limits(&raw, out, error);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
static tf_transform_limits_v1 tf_wasm_safe_limits(void) {
|
|
334
|
+
tf_transform_limits_v1 limits;
|
|
335
|
+
memset(&limits, 0, sizeof(limits));
|
|
336
|
+
(void)tf_transform_limits_init_safe_v1(&limits, sizeof(limits));
|
|
337
|
+
return limits;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
static tf_transform_code tf_wasm_transfer_error(
|
|
341
|
+
tf_transform_error **error, const tf_transform_limits_v1 *limits,
|
|
342
|
+
uint32_t error_offset, tf_transform_code code) {
|
|
343
|
+
uint32_t handle = 0;
|
|
344
|
+
tf_transform_code install_code;
|
|
345
|
+
if (!error || !*error) return code;
|
|
346
|
+
install_code = tf_wasm_install_handle(
|
|
347
|
+
TF_WASM_HANDLE_ERROR, *error, NULL, NULL, 0, limits, &handle);
|
|
348
|
+
if (install_code != TF_TRANSFORM_OK) {
|
|
349
|
+
tf_transform_error_destroy(error);
|
|
350
|
+
return code;
|
|
351
|
+
}
|
|
352
|
+
*error = NULL;
|
|
353
|
+
if (!tf_wasm_write_u32(error_offset, handle)) {
|
|
354
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
355
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
356
|
+
}
|
|
357
|
+
return code;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
static tf_transform_code tf_wasm_transfer_error_safe(
|
|
361
|
+
tf_transform_error **error, uint32_t error_offset,
|
|
362
|
+
tf_transform_code code) {
|
|
363
|
+
tf_transform_limits_v1 limits = tf_wasm_safe_limits();
|
|
364
|
+
return tf_wasm_transfer_error(error, &limits, error_offset, code);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
static tf_wasm_cancel_token *tf_wasm_optional_token(uint32_t handle) {
|
|
368
|
+
tf_wasm_handle_slot *slot;
|
|
369
|
+
if (handle == 0) return NULL;
|
|
370
|
+
slot = tf_wasm_get_slot(handle, TF_WASM_HANDLE_CANCEL_TOKEN);
|
|
371
|
+
return slot ? (tf_wasm_cancel_token *)slot->pointer : NULL;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
static void tf_wasm_runtime_init(
|
|
375
|
+
tf_transform_runtime_v1 *runtime,
|
|
376
|
+
const tf_transform_limits_v1 *limits, tf_wasm_cancel_token *token) {
|
|
377
|
+
memset(runtime, 0, sizeof(*runtime));
|
|
378
|
+
runtime->abi_version = 1;
|
|
379
|
+
runtime->struct_size = (uint32_t)sizeof(*runtime);
|
|
380
|
+
runtime->limits = limits;
|
|
381
|
+
if (token) {
|
|
382
|
+
runtime->cancel = tf_wasm_cancel_poll;
|
|
383
|
+
runtime->cancel_user = token;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
static void tf_wasm_schema_clear(tf_wasm_schema_owner *owner) {
|
|
388
|
+
if (!owner) return;
|
|
389
|
+
free(owner->fields);
|
|
390
|
+
free(owner->dtypes);
|
|
391
|
+
memset(owner, 0, sizeof(*owner));
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
static tf_transform_code tf_wasm_parse_schema(
|
|
395
|
+
uint32_t offset, const tf_transform_limits_v1 *limits,
|
|
396
|
+
tf_wasm_cancel_token *token, tf_wasm_schema_owner *owner) {
|
|
397
|
+
tf_wasm_schema_view_v1 wire;
|
|
398
|
+
uint64_t expected_bytes;
|
|
399
|
+
memset(owner, 0, sizeof(*owner));
|
|
400
|
+
if (!tf_wasm_read(offset, &wire, sizeof(wire))
|
|
401
|
+
|| wire.abi_version != 1 || wire.struct_size != sizeof(wire)
|
|
402
|
+
|| wire.column_count == 0)
|
|
403
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
404
|
+
if ((uint64_t)wire.column_count > limits->max_input_columns)
|
|
405
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
406
|
+
expected_bytes = (uint64_t)wire.column_count * sizeof(tf_wasm_field_view_v1);
|
|
407
|
+
if (expected_bytes != wire.fields_bytes
|
|
408
|
+
|| !tf_wasm_heap_span(wire.fields_offset, wire.fields_bytes))
|
|
409
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
410
|
+
if (expected_bytes > limits->max_allocation_bytes)
|
|
411
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
412
|
+
owner->count = wire.column_count;
|
|
413
|
+
if ((uint64_t)owner->count * sizeof(*owner->fields)
|
|
414
|
+
> limits->max_allocation_bytes
|
|
415
|
+
|| (uint64_t)owner->count * sizeof(*owner->dtypes)
|
|
416
|
+
> limits->max_allocation_bytes)
|
|
417
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
418
|
+
owner->fields = (tf_field_view_v1 *)calloc(
|
|
419
|
+
owner->count, sizeof(*owner->fields));
|
|
420
|
+
owner->dtypes = (uint32_t *)calloc(owner->count, sizeof(*owner->dtypes));
|
|
421
|
+
if (!owner->fields || !owner->dtypes) {
|
|
422
|
+
tf_wasm_schema_clear(owner);
|
|
423
|
+
return TF_TRANSFORM_ALLOCATION;
|
|
424
|
+
}
|
|
425
|
+
for (size_t i = 0; i < owner->count; ++i) {
|
|
426
|
+
tf_wasm_field_view_v1 field;
|
|
427
|
+
uint32_t field_offset = (uint32_t)(
|
|
428
|
+
(uint64_t)wire.fields_offset + i * sizeof(field));
|
|
429
|
+
uint8_t *id;
|
|
430
|
+
uint8_t *name;
|
|
431
|
+
if (i % TF_TRANSFORM_CANCEL_ITERS_V1 == 0
|
|
432
|
+
&& tf_wasm_cancel_poll(token)) {
|
|
433
|
+
tf_wasm_schema_clear(owner);
|
|
434
|
+
return TF_TRANSFORM_CANCELLED;
|
|
435
|
+
}
|
|
436
|
+
if (!tf_wasm_read(field_offset, &field, sizeof(field))
|
|
437
|
+
|| field.abi_version != 1 || field.struct_size != sizeof(field)
|
|
438
|
+
|| field.flags != 0
|
|
439
|
+
|| (field.dtype != TF_VIEW_FLOAT32
|
|
440
|
+
&& field.dtype != TF_VIEW_FLOAT64)
|
|
441
|
+
|| field.id_bytes == 0 || field.name_bytes == 0)
|
|
442
|
+
goto invalid;
|
|
443
|
+
id = tf_wasm_heap_span(field.id_offset, field.id_bytes);
|
|
444
|
+
name = tf_wasm_heap_span(field.name_offset, field.name_bytes);
|
|
445
|
+
if (!id || !name) goto invalid;
|
|
446
|
+
owner->fields[i].abi_version = 1;
|
|
447
|
+
owner->fields[i].struct_size = (uint32_t)sizeof(owner->fields[i]);
|
|
448
|
+
owner->fields[i].dtype = field.dtype;
|
|
449
|
+
owner->fields[i].id_utf8 = id;
|
|
450
|
+
owner->fields[i].id_bytes = field.id_bytes;
|
|
451
|
+
owner->fields[i].name_utf8 = name;
|
|
452
|
+
owner->fields[i].name_bytes = field.name_bytes;
|
|
453
|
+
owner->dtypes[i] = field.dtype;
|
|
454
|
+
}
|
|
455
|
+
owner->view.abi_version = 1;
|
|
456
|
+
owner->view.struct_size = (uint32_t)sizeof(owner->view);
|
|
457
|
+
owner->view.column_count = owner->count;
|
|
458
|
+
owner->view.fields = owner->fields;
|
|
459
|
+
owner->view.fields_bytes = owner->count * sizeof(*owner->fields);
|
|
460
|
+
return TF_TRANSFORM_OK;
|
|
461
|
+
invalid:
|
|
462
|
+
tf_wasm_schema_clear(owner);
|
|
463
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
static void tf_wasm_table_clear(tf_wasm_table_owner *owner) {
|
|
467
|
+
if (!owner) return;
|
|
468
|
+
free(owner->columns);
|
|
469
|
+
memset(owner, 0, sizeof(*owner));
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
static tf_transform_code tf_wasm_parse_table(
|
|
473
|
+
uint32_t offset, const tf_wasm_handle_slot *slot,
|
|
474
|
+
tf_wasm_cancel_token *token, tf_wasm_table_owner *owner) {
|
|
475
|
+
tf_wasm_table_view_v1 wire;
|
|
476
|
+
uint64_t expected_bytes;
|
|
477
|
+
memset(owner, 0, sizeof(*owner));
|
|
478
|
+
if (!tf_wasm_read(offset, &wire, sizeof(wire))
|
|
479
|
+
|| wire.abi_version != 1 || wire.struct_size != sizeof(wire)
|
|
480
|
+
|| wire.column_count != slot->column_count)
|
|
481
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
482
|
+
expected_bytes = (uint64_t)wire.column_count * sizeof(tf_wasm_column_view_v1);
|
|
483
|
+
if (expected_bytes != wire.columns_bytes
|
|
484
|
+
|| !tf_wasm_heap_span(wire.columns_offset, wire.columns_bytes))
|
|
485
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
486
|
+
if (expected_bytes > slot->max_allocation_bytes)
|
|
487
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
488
|
+
if ((uint64_t)wire.column_count * sizeof(*owner->columns)
|
|
489
|
+
> slot->max_allocation_bytes) return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
490
|
+
owner->columns = (tf_column_view_v1 *)calloc(
|
|
491
|
+
wire.column_count, sizeof(*owner->columns));
|
|
492
|
+
if (!owner->columns) return TF_TRANSFORM_ALLOCATION;
|
|
493
|
+
for (size_t i = 0; i < wire.column_count; ++i) {
|
|
494
|
+
tf_wasm_column_view_v1 column;
|
|
495
|
+
uint32_t column_offset = (uint32_t)(
|
|
496
|
+
(uint64_t)wire.columns_offset + i * sizeof(column));
|
|
497
|
+
uint32_t item_size = slot->dtypes[i] == TF_VIEW_FLOAT32 ? 4u : 8u;
|
|
498
|
+
uint8_t *data;
|
|
499
|
+
uint8_t *validity = NULL;
|
|
500
|
+
if (i % TF_TRANSFORM_CANCEL_ITERS_V1 == 0
|
|
501
|
+
&& tf_wasm_cancel_poll(token)) {
|
|
502
|
+
tf_wasm_table_clear(owner);
|
|
503
|
+
return TF_TRANSFORM_CANCELLED;
|
|
504
|
+
}
|
|
505
|
+
if (!tf_wasm_read(column_offset, &column, sizeof(column))
|
|
506
|
+
|| column.abi_version != 1 || column.struct_size != sizeof(column)
|
|
507
|
+
|| column.stride_bytes == 0
|
|
508
|
+
|| column.stride_bytes % item_size != 0)
|
|
509
|
+
goto invalid;
|
|
510
|
+
data = tf_wasm_heap_span(column.data_offset, column.data_bytes);
|
|
511
|
+
if (wire.row_count != 0
|
|
512
|
+
&& (!data || column.data_offset % item_size != 0)) goto invalid;
|
|
513
|
+
if (column.validity_offset != 0 || column.validity_bytes != 0) {
|
|
514
|
+
validity = tf_wasm_heap_span(
|
|
515
|
+
column.validity_offset, column.validity_bytes);
|
|
516
|
+
if (!validity || column.validity_bit_stride == 0) goto invalid;
|
|
517
|
+
} else if (column.validity_bit_offset != 0
|
|
518
|
+
|| column.validity_bit_stride != 0) goto invalid;
|
|
519
|
+
owner->columns[i].abi_version = 1;
|
|
520
|
+
owner->columns[i].struct_size = (uint32_t)sizeof(owner->columns[i]);
|
|
521
|
+
owner->columns[i].data = data;
|
|
522
|
+
owner->columns[i].data_bytes = column.data_bytes;
|
|
523
|
+
owner->columns[i].stride_bytes = column.stride_bytes;
|
|
524
|
+
owner->columns[i].validity = validity;
|
|
525
|
+
owner->columns[i].validity_bytes = column.validity_bytes;
|
|
526
|
+
owner->columns[i].validity_bit_offset = column.validity_bit_offset;
|
|
527
|
+
owner->columns[i].validity_bit_stride = column.validity_bit_stride;
|
|
528
|
+
}
|
|
529
|
+
owner->view.abi_version = 1;
|
|
530
|
+
owner->view.struct_size = (uint32_t)sizeof(owner->view);
|
|
531
|
+
owner->view.row_count = wire.row_count;
|
|
532
|
+
owner->view.column_count = wire.column_count;
|
|
533
|
+
owner->view.columns = owner->columns;
|
|
534
|
+
owner->view.columns_bytes = wire.column_count * sizeof(*owner->columns);
|
|
535
|
+
return TF_TRANSFORM_OK;
|
|
536
|
+
invalid:
|
|
537
|
+
tf_wasm_table_clear(owner);
|
|
538
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
TF_WASM_EXPORT
|
|
542
|
+
uint32_t tf_wasm_transform_limits_init_safe_v1(
|
|
543
|
+
uint32_t out_offset, uint32_t out_size) {
|
|
544
|
+
tf_transform_limits_v1 limits;
|
|
545
|
+
tf_transform_code code;
|
|
546
|
+
if (out_size < sizeof(limits)
|
|
547
|
+
|| !tf_wasm_heap_span(out_offset, (uint32_t)sizeof(limits)))
|
|
548
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
549
|
+
code = tf_transform_limits_init_safe_v1(&limits, sizeof(limits));
|
|
550
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
551
|
+
return tf_wasm_write(out_offset, &limits, sizeof(limits))
|
|
552
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
TF_WASM_EXPORT
|
|
556
|
+
uint32_t tf_wasm_transform_cancel_create(
|
|
557
|
+
uint32_t host_poll_slot, uint32_t limits_offset,
|
|
558
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
559
|
+
tf_transform_limits_v1 limits;
|
|
560
|
+
tf_transform_error *error = NULL;
|
|
561
|
+
tf_wasm_cancel_token *token;
|
|
562
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
563
|
+
out_handle_offset, out_error_offset);
|
|
564
|
+
uint32_t handle = 0;
|
|
565
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
566
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
567
|
+
if (code != TF_TRANSFORM_OK)
|
|
568
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
569
|
+
token = (tf_wasm_cancel_token *)calloc(1, sizeof(*token));
|
|
570
|
+
if (!token) return TF_TRANSFORM_ALLOCATION;
|
|
571
|
+
atomic_init(&token->references, 1u);
|
|
572
|
+
atomic_init(&token->requested, 0);
|
|
573
|
+
token->host_poll_slot = host_poll_slot;
|
|
574
|
+
code = tf_wasm_install_handle(
|
|
575
|
+
TF_WASM_HANDLE_CANCEL_TOKEN, token, NULL, NULL, 0, &limits, &handle);
|
|
576
|
+
if (code != TF_TRANSFORM_OK) {
|
|
577
|
+
tf_wasm_token_release(token);
|
|
578
|
+
return code;
|
|
579
|
+
}
|
|
580
|
+
if (!tf_wasm_write_u32(out_handle_offset, handle)) {
|
|
581
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
582
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
583
|
+
}
|
|
584
|
+
return TF_TRANSFORM_OK;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
TF_WASM_EXPORT
|
|
588
|
+
uint32_t tf_wasm_transform_cancel_request(uint32_t token_handle) {
|
|
589
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
590
|
+
token_handle, TF_WASM_HANDLE_CANCEL_TOKEN);
|
|
591
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
592
|
+
atomic_store_explicit(
|
|
593
|
+
&((tf_wasm_cancel_token *)slot->pointer)->requested,
|
|
594
|
+
1, memory_order_release);
|
|
595
|
+
return TF_TRANSFORM_OK;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
TF_WASM_EXPORT
|
|
599
|
+
uint32_t tf_wasm_transform_recipe_from_json(
|
|
600
|
+
uint32_t json_offset, uint32_t json_bytes, uint32_t limits_offset,
|
|
601
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
602
|
+
tf_transform_limits_v1 limits;
|
|
603
|
+
tf_transform_error *error = NULL;
|
|
604
|
+
tf_transform_recipe *recipe = NULL;
|
|
605
|
+
uint8_t *json;
|
|
606
|
+
uint32_t handle = 0;
|
|
607
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
608
|
+
out_handle_offset, out_error_offset);
|
|
609
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
610
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
611
|
+
if (code != TF_TRANSFORM_OK)
|
|
612
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
613
|
+
json = tf_wasm_heap_span(json_offset, json_bytes);
|
|
614
|
+
if (json_bytes != 0 && !json) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
615
|
+
code = tf_transform_recipe_from_json(
|
|
616
|
+
json, json_bytes, &limits, &recipe, &error);
|
|
617
|
+
if (code != TF_TRANSFORM_OK)
|
|
618
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
619
|
+
code = tf_wasm_install_handle(
|
|
620
|
+
TF_WASM_HANDLE_RECIPE, recipe, NULL, NULL, 0, &limits, &handle);
|
|
621
|
+
if (code != TF_TRANSFORM_OK) {
|
|
622
|
+
tf_transform_recipe_destroy(&recipe);
|
|
623
|
+
return code;
|
|
624
|
+
}
|
|
625
|
+
if (!tf_wasm_write_u32(out_handle_offset, handle)) {
|
|
626
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
627
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
628
|
+
}
|
|
629
|
+
return TF_TRANSFORM_OK;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
TF_WASM_EXPORT
|
|
633
|
+
uint32_t tf_wasm_transform_analyzer_create(
|
|
634
|
+
uint32_t recipe_handle, uint32_t schema_offset,
|
|
635
|
+
uint32_t limits_offset, uint32_t cancel_token_handle,
|
|
636
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
637
|
+
tf_wasm_handle_slot *recipe_slot;
|
|
638
|
+
tf_wasm_cancel_token *token;
|
|
639
|
+
tf_wasm_schema_owner schema;
|
|
640
|
+
tf_transform_limits_v1 limits;
|
|
641
|
+
tf_transform_runtime_v1 runtime;
|
|
642
|
+
tf_transform_analyzer *analyzer = NULL;
|
|
643
|
+
tf_transform_error *error = NULL;
|
|
644
|
+
uint32_t handle = 0;
|
|
645
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
646
|
+
out_handle_offset, out_error_offset);
|
|
647
|
+
memset(&schema, 0, sizeof(schema));
|
|
648
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
649
|
+
recipe_slot = tf_wasm_get_slot(recipe_handle, TF_WASM_HANDLE_RECIPE);
|
|
650
|
+
if (!recipe_slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
651
|
+
token = tf_wasm_optional_token(cancel_token_handle);
|
|
652
|
+
if (cancel_token_handle != 0 && !token) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
653
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
654
|
+
if (code != TF_TRANSFORM_OK)
|
|
655
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
656
|
+
tf_wasm_runtime_init(&runtime, &limits, token);
|
|
657
|
+
if (tf_wasm_cancel_poll(token)) {
|
|
658
|
+
code = tf_transform_analyzer_create(
|
|
659
|
+
(tf_transform_recipe *)recipe_slot->pointer, &schema.view,
|
|
660
|
+
&runtime, &analyzer, &error);
|
|
661
|
+
return tf_wasm_transfer_error(
|
|
662
|
+
&error, &limits, out_error_offset, code);
|
|
663
|
+
}
|
|
664
|
+
code = tf_wasm_parse_schema(schema_offset, &limits, token, &schema);
|
|
665
|
+
if (code == TF_TRANSFORM_CANCELLED) {
|
|
666
|
+
code = tf_transform_analyzer_create(
|
|
667
|
+
(tf_transform_recipe *)recipe_slot->pointer, &schema.view,
|
|
668
|
+
&runtime, &analyzer, &error);
|
|
669
|
+
tf_wasm_schema_clear(&schema);
|
|
670
|
+
return tf_wasm_transfer_error(
|
|
671
|
+
&error, &limits, out_error_offset, code);
|
|
672
|
+
}
|
|
673
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
674
|
+
if (tf_wasm_cancel_poll(token)) {
|
|
675
|
+
code = tf_transform_analyzer_create(
|
|
676
|
+
(tf_transform_recipe *)recipe_slot->pointer, &schema.view,
|
|
677
|
+
&runtime, &analyzer, &error);
|
|
678
|
+
tf_wasm_schema_clear(&schema);
|
|
679
|
+
return tf_wasm_transfer_error(
|
|
680
|
+
&error, &limits, out_error_offset, code);
|
|
681
|
+
}
|
|
682
|
+
code = tf_transform_analyzer_create(
|
|
683
|
+
(tf_transform_recipe *)recipe_slot->pointer, &schema.view,
|
|
684
|
+
&runtime, &analyzer, &error);
|
|
685
|
+
if (code != TF_TRANSFORM_OK) {
|
|
686
|
+
tf_wasm_schema_clear(&schema);
|
|
687
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
688
|
+
}
|
|
689
|
+
code = tf_wasm_install_handle(
|
|
690
|
+
TF_WASM_HANDLE_ANALYZER, analyzer, token,
|
|
691
|
+
schema.dtypes, schema.count, &limits, &handle);
|
|
692
|
+
tf_wasm_schema_clear(&schema);
|
|
693
|
+
if (code != TF_TRANSFORM_OK) {
|
|
694
|
+
tf_transform_analyzer_destroy(&analyzer);
|
|
695
|
+
return code;
|
|
696
|
+
}
|
|
697
|
+
if (!tf_wasm_write_u32(out_handle_offset, handle)) {
|
|
698
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
699
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
700
|
+
}
|
|
701
|
+
return TF_TRANSFORM_OK;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
TF_WASM_EXPORT
|
|
705
|
+
uint32_t tf_wasm_transform_analyzer_push(
|
|
706
|
+
uint32_t analyzer_handle, uint32_t table_offset,
|
|
707
|
+
uint32_t out_error_offset) {
|
|
708
|
+
tf_wasm_handle_slot *slot;
|
|
709
|
+
tf_wasm_table_owner table;
|
|
710
|
+
tf_transform_error *error = NULL;
|
|
711
|
+
tf_transform_limits_v1 limits = tf_wasm_safe_limits();
|
|
712
|
+
tf_transform_code code = tf_wasm_prepare_error(out_error_offset);
|
|
713
|
+
memset(&table, 0, sizeof(table));
|
|
714
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
715
|
+
slot = tf_wasm_get_slot(analyzer_handle, TF_WASM_HANDLE_ANALYZER);
|
|
716
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
717
|
+
limits.max_live_handles = slot->max_live_handles;
|
|
718
|
+
limits.max_retired_handle_slots = slot->max_retired_slots;
|
|
719
|
+
if (tf_wasm_cancel_poll(slot->token)) {
|
|
720
|
+
code = tf_transform_analyzer_push(
|
|
721
|
+
(tf_transform_analyzer *)slot->pointer, &table.view, &error);
|
|
722
|
+
return tf_wasm_transfer_error(
|
|
723
|
+
&error, &limits, out_error_offset, code);
|
|
724
|
+
}
|
|
725
|
+
code = tf_wasm_parse_table(table_offset, slot, slot->token, &table);
|
|
726
|
+
if (code == TF_TRANSFORM_CANCELLED) {
|
|
727
|
+
code = tf_transform_analyzer_push(
|
|
728
|
+
(tf_transform_analyzer *)slot->pointer, &table.view, &error);
|
|
729
|
+
tf_wasm_table_clear(&table);
|
|
730
|
+
return tf_wasm_transfer_error(
|
|
731
|
+
&error, &limits, out_error_offset, code);
|
|
732
|
+
}
|
|
733
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
734
|
+
if (tf_wasm_cancel_poll(slot->token)) {
|
|
735
|
+
code = tf_transform_analyzer_push(
|
|
736
|
+
(tf_transform_analyzer *)slot->pointer, &table.view, &error);
|
|
737
|
+
tf_wasm_table_clear(&table);
|
|
738
|
+
return tf_wasm_transfer_error(
|
|
739
|
+
&error, &limits, out_error_offset, code);
|
|
740
|
+
}
|
|
741
|
+
code = tf_transform_analyzer_push(
|
|
742
|
+
(tf_transform_analyzer *)slot->pointer, &table.view, &error);
|
|
743
|
+
tf_wasm_table_clear(&table);
|
|
744
|
+
if (code != TF_TRANSFORM_OK)
|
|
745
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
746
|
+
return TF_TRANSFORM_OK;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
TF_WASM_EXPORT
|
|
750
|
+
uint32_t tf_wasm_transform_analyzer_finalize(
|
|
751
|
+
uint32_t analyzer_handle, uint32_t out_handle_offset,
|
|
752
|
+
uint32_t out_error_offset) {
|
|
753
|
+
tf_wasm_handle_slot *slot;
|
|
754
|
+
tf_transform_plan *plan = NULL;
|
|
755
|
+
tf_transform_error *error = NULL;
|
|
756
|
+
tf_transform_limits_v1 limits = tf_wasm_safe_limits();
|
|
757
|
+
uint32_t handle = 0;
|
|
758
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
759
|
+
out_handle_offset, out_error_offset);
|
|
760
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
761
|
+
slot = tf_wasm_get_slot(analyzer_handle, TF_WASM_HANDLE_ANALYZER);
|
|
762
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
763
|
+
limits.max_live_handles = slot->max_live_handles;
|
|
764
|
+
limits.max_retired_handle_slots = slot->max_retired_slots;
|
|
765
|
+
limits.max_allocation_bytes = slot->max_allocation_bytes;
|
|
766
|
+
if (tf_wasm_cancel_poll(slot->token)) {
|
|
767
|
+
code = tf_transform_analyzer_finalize(
|
|
768
|
+
(tf_transform_analyzer *)slot->pointer, &plan, &error);
|
|
769
|
+
return tf_wasm_transfer_error(
|
|
770
|
+
&error, &limits, out_error_offset, code);
|
|
771
|
+
}
|
|
772
|
+
code = tf_wasm_preflight_handle(&limits);
|
|
773
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
774
|
+
code = tf_transform_analyzer_finalize(
|
|
775
|
+
(tf_transform_analyzer *)slot->pointer, &plan, &error);
|
|
776
|
+
if (code != TF_TRANSFORM_OK)
|
|
777
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
778
|
+
code = tf_wasm_install_handle(
|
|
779
|
+
TF_WASM_HANDLE_PLAN, plan, NULL, NULL, 0, &limits, &handle);
|
|
780
|
+
if (code != TF_TRANSFORM_OK) {
|
|
781
|
+
tf_transform_plan_destroy(&plan);
|
|
782
|
+
return code;
|
|
783
|
+
}
|
|
784
|
+
if (!tf_wasm_write_u32(out_handle_offset, handle)) {
|
|
785
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
786
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
787
|
+
}
|
|
788
|
+
return TF_TRANSFORM_OK;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
static tf_transform_code tf_wasm_wrap_bytes(
|
|
792
|
+
uint8_t **data, size_t *len, const tf_transform_limits_v1 *limits,
|
|
793
|
+
uint32_t output_offset) {
|
|
794
|
+
tf_wasm_owned_bytes *owned;
|
|
795
|
+
uint32_t handle = 0;
|
|
796
|
+
tf_transform_code code;
|
|
797
|
+
owned = (tf_wasm_owned_bytes *)calloc(1, sizeof(*owned));
|
|
798
|
+
if (!owned) {
|
|
799
|
+
tf_transform_bytes_free(data, len);
|
|
800
|
+
return TF_TRANSFORM_ALLOCATION;
|
|
801
|
+
}
|
|
802
|
+
owned->data = *data;
|
|
803
|
+
owned->len = *len;
|
|
804
|
+
*data = NULL;
|
|
805
|
+
*len = 0;
|
|
806
|
+
code = tf_wasm_install_handle(
|
|
807
|
+
TF_WASM_HANDLE_OWNED_BYTES, owned, NULL, NULL, 0, limits, &handle);
|
|
808
|
+
if (code != TF_TRANSFORM_OK) {
|
|
809
|
+
tf_wasm_destroy_pointer(TF_WASM_HANDLE_OWNED_BYTES, owned);
|
|
810
|
+
return code;
|
|
811
|
+
}
|
|
812
|
+
if (!tf_wasm_write_u32(output_offset, handle)) {
|
|
813
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
814
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
815
|
+
}
|
|
816
|
+
return TF_TRANSFORM_OK;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
TF_WASM_EXPORT
|
|
820
|
+
uint32_t tf_wasm_transform_plan_export(
|
|
821
|
+
uint32_t plan_handle, uint32_t limits_offset,
|
|
822
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
823
|
+
tf_wasm_handle_slot *slot;
|
|
824
|
+
tf_transform_limits_v1 limits;
|
|
825
|
+
tf_transform_error *error = NULL;
|
|
826
|
+
uint8_t *data = NULL;
|
|
827
|
+
size_t len = 0;
|
|
828
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
829
|
+
out_handle_offset, out_error_offset);
|
|
830
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
831
|
+
slot = tf_wasm_get_slot(plan_handle, TF_WASM_HANDLE_PLAN);
|
|
832
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
833
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
834
|
+
if (code != TF_TRANSFORM_OK)
|
|
835
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
836
|
+
code = tf_transform_plan_export(
|
|
837
|
+
(tf_transform_plan *)slot->pointer, &limits, &data, &len, &error);
|
|
838
|
+
if (code != TF_TRANSFORM_OK)
|
|
839
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
840
|
+
return tf_wasm_wrap_bytes(&data, &len, &limits, out_handle_offset);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
TF_WASM_EXPORT
|
|
844
|
+
uint32_t tf_wasm_transform_plan_import(
|
|
845
|
+
uint32_t bytes_offset, uint32_t bytes_len, uint32_t limits_offset,
|
|
846
|
+
uint32_t cancel_token_handle, uint32_t out_handle_offset,
|
|
847
|
+
uint32_t out_error_offset) {
|
|
848
|
+
tf_transform_limits_v1 limits;
|
|
849
|
+
tf_transform_runtime_v1 runtime;
|
|
850
|
+
tf_wasm_cancel_token *token;
|
|
851
|
+
tf_transform_plan *plan = NULL;
|
|
852
|
+
tf_transform_error *error = NULL;
|
|
853
|
+
uint8_t *bytes;
|
|
854
|
+
uint32_t handle = 0;
|
|
855
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
856
|
+
out_handle_offset, out_error_offset);
|
|
857
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
858
|
+
token = tf_wasm_optional_token(cancel_token_handle);
|
|
859
|
+
if (cancel_token_handle != 0 && !token) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
860
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
861
|
+
if (code != TF_TRANSFORM_OK)
|
|
862
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
863
|
+
bytes = tf_wasm_heap_span(bytes_offset, bytes_len);
|
|
864
|
+
if (bytes_len != 0 && !bytes) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
865
|
+
tf_wasm_runtime_init(&runtime, &limits, token);
|
|
866
|
+
code = tf_transform_plan_import(
|
|
867
|
+
bytes, bytes_len, &runtime, &plan, &error);
|
|
868
|
+
if (code != TF_TRANSFORM_OK)
|
|
869
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
870
|
+
code = tf_wasm_install_handle(
|
|
871
|
+
TF_WASM_HANDLE_PLAN, plan, NULL, NULL, 0, &limits, &handle);
|
|
872
|
+
if (code != TF_TRANSFORM_OK) {
|
|
873
|
+
tf_transform_plan_destroy(&plan);
|
|
874
|
+
return code;
|
|
875
|
+
}
|
|
876
|
+
if (!tf_wasm_write_u32(out_handle_offset, handle)) {
|
|
877
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
878
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
879
|
+
}
|
|
880
|
+
return TF_TRANSFORM_OK;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
TF_WASM_EXPORT
|
|
884
|
+
uint32_t tf_wasm_transform_plan_schema_json(
|
|
885
|
+
uint32_t plan_handle, uint32_t which, uint32_t limits_offset,
|
|
886
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
887
|
+
tf_wasm_handle_slot *slot;
|
|
888
|
+
tf_transform_limits_v1 limits;
|
|
889
|
+
tf_transform_error *error = NULL;
|
|
890
|
+
uint8_t *data = NULL;
|
|
891
|
+
size_t len = 0;
|
|
892
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
893
|
+
out_handle_offset, out_error_offset);
|
|
894
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
895
|
+
slot = tf_wasm_get_slot(plan_handle, TF_WASM_HANDLE_PLAN);
|
|
896
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
897
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
898
|
+
if (code != TF_TRANSFORM_OK)
|
|
899
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
900
|
+
code = tf_transform_plan_schema_json(
|
|
901
|
+
(tf_transform_plan *)slot->pointer, which, &limits,
|
|
902
|
+
&data, &len, &error);
|
|
903
|
+
if (code != TF_TRANSFORM_OK)
|
|
904
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
905
|
+
return tf_wasm_wrap_bytes(&data, &len, &limits, out_handle_offset);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
TF_WASM_EXPORT
|
|
909
|
+
uint32_t tf_wasm_transform_plan_recipe_sha256(
|
|
910
|
+
uint32_t plan_handle, uint32_t limits_offset,
|
|
911
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
912
|
+
tf_wasm_handle_slot *slot;
|
|
913
|
+
tf_transform_limits_v1 limits;
|
|
914
|
+
tf_transform_error *error = NULL;
|
|
915
|
+
uint8_t fingerprint[65];
|
|
916
|
+
uint8_t *data = NULL;
|
|
917
|
+
size_t len = 64;
|
|
918
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
919
|
+
out_handle_offset, out_error_offset);
|
|
920
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
921
|
+
slot = tf_wasm_get_slot(plan_handle, TF_WASM_HANDLE_PLAN);
|
|
922
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
923
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
924
|
+
if (code != TF_TRANSFORM_OK)
|
|
925
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
926
|
+
if (limits.max_allocation_bytes < len) {
|
|
927
|
+
code = tf_transform_set_error(
|
|
928
|
+
&error, TF_TRANSFORM_RESOURCE_LIMIT,
|
|
929
|
+
"recipe fingerprint output exceeds allocation limit");
|
|
930
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
931
|
+
}
|
|
932
|
+
code = tf_transform_plan_recipe_sha256(
|
|
933
|
+
(tf_transform_plan *)slot->pointer, &limits, fingerprint, &error);
|
|
934
|
+
if (code != TF_TRANSFORM_OK)
|
|
935
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
936
|
+
data = (uint8_t *)malloc(len);
|
|
937
|
+
if (!data) {
|
|
938
|
+
code = tf_transform_set_error(
|
|
939
|
+
&error, TF_TRANSFORM_ALLOCATION,
|
|
940
|
+
"recipe fingerprint output allocation failed");
|
|
941
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
942
|
+
}
|
|
943
|
+
memcpy(data, fingerprint, len);
|
|
944
|
+
return tf_wasm_wrap_bytes(&data, &len, &limits, out_handle_offset);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
static tf_transform_code tf_wasm_get_schema_field(
|
|
948
|
+
uint32_t plan_handle, uint32_t which, uint32_t index,
|
|
949
|
+
tf_field_view_v1 *field, tf_transform_error **error,
|
|
950
|
+
tf_wasm_handle_slot **slot_out) {
|
|
951
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
952
|
+
plan_handle, TF_WASM_HANDLE_PLAN);
|
|
953
|
+
const tf_transform_schema *schema = NULL;
|
|
954
|
+
tf_transform_code code;
|
|
955
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
956
|
+
code = tf_transform_plan_schema(
|
|
957
|
+
(tf_transform_plan *)slot->pointer, which, &schema, error);
|
|
958
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
959
|
+
code = tf_transform_schema_field(schema, index, field, error);
|
|
960
|
+
if (code == TF_TRANSFORM_OK && slot_out) *slot_out = slot;
|
|
961
|
+
return code;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
TF_WASM_EXPORT
|
|
965
|
+
uint32_t tf_wasm_transform_plan_schema_field_count(
|
|
966
|
+
uint32_t plan_handle, uint32_t which, uint32_t out_count_offset,
|
|
967
|
+
uint32_t out_error_offset) {
|
|
968
|
+
tf_wasm_handle_slot *slot;
|
|
969
|
+
const tf_transform_schema *schema = NULL;
|
|
970
|
+
tf_transform_error *error = NULL;
|
|
971
|
+
tf_transform_limits_v1 limits = tf_wasm_safe_limits();
|
|
972
|
+
size_t count;
|
|
973
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
974
|
+
out_count_offset, out_error_offset);
|
|
975
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
976
|
+
slot = tf_wasm_get_slot(plan_handle, TF_WASM_HANDLE_PLAN);
|
|
977
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
978
|
+
limits.max_live_handles = slot->max_live_handles;
|
|
979
|
+
limits.max_retired_handle_slots = slot->max_retired_slots;
|
|
980
|
+
code = tf_transform_plan_schema(
|
|
981
|
+
(tf_transform_plan *)slot->pointer, which, &schema, &error);
|
|
982
|
+
if (code != TF_TRANSFORM_OK)
|
|
983
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
984
|
+
count = tf_transform_schema_field_count(schema);
|
|
985
|
+
if (count > UINT32_MAX) return TF_TRANSFORM_INTERNAL;
|
|
986
|
+
return tf_wasm_write_u32(out_count_offset, (uint32_t)count)
|
|
987
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
TF_WASM_EXPORT
|
|
991
|
+
uint32_t tf_wasm_transform_plan_schema_field_info(
|
|
992
|
+
uint32_t plan_handle, uint32_t which, uint32_t index,
|
|
993
|
+
uint32_t out_info_offset, uint32_t out_error_offset) {
|
|
994
|
+
tf_field_view_v1 field;
|
|
995
|
+
tf_wasm_schema_field_info_v1 info;
|
|
996
|
+
tf_wasm_handle_slot *slot = NULL;
|
|
997
|
+
tf_transform_error *error = NULL;
|
|
998
|
+
tf_transform_limits_v1 limits = tf_wasm_safe_limits();
|
|
999
|
+
tf_transform_code code;
|
|
1000
|
+
if (tf_wasm_spans_overlap(
|
|
1001
|
+
out_info_offset, sizeof(info), out_error_offset, 4)
|
|
1002
|
+
|| !tf_wasm_heap_span(out_info_offset, sizeof(info)))
|
|
1003
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1004
|
+
code = tf_wasm_prepare_error(out_error_offset);
|
|
1005
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
1006
|
+
memset(&field, 0, sizeof(field));
|
|
1007
|
+
code = tf_wasm_get_schema_field(
|
|
1008
|
+
plan_handle, which, index, &field, &error, &slot);
|
|
1009
|
+
if (slot) {
|
|
1010
|
+
limits.max_live_handles = slot->max_live_handles;
|
|
1011
|
+
limits.max_retired_handle_slots = slot->max_retired_slots;
|
|
1012
|
+
}
|
|
1013
|
+
if (code != TF_TRANSFORM_OK)
|
|
1014
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
1015
|
+
if (field.id_bytes > UINT32_MAX || field.name_bytes > UINT32_MAX)
|
|
1016
|
+
return TF_TRANSFORM_INTERNAL;
|
|
1017
|
+
info.abi_version = 1;
|
|
1018
|
+
info.struct_size = sizeof(info);
|
|
1019
|
+
info.dtype = field.dtype;
|
|
1020
|
+
info.id_bytes = (uint32_t)field.id_bytes;
|
|
1021
|
+
info.name_bytes = (uint32_t)field.name_bytes;
|
|
1022
|
+
return tf_wasm_write(out_info_offset, &info, sizeof(info))
|
|
1023
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
TF_WASM_EXPORT
|
|
1027
|
+
uint32_t tf_wasm_transform_plan_schema_field_copy(
|
|
1028
|
+
uint32_t plan_handle, uint32_t which, uint32_t index,
|
|
1029
|
+
uint32_t id_offset, uint32_t id_capacity,
|
|
1030
|
+
uint32_t name_offset, uint32_t name_capacity,
|
|
1031
|
+
uint32_t out_error_offset) {
|
|
1032
|
+
tf_field_view_v1 field;
|
|
1033
|
+
tf_wasm_handle_slot *slot = NULL;
|
|
1034
|
+
tf_transform_error *error = NULL;
|
|
1035
|
+
tf_transform_limits_v1 limits = tf_wasm_safe_limits();
|
|
1036
|
+
uint8_t *id_destination;
|
|
1037
|
+
uint8_t *name_destination;
|
|
1038
|
+
tf_transform_code code = tf_wasm_prepare_error(out_error_offset);
|
|
1039
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
1040
|
+
memset(&field, 0, sizeof(field));
|
|
1041
|
+
code = tf_wasm_get_schema_field(
|
|
1042
|
+
plan_handle, which, index, &field, &error, &slot);
|
|
1043
|
+
if (slot) {
|
|
1044
|
+
limits.max_live_handles = slot->max_live_handles;
|
|
1045
|
+
limits.max_retired_handle_slots = slot->max_retired_slots;
|
|
1046
|
+
}
|
|
1047
|
+
if (code != TF_TRANSFORM_OK)
|
|
1048
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
1049
|
+
if (field.id_bytes > id_capacity || field.name_bytes > name_capacity)
|
|
1050
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
1051
|
+
if (tf_wasm_spans_overlap(id_offset, id_capacity, name_offset, name_capacity)
|
|
1052
|
+
|| tf_wasm_spans_overlap(id_offset, id_capacity, out_error_offset, 4)
|
|
1053
|
+
|| tf_wasm_spans_overlap(name_offset, name_capacity, out_error_offset, 4))
|
|
1054
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1055
|
+
id_destination = tf_wasm_heap_span(id_offset, id_capacity);
|
|
1056
|
+
name_destination = tf_wasm_heap_span(name_offset, name_capacity);
|
|
1057
|
+
if ((id_capacity != 0 && !id_destination)
|
|
1058
|
+
|| (name_capacity != 0 && !name_destination))
|
|
1059
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1060
|
+
if (field.id_bytes != 0) memcpy(id_destination, field.id_utf8, field.id_bytes);
|
|
1061
|
+
if (field.name_bytes != 0)
|
|
1062
|
+
memcpy(name_destination, field.name_utf8, field.name_bytes);
|
|
1063
|
+
return TF_TRANSFORM_OK;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
TF_WASM_EXPORT
|
|
1067
|
+
uint32_t tf_wasm_transform_apply_create(
|
|
1068
|
+
uint32_t plan_handle, uint32_t schema_offset,
|
|
1069
|
+
uint32_t limits_offset, uint32_t cancel_token_handle,
|
|
1070
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
1071
|
+
tf_wasm_handle_slot *plan_slot;
|
|
1072
|
+
tf_wasm_cancel_token *token;
|
|
1073
|
+
tf_wasm_schema_owner schema;
|
|
1074
|
+
tf_transform_limits_v1 limits;
|
|
1075
|
+
tf_transform_runtime_v1 runtime;
|
|
1076
|
+
tf_transform_apply *apply = NULL;
|
|
1077
|
+
tf_transform_error *error = NULL;
|
|
1078
|
+
uint32_t handle = 0;
|
|
1079
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
1080
|
+
out_handle_offset, out_error_offset);
|
|
1081
|
+
memset(&schema, 0, sizeof(schema));
|
|
1082
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
1083
|
+
plan_slot = tf_wasm_get_slot(plan_handle, TF_WASM_HANDLE_PLAN);
|
|
1084
|
+
if (!plan_slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1085
|
+
token = tf_wasm_optional_token(cancel_token_handle);
|
|
1086
|
+
if (cancel_token_handle != 0 && !token) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1087
|
+
code = tf_wasm_read_limits(limits_offset, &limits, &error);
|
|
1088
|
+
if (code != TF_TRANSFORM_OK)
|
|
1089
|
+
return tf_wasm_transfer_error_safe(&error, out_error_offset, code);
|
|
1090
|
+
tf_wasm_runtime_init(&runtime, &limits, token);
|
|
1091
|
+
if (tf_wasm_cancel_poll(token)) {
|
|
1092
|
+
code = tf_transform_apply_create(
|
|
1093
|
+
(tf_transform_plan *)plan_slot->pointer, &schema.view,
|
|
1094
|
+
&runtime, &apply, &error);
|
|
1095
|
+
return tf_wasm_transfer_error(
|
|
1096
|
+
&error, &limits, out_error_offset, code);
|
|
1097
|
+
}
|
|
1098
|
+
code = tf_wasm_parse_schema(schema_offset, &limits, token, &schema);
|
|
1099
|
+
if (code == TF_TRANSFORM_CANCELLED) {
|
|
1100
|
+
code = tf_transform_apply_create(
|
|
1101
|
+
(tf_transform_plan *)plan_slot->pointer, &schema.view,
|
|
1102
|
+
&runtime, &apply, &error);
|
|
1103
|
+
tf_wasm_schema_clear(&schema);
|
|
1104
|
+
return tf_wasm_transfer_error(
|
|
1105
|
+
&error, &limits, out_error_offset, code);
|
|
1106
|
+
}
|
|
1107
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
1108
|
+
if (tf_wasm_cancel_poll(token)) {
|
|
1109
|
+
code = tf_transform_apply_create(
|
|
1110
|
+
(tf_transform_plan *)plan_slot->pointer, &schema.view,
|
|
1111
|
+
&runtime, &apply, &error);
|
|
1112
|
+
tf_wasm_schema_clear(&schema);
|
|
1113
|
+
return tf_wasm_transfer_error(
|
|
1114
|
+
&error, &limits, out_error_offset, code);
|
|
1115
|
+
}
|
|
1116
|
+
code = tf_transform_apply_create(
|
|
1117
|
+
(tf_transform_plan *)plan_slot->pointer, &schema.view,
|
|
1118
|
+
&runtime, &apply, &error);
|
|
1119
|
+
if (code != TF_TRANSFORM_OK) {
|
|
1120
|
+
tf_wasm_schema_clear(&schema);
|
|
1121
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
1122
|
+
}
|
|
1123
|
+
code = tf_wasm_install_handle(
|
|
1124
|
+
TF_WASM_HANDLE_APPLY, apply, token,
|
|
1125
|
+
schema.dtypes, schema.count, &limits, &handle);
|
|
1126
|
+
tf_wasm_schema_clear(&schema);
|
|
1127
|
+
if (code != TF_TRANSFORM_OK) {
|
|
1128
|
+
tf_transform_apply_destroy(&apply);
|
|
1129
|
+
return code;
|
|
1130
|
+
}
|
|
1131
|
+
if (!tf_wasm_write_u32(out_handle_offset, handle)) {
|
|
1132
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
1133
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1134
|
+
}
|
|
1135
|
+
return TF_TRANSFORM_OK;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
TF_WASM_EXPORT
|
|
1139
|
+
uint32_t tf_wasm_transform_apply_run(
|
|
1140
|
+
uint32_t apply_handle, uint32_t table_offset,
|
|
1141
|
+
uint32_t out_handle_offset, uint32_t out_error_offset) {
|
|
1142
|
+
tf_wasm_handle_slot *slot;
|
|
1143
|
+
tf_wasm_table_owner table;
|
|
1144
|
+
tf_wasm_owned_dense *owned;
|
|
1145
|
+
tf_transform_error *error = NULL;
|
|
1146
|
+
tf_transform_limits_v1 limits = tf_wasm_safe_limits();
|
|
1147
|
+
uint32_t handle = 0;
|
|
1148
|
+
tf_transform_code code = tf_wasm_prepare_outputs(
|
|
1149
|
+
out_handle_offset, out_error_offset);
|
|
1150
|
+
memset(&table, 0, sizeof(table));
|
|
1151
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
1152
|
+
slot = tf_wasm_get_slot(apply_handle, TF_WASM_HANDLE_APPLY);
|
|
1153
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1154
|
+
limits.max_live_handles = slot->max_live_handles;
|
|
1155
|
+
limits.max_retired_handle_slots = slot->max_retired_slots;
|
|
1156
|
+
limits.max_allocation_bytes = slot->max_allocation_bytes;
|
|
1157
|
+
if (tf_wasm_cancel_poll(slot->token)) {
|
|
1158
|
+
tf_owned_dense_v1 cancelled = {0};
|
|
1159
|
+
code = tf_transform_apply_run(
|
|
1160
|
+
(tf_transform_apply *)slot->pointer, &table.view,
|
|
1161
|
+
&cancelled, &error);
|
|
1162
|
+
return tf_wasm_transfer_error(
|
|
1163
|
+
&error, &limits, out_error_offset, code);
|
|
1164
|
+
}
|
|
1165
|
+
code = tf_wasm_parse_table(table_offset, slot, slot->token, &table);
|
|
1166
|
+
if (code == TF_TRANSFORM_CANCELLED) {
|
|
1167
|
+
tf_owned_dense_v1 cancelled = {0};
|
|
1168
|
+
code = tf_transform_apply_run(
|
|
1169
|
+
(tf_transform_apply *)slot->pointer, &table.view,
|
|
1170
|
+
&cancelled, &error);
|
|
1171
|
+
tf_wasm_table_clear(&table);
|
|
1172
|
+
return tf_wasm_transfer_error(
|
|
1173
|
+
&error, &limits, out_error_offset, code);
|
|
1174
|
+
}
|
|
1175
|
+
if (code != TF_TRANSFORM_OK) return code;
|
|
1176
|
+
if (tf_wasm_cancel_poll(slot->token)) {
|
|
1177
|
+
tf_owned_dense_v1 cancelled = {0};
|
|
1178
|
+
code = tf_transform_apply_run(
|
|
1179
|
+
(tf_transform_apply *)slot->pointer, &table.view,
|
|
1180
|
+
&cancelled, &error);
|
|
1181
|
+
tf_wasm_table_clear(&table);
|
|
1182
|
+
return tf_wasm_transfer_error(
|
|
1183
|
+
&error, &limits, out_error_offset, code);
|
|
1184
|
+
}
|
|
1185
|
+
code = tf_wasm_preflight_handle(&limits);
|
|
1186
|
+
if (code != TF_TRANSFORM_OK) {
|
|
1187
|
+
tf_wasm_table_clear(&table);
|
|
1188
|
+
return code;
|
|
1189
|
+
}
|
|
1190
|
+
owned = (tf_wasm_owned_dense *)calloc(1, sizeof(*owned));
|
|
1191
|
+
if (!owned) {
|
|
1192
|
+
tf_wasm_table_clear(&table);
|
|
1193
|
+
return TF_TRANSFORM_ALLOCATION;
|
|
1194
|
+
}
|
|
1195
|
+
code = tf_transform_apply_run(
|
|
1196
|
+
(tf_transform_apply *)slot->pointer, &table.view,
|
|
1197
|
+
&owned->value, &error);
|
|
1198
|
+
tf_wasm_table_clear(&table);
|
|
1199
|
+
if (code != TF_TRANSFORM_OK) {
|
|
1200
|
+
tf_wasm_destroy_pointer(TF_WASM_HANDLE_OWNED_DENSE, owned);
|
|
1201
|
+
return tf_wasm_transfer_error(&error, &limits, out_error_offset, code);
|
|
1202
|
+
}
|
|
1203
|
+
code = tf_wasm_install_handle(
|
|
1204
|
+
TF_WASM_HANDLE_OWNED_DENSE, owned, slot->token, NULL, 0,
|
|
1205
|
+
&limits, &handle);
|
|
1206
|
+
if (code != TF_TRANSFORM_OK) {
|
|
1207
|
+
tf_wasm_destroy_pointer(TF_WASM_HANDLE_OWNED_DENSE, owned);
|
|
1208
|
+
return code;
|
|
1209
|
+
}
|
|
1210
|
+
if (!tf_wasm_write_u32(out_handle_offset, handle)) {
|
|
1211
|
+
(void)tf_wasm_transform_handle_destroy(handle);
|
|
1212
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1213
|
+
}
|
|
1214
|
+
return TF_TRANSFORM_OK;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
TF_WASM_EXPORT
|
|
1218
|
+
uint32_t tf_wasm_transform_error_code(
|
|
1219
|
+
uint32_t error_handle, uint32_t out_code_offset) {
|
|
1220
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
1221
|
+
error_handle, TF_WASM_HANDLE_ERROR);
|
|
1222
|
+
tf_transform_code code;
|
|
1223
|
+
if (!slot || !tf_wasm_heap_span(out_code_offset, 4))
|
|
1224
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1225
|
+
code = tf_transform_error_get_code((tf_transform_error *)slot->pointer);
|
|
1226
|
+
return tf_wasm_write_u32(out_code_offset, (uint32_t)code)
|
|
1227
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
TF_WASM_EXPORT
|
|
1231
|
+
uint32_t tf_wasm_transform_error_message_size(
|
|
1232
|
+
uint32_t error_handle, uint32_t out_size_offset) {
|
|
1233
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
1234
|
+
error_handle, TF_WASM_HANDLE_ERROR);
|
|
1235
|
+
size_t len = 0;
|
|
1236
|
+
if (!slot || !tf_wasm_heap_span(out_size_offset, 4))
|
|
1237
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1238
|
+
(void)tf_transform_error_message((tf_transform_error *)slot->pointer, &len);
|
|
1239
|
+
if (len > UINT32_MAX) return TF_TRANSFORM_INTERNAL;
|
|
1240
|
+
return tf_wasm_write_u32(out_size_offset, (uint32_t)len)
|
|
1241
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
TF_WASM_EXPORT
|
|
1245
|
+
uint32_t tf_wasm_transform_error_message_copy(
|
|
1246
|
+
uint32_t error_handle, uint32_t destination_offset,
|
|
1247
|
+
uint32_t destination_capacity) {
|
|
1248
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
1249
|
+
error_handle, TF_WASM_HANDLE_ERROR);
|
|
1250
|
+
size_t len = 0;
|
|
1251
|
+
const uint8_t *message;
|
|
1252
|
+
uint8_t *destination;
|
|
1253
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1254
|
+
message = tf_transform_error_message(
|
|
1255
|
+
(tf_transform_error *)slot->pointer, &len);
|
|
1256
|
+
if (len > destination_capacity) return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
1257
|
+
destination = tf_wasm_heap_span(destination_offset, destination_capacity);
|
|
1258
|
+
if (destination_capacity != 0 && !destination)
|
|
1259
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1260
|
+
if (len != 0) memcpy(destination, message, len);
|
|
1261
|
+
return TF_TRANSFORM_OK;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
TF_WASM_EXPORT
|
|
1265
|
+
uint32_t tf_wasm_transform_owned_bytes_size(
|
|
1266
|
+
uint32_t bytes_handle, uint32_t out_size_offset) {
|
|
1267
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
1268
|
+
bytes_handle, TF_WASM_HANDLE_OWNED_BYTES);
|
|
1269
|
+
tf_wasm_owned_bytes *owned;
|
|
1270
|
+
if (!slot || !tf_wasm_heap_span(out_size_offset, 4))
|
|
1271
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1272
|
+
owned = (tf_wasm_owned_bytes *)slot->pointer;
|
|
1273
|
+
if (owned->len > UINT32_MAX) return TF_TRANSFORM_INTERNAL;
|
|
1274
|
+
return tf_wasm_write_u32(out_size_offset, (uint32_t)owned->len)
|
|
1275
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
TF_WASM_EXPORT
|
|
1279
|
+
uint32_t tf_wasm_transform_owned_bytes_copy(
|
|
1280
|
+
uint32_t bytes_handle, uint32_t destination_offset,
|
|
1281
|
+
uint32_t destination_capacity) {
|
|
1282
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
1283
|
+
bytes_handle, TF_WASM_HANDLE_OWNED_BYTES);
|
|
1284
|
+
tf_wasm_owned_bytes *owned;
|
|
1285
|
+
uint8_t *destination;
|
|
1286
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1287
|
+
owned = (tf_wasm_owned_bytes *)slot->pointer;
|
|
1288
|
+
if (owned->len > destination_capacity) return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
1289
|
+
destination = tf_wasm_heap_span(destination_offset, destination_capacity);
|
|
1290
|
+
if (destination_capacity != 0 && !destination)
|
|
1291
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1292
|
+
if (owned->len != 0) memcpy(destination, owned->data, owned->len);
|
|
1293
|
+
return TF_TRANSFORM_OK;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
TF_WASM_EXPORT
|
|
1297
|
+
uint32_t tf_wasm_transform_owned_dense_info(
|
|
1298
|
+
uint32_t dense_handle, uint32_t out_info_offset) {
|
|
1299
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
1300
|
+
dense_handle, TF_WASM_HANDLE_OWNED_DENSE);
|
|
1301
|
+
tf_wasm_owned_dense *owned;
|
|
1302
|
+
tf_wasm_dense_info_v1 info;
|
|
1303
|
+
if (!slot || !tf_wasm_heap_span(out_info_offset, sizeof(info)))
|
|
1304
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1305
|
+
owned = (tf_wasm_owned_dense *)slot->pointer;
|
|
1306
|
+
if (owned->value.rows > UINT32_MAX
|
|
1307
|
+
|| owned->value.columns > UINT32_MAX
|
|
1308
|
+
|| owned->value.data_bytes > UINT32_MAX)
|
|
1309
|
+
return TF_TRANSFORM_INTERNAL;
|
|
1310
|
+
info.abi_version = 1;
|
|
1311
|
+
info.struct_size = sizeof(info);
|
|
1312
|
+
info.dtype = owned->value.dtype;
|
|
1313
|
+
info.flags = owned->value.flags;
|
|
1314
|
+
info.rows = (uint32_t)owned->value.rows;
|
|
1315
|
+
info.columns = (uint32_t)owned->value.columns;
|
|
1316
|
+
info.data_bytes = (uint32_t)owned->value.data_bytes;
|
|
1317
|
+
return tf_wasm_write(out_info_offset, &info, sizeof(info))
|
|
1318
|
+
? TF_TRANSFORM_OK : TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
TF_WASM_EXPORT
|
|
1322
|
+
uint32_t tf_wasm_transform_owned_dense_copy(
|
|
1323
|
+
uint32_t dense_handle, uint32_t destination_offset,
|
|
1324
|
+
uint32_t destination_capacity) {
|
|
1325
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(
|
|
1326
|
+
dense_handle, TF_WASM_HANDLE_OWNED_DENSE);
|
|
1327
|
+
tf_wasm_owned_dense *owned;
|
|
1328
|
+
uint8_t *destination;
|
|
1329
|
+
size_t offset = 0;
|
|
1330
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1331
|
+
owned = (tf_wasm_owned_dense *)slot->pointer;
|
|
1332
|
+
if (owned->value.data_bytes > destination_capacity)
|
|
1333
|
+
return TF_TRANSFORM_RESOURCE_LIMIT;
|
|
1334
|
+
destination = tf_wasm_heap_span(destination_offset, destination_capacity);
|
|
1335
|
+
if (destination_capacity != 0 && !destination)
|
|
1336
|
+
return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1337
|
+
while (offset < owned->value.data_bytes) {
|
|
1338
|
+
size_t chunk = owned->value.data_bytes - offset;
|
|
1339
|
+
if (chunk > TF_TRANSFORM_CANCEL_BYTES_V1)
|
|
1340
|
+
chunk = TF_TRANSFORM_CANCEL_BYTES_V1;
|
|
1341
|
+
if (tf_wasm_cancel_poll(slot->token)) return TF_TRANSFORM_CANCELLED;
|
|
1342
|
+
memcpy(destination + offset,
|
|
1343
|
+
(const uint8_t *)owned->value.data + offset, chunk);
|
|
1344
|
+
offset += chunk;
|
|
1345
|
+
}
|
|
1346
|
+
if (tf_wasm_cancel_poll(slot->token)) return TF_TRANSFORM_CANCELLED;
|
|
1347
|
+
return TF_TRANSFORM_OK;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
TF_WASM_EXPORT
|
|
1351
|
+
uint32_t tf_wasm_transform_handle_destroy(uint32_t handle) {
|
|
1352
|
+
tf_wasm_handle_slot *slot = tf_wasm_get_slot(handle, 0);
|
|
1353
|
+
uint16_t index = (uint16_t)(handle & TF_WASM_SLOT_MASK);
|
|
1354
|
+
if (!slot) return TF_TRANSFORM_INVALID_ARGUMENT;
|
|
1355
|
+
tf_wasm_destroy_pointer(slot->type, slot->pointer);
|
|
1356
|
+
tf_wasm_token_release(slot->token);
|
|
1357
|
+
free(slot->dtypes);
|
|
1358
|
+
slot->pointer = NULL;
|
|
1359
|
+
slot->token = NULL;
|
|
1360
|
+
slot->dtypes = NULL;
|
|
1361
|
+
slot->column_count = 0;
|
|
1362
|
+
slot->type = 0;
|
|
1363
|
+
if (tf_wasm_live_handles != 0) --tf_wasm_live_handles;
|
|
1364
|
+
if (slot->generation == TF_WASM_GENERATION_MASK) {
|
|
1365
|
+
slot->retired = 1;
|
|
1366
|
+
++tf_wasm_retired_slots;
|
|
1367
|
+
} else {
|
|
1368
|
+
++slot->generation;
|
|
1369
|
+
slot->next_free = tf_wasm_free_slot_head;
|
|
1370
|
+
tf_wasm_free_slot_head = index;
|
|
1371
|
+
}
|
|
1372
|
+
return TF_TRANSFORM_OK;
|
|
1373
|
+
}
|