space-data-module-sdk 0.5.15 → 0.5.18
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/README.md +24 -0
- package/package.json +8 -4
- package/schemas/HostStorageAbi.fbs +53 -0
- package/src/bundle/codec.js +1 -1
- package/src/compliance/pluginCompliance.js +1 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.js +1 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.js +1 -1
- package/src/generated/orbpro/manifest/accepted-type-set.js +1 -1
- package/src/generated/orbpro/manifest/build-artifact.js +1 -1
- package/src/generated/orbpro/manifest/host-capability.js +1 -1
- package/src/generated/orbpro/manifest/method-manifest.js +1 -1
- package/src/generated/orbpro/manifest/plugin-manifest.js +1 -1
- package/src/generated/orbpro/manifest/port-manifest.js +1 -1
- package/src/generated/orbpro/manifest/protocol-spec.js +1 -1
- package/src/generated/orbpro/manifest/timer-spec.js +1 -1
- package/src/generated/orbpro/module/canonicalization-rule.js +1 -1
- package/src/generated/orbpro/module/module-bundle-entry.js +1 -1
- package/src/generated/orbpro/module/module-bundle.js +1 -1
- package/src/generated/orbpro/stream/flat-buffer-type-ref.js +1 -1
- package/src/generated/orbpro/stream/typed-arena-buffer.js +1 -1
- package/src/index.d.ts +139 -0
- package/src/index.js +1 -0
- package/src/invoke/codec.js +1 -1
- package/src/manifest/codec.js +1 -1
- package/src/manifest/typeRefs.js +49 -12
- package/src/runtime-host/flatsqlRuntimeStore.js +217 -0
- package/src/runtime-host/index.js +21 -0
- package/src/runtime-host/moduleRegistry.js +92 -0
- package/src/runtime-host/runtimeRegionStore.js +245 -0
- package/src/testing/buildWasmEdgeRunner.js +41 -2
- package/src/testing/index.d.ts +123 -2
- package/src/testing/index.js +1 -0
- package/src/testing/moduleHarness.js +102 -1
- package/src/testing/native/wasmedge_emscripten_pthread_runner.c +2319 -209
- package/src/testing/processInvoke.js +250 -9
- package/src/testing/streamInvokeCodec.js +175 -0
- package/src/transport/records.js +19 -6
|
@@ -61,9 +61,89 @@ typedef struct ThreadLaunchContext {
|
|
|
61
61
|
uint32_t arg;
|
|
62
62
|
} ThreadLaunchContext;
|
|
63
63
|
|
|
64
|
+
typedef enum HostControlOpcode {
|
|
65
|
+
HOST_CONTROL_WRITE = 1,
|
|
66
|
+
HOST_CONTROL_READ = 2,
|
|
67
|
+
HOST_CONTROL_FREE = 3,
|
|
68
|
+
HOST_CONTROL_INSTALL_MODULE = 16,
|
|
69
|
+
HOST_CONTROL_LIST_MODULES = 17,
|
|
70
|
+
HOST_CONTROL_UNLOAD_MODULE = 18,
|
|
71
|
+
HOST_CONTROL_INVOKE_MODULE = 19,
|
|
72
|
+
HOST_CONTROL_APPEND_ROW = 20,
|
|
73
|
+
HOST_CONTROL_LIST_ROWS = 21,
|
|
74
|
+
HOST_CONTROL_RESOLVE_ROW = 22,
|
|
75
|
+
HOST_CONTROL_ALLOCATE_REGION = 23,
|
|
76
|
+
HOST_CONTROL_DESCRIBE_REGION = 24,
|
|
77
|
+
HOST_CONTROL_RESOLVE_RECORD = 25,
|
|
78
|
+
HOST_CONTROL_QUERY_ROWS = 26,
|
|
79
|
+
} HostControlOpcode;
|
|
80
|
+
|
|
64
81
|
#define EM_PTHREAD_STACK_OFFSET 52U
|
|
65
82
|
#define EM_PTHREAD_STACK_SIZE_OFFSET 56U
|
|
66
83
|
#define EM_PTHREAD_EAGAIN 6
|
|
84
|
+
static const uint8_t HOST_CONTROL_MAGIC[4] = {'O', 'R', 'P', 'W'};
|
|
85
|
+
|
|
86
|
+
typedef struct JsonSlice {
|
|
87
|
+
const char *data;
|
|
88
|
+
size_t length;
|
|
89
|
+
} JsonSlice;
|
|
90
|
+
|
|
91
|
+
typedef struct JsonBuffer {
|
|
92
|
+
char *data;
|
|
93
|
+
size_t length;
|
|
94
|
+
size_t capacity;
|
|
95
|
+
} JsonBuffer;
|
|
96
|
+
|
|
97
|
+
typedef struct RuntimeHostModule {
|
|
98
|
+
char *module_id;
|
|
99
|
+
char *wasm_path;
|
|
100
|
+
char *metadata_json;
|
|
101
|
+
char **method_ids;
|
|
102
|
+
size_t method_id_count;
|
|
103
|
+
WasmEdge_ConfigureContext *conf;
|
|
104
|
+
WasmEdge_LoaderContext *loader;
|
|
105
|
+
WasmEdge_ValidatorContext *validator;
|
|
106
|
+
WasmEdge_ExecutorContext *executor;
|
|
107
|
+
WasmEdge_StoreContext *store;
|
|
108
|
+
WasmEdge_ASTModuleContext *ast;
|
|
109
|
+
WasmEdge_ModuleInstanceContext *module;
|
|
110
|
+
RunnerContext runner;
|
|
111
|
+
bool store_mutex_initialized;
|
|
112
|
+
} RuntimeHostModule;
|
|
113
|
+
|
|
114
|
+
typedef struct RuntimeHostRow {
|
|
115
|
+
char *schema_file_id;
|
|
116
|
+
uint64_t row_id;
|
|
117
|
+
char *payload_json;
|
|
118
|
+
} RuntimeHostRow;
|
|
119
|
+
|
|
120
|
+
typedef struct RuntimeHostRegion {
|
|
121
|
+
uint64_t region_id;
|
|
122
|
+
char *layout_id;
|
|
123
|
+
uint32_t record_byte_length;
|
|
124
|
+
uint16_t alignment;
|
|
125
|
+
uint8_t **records;
|
|
126
|
+
size_t record_count;
|
|
127
|
+
} RuntimeHostRegion;
|
|
128
|
+
|
|
129
|
+
typedef struct RuntimeHostState {
|
|
130
|
+
RuntimeHostModule *modules;
|
|
131
|
+
size_t module_count;
|
|
132
|
+
size_t module_capacity;
|
|
133
|
+
RuntimeHostRow *rows;
|
|
134
|
+
size_t row_count;
|
|
135
|
+
size_t row_capacity;
|
|
136
|
+
uint64_t next_row_id;
|
|
137
|
+
RuntimeHostRegion *regions;
|
|
138
|
+
size_t region_count;
|
|
139
|
+
size_t region_capacity;
|
|
140
|
+
uint64_t next_region_id;
|
|
141
|
+
} RuntimeHostState;
|
|
142
|
+
|
|
143
|
+
static WasmEdge_FunctionInstanceContext *find_first_available_function(
|
|
144
|
+
WasmEdge_ModuleInstanceContext *module,
|
|
145
|
+
const char *const *names,
|
|
146
|
+
size_t name_count);
|
|
67
147
|
|
|
68
148
|
static WasmEdge_Result stub_void(
|
|
69
149
|
void *Data,
|
|
@@ -144,10 +224,16 @@ static WasmEdge_Result stub_pthread_create(
|
|
|
144
224
|
WasmEdge_ModuleInstanceFindFunction(thread_context->module, export_name);
|
|
145
225
|
WasmEdge_StringDelete(export_name);
|
|
146
226
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
227
|
+
{
|
|
228
|
+
static const char *const stack_restore_names[] = {
|
|
229
|
+
"_emscripten_stack_restore",
|
|
230
|
+
"stackRestore",
|
|
231
|
+
};
|
|
232
|
+
thread_context->stack_restore = find_first_available_function(
|
|
233
|
+
thread_context->module,
|
|
234
|
+
stack_restore_names,
|
|
235
|
+
sizeof(stack_restore_names) / sizeof(stack_restore_names[0]));
|
|
236
|
+
}
|
|
151
237
|
|
|
152
238
|
export_name = WasmEdge_StringCreateByCString("_emscripten_thread_init");
|
|
153
239
|
thread_context->thread_init =
|
|
@@ -743,252 +829,2276 @@ static bool invoke_function(
|
|
|
743
829
|
return false;
|
|
744
830
|
}
|
|
745
831
|
|
|
746
|
-
static
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
}
|
|
755
|
-
if (context->executor != NULL) {
|
|
756
|
-
WasmEdge_ExecutorDelete(context->executor);
|
|
757
|
-
}
|
|
758
|
-
free(context);
|
|
832
|
+
static WasmEdge_FunctionInstanceContext *find_function(
|
|
833
|
+
WasmEdge_ModuleInstanceContext *module,
|
|
834
|
+
const char *name) {
|
|
835
|
+
WasmEdge_String function_name = WasmEdge_StringCreateByCString(name);
|
|
836
|
+
WasmEdge_FunctionInstanceContext *function =
|
|
837
|
+
WasmEdge_ModuleInstanceFindFunction(module, function_name);
|
|
838
|
+
WasmEdge_StringDelete(function_name);
|
|
839
|
+
return function;
|
|
759
840
|
}
|
|
760
841
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
if (!read_guest_u32(
|
|
772
|
-
context->runner->shared_memory,
|
|
773
|
-
context->pthread_ptr + EM_PTHREAD_STACK_OFFSET,
|
|
774
|
-
&stack_high) ||
|
|
775
|
-
!read_guest_u32(
|
|
776
|
-
context->runner->shared_memory,
|
|
777
|
-
context->pthread_ptr + EM_PTHREAD_STACK_SIZE_OFFSET,
|
|
778
|
-
&stack_size)) {
|
|
779
|
-
destroy_thread_launch_context(context);
|
|
780
|
-
return NULL;
|
|
781
|
-
}
|
|
782
|
-
const uint32_t stack_low = stack_high - stack_size;
|
|
783
|
-
|
|
784
|
-
WasmEdge_Value params[6];
|
|
785
|
-
WasmEdge_Value returns[1];
|
|
786
|
-
|
|
787
|
-
params[0] = WasmEdge_ValueGenI32((int32_t)stack_high);
|
|
788
|
-
params[1] = WasmEdge_ValueGenI32((int32_t)stack_low);
|
|
789
|
-
if (!invoke_function(
|
|
790
|
-
context->executor,
|
|
791
|
-
context->stack_set_limits,
|
|
792
|
-
params,
|
|
793
|
-
2,
|
|
794
|
-
NULL,
|
|
795
|
-
0,
|
|
796
|
-
"emscripten_stack_set_limits")) {
|
|
797
|
-
goto thread_crashed;
|
|
842
|
+
static WasmEdge_FunctionInstanceContext *find_first_available_function(
|
|
843
|
+
WasmEdge_ModuleInstanceContext *module,
|
|
844
|
+
const char *const *names,
|
|
845
|
+
size_t name_count) {
|
|
846
|
+
for (size_t index = 0; index < name_count; ++index) {
|
|
847
|
+
WasmEdge_FunctionInstanceContext *function =
|
|
848
|
+
find_function(module, names[index]);
|
|
849
|
+
if (function != NULL) {
|
|
850
|
+
return function;
|
|
851
|
+
}
|
|
798
852
|
}
|
|
853
|
+
return NULL;
|
|
854
|
+
}
|
|
799
855
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
goto thread_crashed;
|
|
856
|
+
static WasmEdge_MemoryInstanceContext *resolve_guest_memory(
|
|
857
|
+
WasmEdge_ModuleInstanceContext *module,
|
|
858
|
+
RunnerContext *runner) {
|
|
859
|
+
WasmEdge_String memory_name = WasmEdge_StringCreateByCString("memory");
|
|
860
|
+
WasmEdge_MemoryInstanceContext *memory =
|
|
861
|
+
WasmEdge_ModuleInstanceFindMemory(module, memory_name);
|
|
862
|
+
WasmEdge_StringDelete(memory_name);
|
|
863
|
+
if (memory != NULL) {
|
|
864
|
+
return memory;
|
|
810
865
|
}
|
|
866
|
+
return runner->shared_memory;
|
|
867
|
+
}
|
|
811
868
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
context->executor,
|
|
820
|
-
context->thread_init,
|
|
821
|
-
params,
|
|
822
|
-
6,
|
|
823
|
-
NULL,
|
|
824
|
-
0,
|
|
825
|
-
"_emscripten_thread_init")) {
|
|
826
|
-
goto thread_crashed;
|
|
869
|
+
static bool write_guest_memory(
|
|
870
|
+
WasmEdge_MemoryInstanceContext *memory,
|
|
871
|
+
uint32_t offset,
|
|
872
|
+
const uint8_t *bytes,
|
|
873
|
+
uint32_t length) {
|
|
874
|
+
if (length == 0) {
|
|
875
|
+
return true;
|
|
827
876
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
NULL,
|
|
833
|
-
0,
|
|
834
|
-
returns,
|
|
835
|
-
1,
|
|
836
|
-
"_emscripten_tls_init")) {
|
|
837
|
-
goto thread_crashed;
|
|
877
|
+
const WasmEdge_Result result =
|
|
878
|
+
WasmEdge_MemoryInstanceSetData(memory, bytes, offset, length);
|
|
879
|
+
if (WasmEdge_ResultOK(result)) {
|
|
880
|
+
return true;
|
|
838
881
|
}
|
|
882
|
+
fprintf(
|
|
883
|
+
stderr,
|
|
884
|
+
"guest memory write failed: %s (0x%x)\n",
|
|
885
|
+
WasmEdge_ResultGetMessage(result),
|
|
886
|
+
WasmEdge_ResultGetCode(result));
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
839
889
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
if (
|
|
846
|
-
|
|
847
|
-
stderr,
|
|
848
|
-
"table lookup failed: %s (0x%x)\n",
|
|
849
|
-
WasmEdge_ResultGetMessage(table_result),
|
|
850
|
-
WasmEdge_ResultGetCode(table_result));
|
|
851
|
-
goto thread_crashed;
|
|
890
|
+
static bool read_guest_memory(
|
|
891
|
+
const WasmEdge_MemoryInstanceContext *memory,
|
|
892
|
+
uint32_t offset,
|
|
893
|
+
uint8_t *bytes,
|
|
894
|
+
uint32_t length) {
|
|
895
|
+
if (length == 0) {
|
|
896
|
+
return true;
|
|
852
897
|
}
|
|
853
|
-
const
|
|
854
|
-
|
|
855
|
-
if (
|
|
856
|
-
|
|
857
|
-
goto thread_crashed;
|
|
898
|
+
const WasmEdge_Result result =
|
|
899
|
+
WasmEdge_MemoryInstanceGetData(memory, bytes, offset, length);
|
|
900
|
+
if (WasmEdge_ResultOK(result)) {
|
|
901
|
+
return true;
|
|
858
902
|
}
|
|
903
|
+
fprintf(
|
|
904
|
+
stderr,
|
|
905
|
+
"guest memory read failed: %s (0x%x)\n",
|
|
906
|
+
WasmEdge_ResultGetMessage(result),
|
|
907
|
+
WasmEdge_ResultGetCode(result));
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
859
910
|
|
|
860
|
-
|
|
911
|
+
static bool guest_malloc(
|
|
912
|
+
WasmEdge_ExecutorContext *executor,
|
|
913
|
+
WasmEdge_FunctionInstanceContext *malloc_fn,
|
|
914
|
+
uint32_t length,
|
|
915
|
+
uint32_t *pointer_out) {
|
|
916
|
+
WasmEdge_Value params[1];
|
|
917
|
+
WasmEdge_Value returns[1];
|
|
918
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)length);
|
|
861
919
|
if (!invoke_function(
|
|
862
|
-
|
|
863
|
-
|
|
920
|
+
executor,
|
|
921
|
+
malloc_fn,
|
|
864
922
|
params,
|
|
865
923
|
1,
|
|
866
924
|
returns,
|
|
867
925
|
1,
|
|
868
|
-
"
|
|
869
|
-
|
|
926
|
+
"plugin_alloc")) {
|
|
927
|
+
return false;
|
|
870
928
|
}
|
|
929
|
+
*pointer_out = (uint32_t)WasmEdge_ValueGetI32(returns[0]);
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
871
932
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
933
|
+
static bool guest_free(
|
|
934
|
+
WasmEdge_ExecutorContext *executor,
|
|
935
|
+
WasmEdge_FunctionInstanceContext *free_fn,
|
|
936
|
+
uint32_t pointer,
|
|
937
|
+
uint32_t length) {
|
|
938
|
+
if (pointer == 0) {
|
|
939
|
+
return true;
|
|
940
|
+
}
|
|
941
|
+
WasmEdge_Value params[2];
|
|
942
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)pointer);
|
|
943
|
+
params[1] = WasmEdge_ValueGenI32((int32_t)length);
|
|
944
|
+
return invoke_function(
|
|
945
|
+
executor,
|
|
946
|
+
free_fn,
|
|
876
947
|
params,
|
|
877
|
-
|
|
948
|
+
2,
|
|
878
949
|
NULL,
|
|
879
950
|
0,
|
|
880
|
-
"
|
|
881
|
-
|
|
882
|
-
return NULL;
|
|
951
|
+
"plugin_free");
|
|
952
|
+
}
|
|
883
953
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
"
|
|
954
|
+
static bool read_exact(FILE *stream, uint8_t *buffer, size_t length) {
|
|
955
|
+
size_t offset = 0;
|
|
956
|
+
while (offset < length) {
|
|
957
|
+
const size_t read_len = fread(buffer + offset, 1, length - offset, stream);
|
|
958
|
+
if (read_len == 0) {
|
|
959
|
+
if (feof(stream)) {
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
if (ferror(stream)) {
|
|
963
|
+
perror("fread");
|
|
964
|
+
}
|
|
965
|
+
return false;
|
|
966
|
+
}
|
|
967
|
+
offset += read_len;
|
|
894
968
|
}
|
|
895
|
-
|
|
896
|
-
return NULL;
|
|
969
|
+
return true;
|
|
897
970
|
}
|
|
898
971
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
972
|
+
static bool write_all(FILE *stream, const uint8_t *buffer, size_t length) {
|
|
973
|
+
size_t offset = 0;
|
|
974
|
+
while (offset < length) {
|
|
975
|
+
const size_t write_len =
|
|
976
|
+
fwrite(buffer + offset, 1, length - offset, stream);
|
|
977
|
+
if (write_len == 0) {
|
|
978
|
+
if (ferror(stream)) {
|
|
979
|
+
perror("fwrite");
|
|
980
|
+
}
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
offset += write_len;
|
|
903
984
|
}
|
|
985
|
+
return fflush(stream) == 0;
|
|
986
|
+
}
|
|
904
987
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
WasmEdge_ExecutorContext *executor = WasmEdge_ExecutorCreate(conf, NULL);
|
|
910
|
-
WasmEdge_StoreContext *store = WasmEdge_StoreCreate();
|
|
911
|
-
RunnerContext runner = {
|
|
912
|
-
.conf = conf,
|
|
913
|
-
.ast = NULL,
|
|
914
|
-
.store = store,
|
|
915
|
-
.shared_memory = NULL,
|
|
916
|
-
};
|
|
917
|
-
pthread_mutex_init(&runner.store_mutex, NULL);
|
|
988
|
+
static uint32_t read_le_u32_bytes(const uint8_t *bytes) {
|
|
989
|
+
return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
|
|
990
|
+
((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
|
|
991
|
+
}
|
|
918
992
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
runner.ast = ast;
|
|
925
|
-
res = WasmEdge_ValidatorValidate(validator, ast);
|
|
926
|
-
if (!WasmEdge_ResultOK(res)) {
|
|
927
|
-
fail_result("validate", res);
|
|
928
|
-
}
|
|
993
|
+
static void runtime_host_state_init(RuntimeHostState *state) {
|
|
994
|
+
memset(state, 0, sizeof(*state));
|
|
995
|
+
state->next_row_id = 1;
|
|
996
|
+
state->next_region_id = 1;
|
|
997
|
+
}
|
|
929
998
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
(uint32_t)(argc - 1),
|
|
934
|
-
NULL,
|
|
935
|
-
0,
|
|
936
|
-
NULL,
|
|
937
|
-
0,
|
|
938
|
-
STDIN_FILENO,
|
|
939
|
-
STDOUT_FILENO,
|
|
940
|
-
STDERR_FILENO);
|
|
941
|
-
res = WasmEdge_ExecutorRegisterImport(executor, store, wasi);
|
|
942
|
-
if (!WasmEdge_ResultOK(res)) {
|
|
943
|
-
fail_result("register wasi", res);
|
|
944
|
-
}
|
|
999
|
+
static void json_buffer_init(JsonBuffer *buffer) {
|
|
1000
|
+
memset(buffer, 0, sizeof(*buffer));
|
|
1001
|
+
}
|
|
945
1002
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1003
|
+
static void json_buffer_free(JsonBuffer *buffer) {
|
|
1004
|
+
free(buffer->data);
|
|
1005
|
+
buffer->data = NULL;
|
|
1006
|
+
buffer->length = 0;
|
|
1007
|
+
buffer->capacity = 0;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
static bool json_buffer_reserve(JsonBuffer *buffer, size_t additional) {
|
|
1011
|
+
const size_t required = buffer->length + additional + 1;
|
|
1012
|
+
if (required <= buffer->capacity) {
|
|
1013
|
+
return true;
|
|
952
1014
|
}
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1015
|
+
size_t next_capacity = buffer->capacity == 0 ? 256 : buffer->capacity;
|
|
1016
|
+
while (next_capacity < required) {
|
|
1017
|
+
next_capacity *= 2;
|
|
956
1018
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
import_config.receive_on_main_thread_param_len == 4
|
|
961
|
-
? 4
|
|
962
|
-
: 5,
|
|
963
|
-
import_config.notify_mailbox_postmessage_param_len == 3
|
|
964
|
-
? 3
|
|
965
|
-
: 2);
|
|
966
|
-
res = WasmEdge_ExecutorRegisterImport(executor, store, env);
|
|
967
|
-
if (!WasmEdge_ResultOK(res)) {
|
|
968
|
-
fail_result("register env", res);
|
|
1019
|
+
char *next = realloc(buffer->data, next_capacity);
|
|
1020
|
+
if (next == NULL) {
|
|
1021
|
+
return false;
|
|
969
1022
|
}
|
|
1023
|
+
buffer->data = next;
|
|
1024
|
+
buffer->capacity = next_capacity;
|
|
1025
|
+
return true;
|
|
1026
|
+
}
|
|
970
1027
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1028
|
+
static bool json_buffer_append_bytes(
|
|
1029
|
+
JsonBuffer *buffer,
|
|
1030
|
+
const char *bytes,
|
|
1031
|
+
size_t length) {
|
|
1032
|
+
if (!json_buffer_reserve(buffer, length)) {
|
|
1033
|
+
return false;
|
|
975
1034
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1035
|
+
memcpy(buffer->data + buffer->length, bytes, length);
|
|
1036
|
+
buffer->length += length;
|
|
1037
|
+
buffer->data[buffer->length] = '\0';
|
|
1038
|
+
return true;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
static bool json_buffer_append_cstr(JsonBuffer *buffer, const char *value) {
|
|
1042
|
+
return json_buffer_append_bytes(buffer, value, strlen(value));
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
static bool json_buffer_append_char(JsonBuffer *buffer, char value) {
|
|
1046
|
+
return json_buffer_append_bytes(buffer, &value, 1);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
static bool json_buffer_append_u64(JsonBuffer *buffer, uint64_t value) {
|
|
1050
|
+
char scratch[32];
|
|
1051
|
+
const int written =
|
|
1052
|
+
snprintf(scratch, sizeof(scratch), "%llu", (unsigned long long)value);
|
|
1053
|
+
return written > 0 &&
|
|
1054
|
+
json_buffer_append_bytes(buffer, scratch, (size_t)written);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
static bool json_buffer_append_u32(JsonBuffer *buffer, uint32_t value) {
|
|
1058
|
+
char scratch[32];
|
|
1059
|
+
const int written = snprintf(scratch, sizeof(scratch), "%u", value);
|
|
1060
|
+
return written > 0 &&
|
|
1061
|
+
json_buffer_append_bytes(buffer, scratch, (size_t)written);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
static bool json_buffer_append_json_string(
|
|
1065
|
+
JsonBuffer *buffer,
|
|
1066
|
+
const char *value) {
|
|
1067
|
+
if (!json_buffer_append_char(buffer, '"')) {
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1070
|
+
for (const unsigned char *cursor = (const unsigned char *)value;
|
|
1071
|
+
*cursor != '\0';
|
|
1072
|
+
++cursor) {
|
|
1073
|
+
switch (*cursor) {
|
|
1074
|
+
case '"':
|
|
1075
|
+
case '\\':
|
|
1076
|
+
if (!json_buffer_append_char(buffer, '\\') ||
|
|
1077
|
+
!json_buffer_append_char(buffer, (char)*cursor)) {
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
1080
|
+
break;
|
|
1081
|
+
case '\b':
|
|
1082
|
+
if (!json_buffer_append_cstr(buffer, "\\b")) {
|
|
1083
|
+
return false;
|
|
1084
|
+
}
|
|
1085
|
+
break;
|
|
1086
|
+
case '\f':
|
|
1087
|
+
if (!json_buffer_append_cstr(buffer, "\\f")) {
|
|
1088
|
+
return false;
|
|
1089
|
+
}
|
|
1090
|
+
break;
|
|
1091
|
+
case '\n':
|
|
1092
|
+
if (!json_buffer_append_cstr(buffer, "\\n")) {
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
break;
|
|
1096
|
+
case '\r':
|
|
1097
|
+
if (!json_buffer_append_cstr(buffer, "\\r")) {
|
|
1098
|
+
return false;
|
|
1099
|
+
}
|
|
1100
|
+
break;
|
|
1101
|
+
case '\t':
|
|
1102
|
+
if (!json_buffer_append_cstr(buffer, "\\t")) {
|
|
1103
|
+
return false;
|
|
1104
|
+
}
|
|
1105
|
+
break;
|
|
1106
|
+
default:
|
|
1107
|
+
if (*cursor < 0x20U) {
|
|
1108
|
+
char escaped[7];
|
|
1109
|
+
const int written =
|
|
1110
|
+
snprintf(escaped, sizeof(escaped), "\\u%04x", *cursor);
|
|
1111
|
+
if (written <= 0 ||
|
|
1112
|
+
!json_buffer_append_bytes(buffer, escaped, (size_t)written)) {
|
|
1113
|
+
return false;
|
|
1114
|
+
}
|
|
1115
|
+
} else if (!json_buffer_append_char(buffer, (char)*cursor)) {
|
|
1116
|
+
return false;
|
|
1117
|
+
}
|
|
1118
|
+
break;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return json_buffer_append_char(buffer, '"');
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
static uint8_t *json_buffer_detach(
|
|
1125
|
+
JsonBuffer *buffer,
|
|
1126
|
+
uint32_t *length_out) {
|
|
1127
|
+
uint8_t *bytes = NULL;
|
|
1128
|
+
if (buffer->length > 0) {
|
|
1129
|
+
bytes = malloc(buffer->length);
|
|
1130
|
+
if (bytes == NULL) {
|
|
1131
|
+
return NULL;
|
|
1132
|
+
}
|
|
1133
|
+
memcpy(bytes, buffer->data, buffer->length);
|
|
1134
|
+
}
|
|
1135
|
+
*length_out = (uint32_t)buffer->length;
|
|
1136
|
+
json_buffer_free(buffer);
|
|
1137
|
+
return bytes;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
static void skip_json_whitespace(
|
|
1141
|
+
const char *json,
|
|
1142
|
+
size_t length,
|
|
1143
|
+
size_t *offset) {
|
|
1144
|
+
while (*offset < length) {
|
|
1145
|
+
const char ch = json[*offset];
|
|
1146
|
+
if (ch != ' ' && ch != '\n' && ch != '\r' && ch != '\t') {
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
*offset += 1;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
static bool consume_json_string(
|
|
1154
|
+
const char *json,
|
|
1155
|
+
size_t length,
|
|
1156
|
+
size_t *offset) {
|
|
1157
|
+
if (*offset >= length || json[*offset] != '"') {
|
|
1158
|
+
return false;
|
|
1159
|
+
}
|
|
1160
|
+
*offset += 1;
|
|
1161
|
+
while (*offset < length) {
|
|
1162
|
+
const char ch = json[*offset];
|
|
1163
|
+
*offset += 1;
|
|
1164
|
+
if (ch == '\\') {
|
|
1165
|
+
if (*offset >= length) {
|
|
1166
|
+
return false;
|
|
1167
|
+
}
|
|
1168
|
+
*offset += 1;
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
if (ch == '"') {
|
|
1172
|
+
return true;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
static bool consume_json_value(
|
|
1179
|
+
const char *json,
|
|
1180
|
+
size_t length,
|
|
1181
|
+
size_t *offset) {
|
|
1182
|
+
skip_json_whitespace(json, length, offset);
|
|
1183
|
+
if (*offset >= length) {
|
|
1184
|
+
return false;
|
|
1185
|
+
}
|
|
1186
|
+
const char ch = json[*offset];
|
|
1187
|
+
if (ch == '"') {
|
|
1188
|
+
return consume_json_string(json, length, offset);
|
|
1189
|
+
}
|
|
1190
|
+
if (ch == '{' || ch == '[') {
|
|
1191
|
+
const char open = ch;
|
|
1192
|
+
const char close = ch == '{' ? '}' : ']';
|
|
1193
|
+
*offset += 1;
|
|
1194
|
+
skip_json_whitespace(json, length, offset);
|
|
1195
|
+
if (*offset < length && json[*offset] == close) {
|
|
1196
|
+
*offset += 1;
|
|
1197
|
+
return true;
|
|
1198
|
+
}
|
|
1199
|
+
for (;;) {
|
|
1200
|
+
if (open == '{') {
|
|
1201
|
+
if (!consume_json_string(json, length, offset)) {
|
|
1202
|
+
return false;
|
|
1203
|
+
}
|
|
1204
|
+
skip_json_whitespace(json, length, offset);
|
|
1205
|
+
if (*offset >= length || json[*offset] != ':') {
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
*offset += 1;
|
|
1209
|
+
}
|
|
1210
|
+
if (!consume_json_value(json, length, offset)) {
|
|
1211
|
+
return false;
|
|
1212
|
+
}
|
|
1213
|
+
skip_json_whitespace(json, length, offset);
|
|
1214
|
+
if (*offset >= length) {
|
|
1215
|
+
return false;
|
|
1216
|
+
}
|
|
1217
|
+
if (json[*offset] == close) {
|
|
1218
|
+
*offset += 1;
|
|
1219
|
+
return true;
|
|
1220
|
+
}
|
|
1221
|
+
if (json[*offset] != ',') {
|
|
1222
|
+
return false;
|
|
1223
|
+
}
|
|
1224
|
+
*offset += 1;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
while (*offset < length) {
|
|
1228
|
+
const char value_ch = json[*offset];
|
|
1229
|
+
if (value_ch == ',' || value_ch == '}' || value_ch == ']' ||
|
|
1230
|
+
value_ch == ' ' || value_ch == '\n' || value_ch == '\r' ||
|
|
1231
|
+
value_ch == '\t') {
|
|
1232
|
+
return true;
|
|
1233
|
+
}
|
|
1234
|
+
*offset += 1;
|
|
1235
|
+
}
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
static bool duplicate_json_string_value(
|
|
1240
|
+
JsonSlice slice,
|
|
1241
|
+
char **value_out) {
|
|
1242
|
+
if (slice.length < 2 || slice.data[0] != '"' ||
|
|
1243
|
+
slice.data[slice.length - 1] != '"') {
|
|
1244
|
+
return false;
|
|
1245
|
+
}
|
|
1246
|
+
char *value = malloc(slice.length);
|
|
1247
|
+
if (value == NULL) {
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
size_t write_index = 0;
|
|
1251
|
+
for (size_t index = 1; index + 1 < slice.length; ++index) {
|
|
1252
|
+
char ch = slice.data[index];
|
|
1253
|
+
if (ch == '\\') {
|
|
1254
|
+
if (index + 1 >= slice.length - 1) {
|
|
1255
|
+
free(value);
|
|
1256
|
+
return false;
|
|
1257
|
+
}
|
|
1258
|
+
index += 1;
|
|
1259
|
+
ch = slice.data[index];
|
|
1260
|
+
switch (ch) {
|
|
1261
|
+
case '"':
|
|
1262
|
+
case '\\':
|
|
1263
|
+
case '/':
|
|
1264
|
+
value[write_index++] = ch;
|
|
1265
|
+
break;
|
|
1266
|
+
case 'b':
|
|
1267
|
+
value[write_index++] = '\b';
|
|
1268
|
+
break;
|
|
1269
|
+
case 'f':
|
|
1270
|
+
value[write_index++] = '\f';
|
|
1271
|
+
break;
|
|
1272
|
+
case 'n':
|
|
1273
|
+
value[write_index++] = '\n';
|
|
1274
|
+
break;
|
|
1275
|
+
case 'r':
|
|
1276
|
+
value[write_index++] = '\r';
|
|
1277
|
+
break;
|
|
1278
|
+
case 't':
|
|
1279
|
+
value[write_index++] = '\t';
|
|
1280
|
+
break;
|
|
1281
|
+
default:
|
|
1282
|
+
free(value);
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
} else {
|
|
1286
|
+
value[write_index++] = ch;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
value[write_index] = '\0';
|
|
1290
|
+
*value_out = value;
|
|
1291
|
+
return true;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
static bool duplicate_json_slice(JsonSlice slice, char **value_out) {
|
|
1295
|
+
char *value = malloc(slice.length + 1);
|
|
1296
|
+
if (value == NULL) {
|
|
1297
|
+
return false;
|
|
1298
|
+
}
|
|
1299
|
+
memcpy(value, slice.data, slice.length);
|
|
1300
|
+
value[slice.length] = '\0';
|
|
1301
|
+
*value_out = value;
|
|
1302
|
+
return true;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
static bool json_slice_is_null(JsonSlice slice) {
|
|
1306
|
+
return slice.length == 4 && memcmp(slice.data, "null", 4) == 0;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
static bool parse_json_u64(JsonSlice slice, uint64_t *value_out) {
|
|
1310
|
+
char scratch[64];
|
|
1311
|
+
if (slice.length == 0 || slice.length >= sizeof(scratch)) {
|
|
1312
|
+
return false;
|
|
1313
|
+
}
|
|
1314
|
+
memcpy(scratch, slice.data, slice.length);
|
|
1315
|
+
scratch[slice.length] = '\0';
|
|
1316
|
+
char *end = NULL;
|
|
1317
|
+
const unsigned long long value = strtoull(scratch, &end, 10);
|
|
1318
|
+
if (end == scratch || *end != '\0') {
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
*value_out = (uint64_t)value;
|
|
1322
|
+
return true;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
static bool find_json_object_field(
|
|
1326
|
+
const char *json,
|
|
1327
|
+
size_t length,
|
|
1328
|
+
const char *field_name,
|
|
1329
|
+
JsonSlice *value_out) {
|
|
1330
|
+
size_t offset = 0;
|
|
1331
|
+
skip_json_whitespace(json, length, &offset);
|
|
1332
|
+
if (offset >= length || json[offset] != '{') {
|
|
1333
|
+
return false;
|
|
1334
|
+
}
|
|
1335
|
+
offset += 1;
|
|
1336
|
+
for (;;) {
|
|
1337
|
+
skip_json_whitespace(json, length, &offset);
|
|
1338
|
+
if (offset >= length) {
|
|
1339
|
+
return false;
|
|
1340
|
+
}
|
|
1341
|
+
if (json[offset] == '}') {
|
|
1342
|
+
return false;
|
|
1343
|
+
}
|
|
1344
|
+
const size_t key_start = offset;
|
|
1345
|
+
if (!consume_json_string(json, length, &offset)) {
|
|
1346
|
+
return false;
|
|
1347
|
+
}
|
|
1348
|
+
JsonSlice key_slice = {
|
|
1349
|
+
.data = json + key_start,
|
|
1350
|
+
.length = offset - key_start,
|
|
1351
|
+
};
|
|
1352
|
+
char *key_value = NULL;
|
|
1353
|
+
if (!duplicate_json_string_value(key_slice, &key_value)) {
|
|
1354
|
+
return false;
|
|
1355
|
+
}
|
|
1356
|
+
skip_json_whitespace(json, length, &offset);
|
|
1357
|
+
if (offset >= length || json[offset] != ':') {
|
|
1358
|
+
free(key_value);
|
|
1359
|
+
return false;
|
|
1360
|
+
}
|
|
1361
|
+
offset += 1;
|
|
1362
|
+
skip_json_whitespace(json, length, &offset);
|
|
1363
|
+
const size_t value_start = offset;
|
|
1364
|
+
if (!consume_json_value(json, length, &offset)) {
|
|
1365
|
+
free(key_value);
|
|
1366
|
+
return false;
|
|
1367
|
+
}
|
|
1368
|
+
const bool matched = strcmp(key_value, field_name) == 0;
|
|
1369
|
+
free(key_value);
|
|
1370
|
+
if (matched) {
|
|
1371
|
+
value_out->data = json + value_start;
|
|
1372
|
+
value_out->length = offset - value_start;
|
|
1373
|
+
return true;
|
|
1374
|
+
}
|
|
1375
|
+
skip_json_whitespace(json, length, &offset);
|
|
1376
|
+
if (offset >= length) {
|
|
1377
|
+
return false;
|
|
1378
|
+
}
|
|
1379
|
+
if (json[offset] == '}') {
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
if (json[offset] != ',') {
|
|
1383
|
+
return false;
|
|
1384
|
+
}
|
|
1385
|
+
offset += 1;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
static bool ensure_runtime_host_capacity(
|
|
1390
|
+
void **buffer,
|
|
1391
|
+
size_t *capacity,
|
|
1392
|
+
size_t count,
|
|
1393
|
+
size_t item_size) {
|
|
1394
|
+
if (count < *capacity) {
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
size_t next_capacity = *capacity == 0 ? 8 : *capacity * 2;
|
|
1398
|
+
while (next_capacity <= count) {
|
|
1399
|
+
next_capacity *= 2;
|
|
1400
|
+
}
|
|
1401
|
+
void *next = realloc(*buffer, next_capacity * item_size);
|
|
1402
|
+
if (next == NULL) {
|
|
1403
|
+
return false;
|
|
1404
|
+
}
|
|
1405
|
+
*buffer = next;
|
|
1406
|
+
*capacity = next_capacity;
|
|
1407
|
+
return true;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
static void runtime_host_module_init(RuntimeHostModule *module) {
|
|
1411
|
+
memset(module, 0, sizeof(*module));
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
static void destroy_runtime_host_module(RuntimeHostModule *module) {
|
|
1415
|
+
if (module == NULL) {
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
free(module->module_id);
|
|
1419
|
+
free(module->wasm_path);
|
|
1420
|
+
free(module->metadata_json);
|
|
1421
|
+
for (size_t index = 0; index < module->method_id_count; ++index) {
|
|
1422
|
+
free(module->method_ids[index]);
|
|
1423
|
+
}
|
|
1424
|
+
free(module->method_ids);
|
|
1425
|
+
if (module->store != NULL) {
|
|
1426
|
+
WasmEdge_StoreDelete(module->store);
|
|
1427
|
+
}
|
|
1428
|
+
if (module->executor != NULL) {
|
|
1429
|
+
WasmEdge_ExecutorDelete(module->executor);
|
|
1430
|
+
}
|
|
1431
|
+
if (module->validator != NULL) {
|
|
1432
|
+
WasmEdge_ValidatorDelete(module->validator);
|
|
1433
|
+
}
|
|
1434
|
+
if (module->loader != NULL) {
|
|
1435
|
+
WasmEdge_LoaderDelete(module->loader);
|
|
1436
|
+
}
|
|
1437
|
+
if (module->conf != NULL) {
|
|
1438
|
+
WasmEdge_ConfigureDelete(module->conf);
|
|
1439
|
+
}
|
|
1440
|
+
if (module->ast != NULL) {
|
|
1441
|
+
WasmEdge_ASTModuleDelete(module->ast);
|
|
1442
|
+
}
|
|
1443
|
+
if (module->store_mutex_initialized) {
|
|
1444
|
+
pthread_mutex_destroy(&module->runner.store_mutex);
|
|
1445
|
+
}
|
|
1446
|
+
memset(module, 0, sizeof(*module));
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
static void destroy_runtime_host_region(RuntimeHostRegion *region) {
|
|
1450
|
+
if (region == NULL) {
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
for (size_t index = 0; index < region->record_count; ++index) {
|
|
1454
|
+
free(region->records[index]);
|
|
1455
|
+
}
|
|
1456
|
+
free(region->records);
|
|
1457
|
+
free(region->layout_id);
|
|
1458
|
+
memset(region, 0, sizeof(*region));
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
static void runtime_host_state_destroy(RuntimeHostState *state) {
|
|
1462
|
+
for (size_t index = 0; index < state->module_count; ++index) {
|
|
1463
|
+
destroy_runtime_host_module(&state->modules[index]);
|
|
1464
|
+
}
|
|
1465
|
+
free(state->modules);
|
|
1466
|
+
for (size_t index = 0; index < state->row_count; ++index) {
|
|
1467
|
+
free(state->rows[index].schema_file_id);
|
|
1468
|
+
free(state->rows[index].payload_json);
|
|
1469
|
+
}
|
|
1470
|
+
free(state->rows);
|
|
1471
|
+
for (size_t index = 0; index < state->region_count; ++index) {
|
|
1472
|
+
destroy_runtime_host_region(&state->regions[index]);
|
|
1473
|
+
}
|
|
1474
|
+
free(state->regions);
|
|
1475
|
+
memset(state, 0, sizeof(*state));
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
static bool invoke_optional_module_init(
|
|
1479
|
+
WasmEdge_ExecutorContext *executor,
|
|
1480
|
+
WasmEdge_ModuleInstanceContext *module,
|
|
1481
|
+
bool service_mode) {
|
|
1482
|
+
if (service_mode) {
|
|
1483
|
+
WasmEdge_FunctionInstanceContext *ctors =
|
|
1484
|
+
find_function(module, "__wasm_call_ctors");
|
|
1485
|
+
if (ctors != NULL) {
|
|
1486
|
+
return invoke_function(
|
|
1487
|
+
executor,
|
|
1488
|
+
ctors,
|
|
1489
|
+
NULL,
|
|
1490
|
+
0,
|
|
1491
|
+
NULL,
|
|
1492
|
+
0,
|
|
1493
|
+
"__wasm_call_ctors");
|
|
1494
|
+
}
|
|
1495
|
+
return true;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
WasmEdge_FunctionInstanceContext *start = find_function(module, "_start");
|
|
1499
|
+
if (start != NULL) {
|
|
1500
|
+
return invoke_function(executor, start, NULL, 0, NULL, 0, "_start");
|
|
1501
|
+
}
|
|
1502
|
+
WasmEdge_FunctionInstanceContext *ctors =
|
|
1503
|
+
find_function(module, "__wasm_call_ctors");
|
|
1504
|
+
if (ctors != NULL) {
|
|
1505
|
+
return invoke_function(
|
|
1506
|
+
executor,
|
|
1507
|
+
ctors,
|
|
1508
|
+
NULL,
|
|
1509
|
+
0,
|
|
1510
|
+
NULL,
|
|
1511
|
+
0,
|
|
1512
|
+
"__wasm_call_ctors");
|
|
1513
|
+
}
|
|
1514
|
+
return true;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
static bool serve_plugin_invoke_requests(
|
|
1518
|
+
WasmEdge_ExecutorContext *executor,
|
|
1519
|
+
WasmEdge_ModuleInstanceContext *module,
|
|
1520
|
+
RunnerContext *runner) {
|
|
1521
|
+
WasmEdge_MemoryInstanceContext *memory = resolve_guest_memory(module, runner);
|
|
1522
|
+
if (memory == NULL) {
|
|
1523
|
+
fprintf(stderr, "guest memory export/import was not found\n");
|
|
1524
|
+
return false;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
WasmEdge_FunctionInstanceContext *malloc_fn =
|
|
1528
|
+
find_function(module, "plugin_alloc");
|
|
1529
|
+
WasmEdge_FunctionInstanceContext *free_fn =
|
|
1530
|
+
find_function(module, "plugin_free");
|
|
1531
|
+
WasmEdge_FunctionInstanceContext *invoke_fn =
|
|
1532
|
+
find_function(module, "plugin_invoke_stream");
|
|
1533
|
+
if (malloc_fn == NULL || free_fn == NULL || invoke_fn == NULL) {
|
|
1534
|
+
fprintf(
|
|
1535
|
+
stderr,
|
|
1536
|
+
"guest must export plugin_alloc, plugin_free, and plugin_invoke_stream\n");
|
|
1537
|
+
return false;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
for (;;) {
|
|
1541
|
+
uint8_t length_bytes[4];
|
|
1542
|
+
const size_t prefix_read = fread(length_bytes, 1, sizeof(length_bytes), stdin);
|
|
1543
|
+
if (prefix_read == 0) {
|
|
1544
|
+
return feof(stdin);
|
|
1545
|
+
}
|
|
1546
|
+
if (prefix_read != sizeof(length_bytes)) {
|
|
1547
|
+
fprintf(stderr, "partial request length prefix\n");
|
|
1548
|
+
return false;
|
|
1549
|
+
}
|
|
1550
|
+
const uint32_t request_size =
|
|
1551
|
+
(uint32_t)length_bytes[0] |
|
|
1552
|
+
((uint32_t)length_bytes[1] << 8) |
|
|
1553
|
+
((uint32_t)length_bytes[2] << 16) |
|
|
1554
|
+
((uint32_t)length_bytes[3] << 24);
|
|
1555
|
+
|
|
1556
|
+
uint8_t *request_bytes = NULL;
|
|
1557
|
+
if (request_size > 0) {
|
|
1558
|
+
request_bytes = malloc(request_size);
|
|
1559
|
+
if (request_bytes == NULL) {
|
|
1560
|
+
fprintf(stderr, "failed to allocate host request buffer\n");
|
|
1561
|
+
return false;
|
|
1562
|
+
}
|
|
1563
|
+
if (!read_exact(stdin, request_bytes, request_size)) {
|
|
1564
|
+
free(request_bytes);
|
|
1565
|
+
fprintf(stderr, "failed to read complete request payload\n");
|
|
1566
|
+
return false;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
if (request_size >= 5 &&
|
|
1571
|
+
memcmp(request_bytes, HOST_CONTROL_MAGIC, sizeof(HOST_CONTROL_MAGIC)) == 0) {
|
|
1572
|
+
const uint8_t opcode = request_bytes[4];
|
|
1573
|
+
bool ok = true;
|
|
1574
|
+
uint8_t *response_bytes = NULL;
|
|
1575
|
+
uint32_t response_size = 0;
|
|
1576
|
+
|
|
1577
|
+
if (opcode == HOST_CONTROL_WRITE) {
|
|
1578
|
+
const uint32_t payload_size = request_size - 5;
|
|
1579
|
+
uint32_t guest_ptr = 0;
|
|
1580
|
+
ok = guest_malloc(executor, malloc_fn, payload_size, &guest_ptr) &&
|
|
1581
|
+
(payload_size == 0 || guest_ptr != 0) &&
|
|
1582
|
+
write_guest_memory(memory, guest_ptr, request_bytes + 5, payload_size);
|
|
1583
|
+
if (ok) {
|
|
1584
|
+
response_size = 4;
|
|
1585
|
+
response_bytes = malloc(response_size);
|
|
1586
|
+
if (response_bytes == NULL) {
|
|
1587
|
+
ok = false;
|
|
1588
|
+
} else {
|
|
1589
|
+
response_bytes[0] = (uint8_t)(guest_ptr & 0xFFU);
|
|
1590
|
+
response_bytes[1] = (uint8_t)((guest_ptr >> 8) & 0xFFU);
|
|
1591
|
+
response_bytes[2] = (uint8_t)((guest_ptr >> 16) & 0xFFU);
|
|
1592
|
+
response_bytes[3] = (uint8_t)((guest_ptr >> 24) & 0xFFU);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
} else if (opcode == HOST_CONTROL_READ) {
|
|
1596
|
+
if (request_size != 13) {
|
|
1597
|
+
ok = false;
|
|
1598
|
+
} else {
|
|
1599
|
+
const uint32_t guest_ptr = read_le_u32_bytes(request_bytes + 5);
|
|
1600
|
+
response_size = read_le_u32_bytes(request_bytes + 9);
|
|
1601
|
+
response_bytes = malloc(response_size);
|
|
1602
|
+
if (response_bytes == NULL && response_size > 0) {
|
|
1603
|
+
ok = false;
|
|
1604
|
+
} else {
|
|
1605
|
+
ok = read_guest_memory(memory, guest_ptr, response_bytes, response_size);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
} else if (opcode == HOST_CONTROL_FREE) {
|
|
1609
|
+
if (request_size != 9 && request_size != 13) {
|
|
1610
|
+
ok = false;
|
|
1611
|
+
} else {
|
|
1612
|
+
const uint32_t guest_ptr = read_le_u32_bytes(request_bytes + 5);
|
|
1613
|
+
const uint32_t guest_len =
|
|
1614
|
+
request_size >= 13 ? read_le_u32_bytes(request_bytes + 9) : 0;
|
|
1615
|
+
ok = guest_free(executor, free_fn, guest_ptr, guest_len);
|
|
1616
|
+
}
|
|
1617
|
+
} else {
|
|
1618
|
+
ok = false;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
free(request_bytes);
|
|
1622
|
+
if (!ok) {
|
|
1623
|
+
free(response_bytes);
|
|
1624
|
+
fprintf(stderr, "invalid WasmEdge host control request\n");
|
|
1625
|
+
return false;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
uint8_t response_length_bytes[4];
|
|
1629
|
+
response_length_bytes[0] = (uint8_t)(response_size & 0xFFU);
|
|
1630
|
+
response_length_bytes[1] = (uint8_t)((response_size >> 8) & 0xFFU);
|
|
1631
|
+
response_length_bytes[2] = (uint8_t)((response_size >> 16) & 0xFFU);
|
|
1632
|
+
response_length_bytes[3] = (uint8_t)((response_size >> 24) & 0xFFU);
|
|
1633
|
+
ok = write_all(stdout, response_length_bytes, sizeof(response_length_bytes)) &&
|
|
1634
|
+
write_all(stdout, response_bytes, response_size);
|
|
1635
|
+
free(response_bytes);
|
|
1636
|
+
if (!ok) {
|
|
1637
|
+
return false;
|
|
1638
|
+
}
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
uint32_t request_ptr = 0;
|
|
1643
|
+
uint32_t response_size_ptr = 0;
|
|
1644
|
+
uint32_t response_ptr = 0;
|
|
1645
|
+
uint32_t response_size = 0;
|
|
1646
|
+
bool ok = true;
|
|
1647
|
+
|
|
1648
|
+
if (request_size > 0) {
|
|
1649
|
+
ok = guest_malloc(executor, malloc_fn, request_size, &request_ptr) &&
|
|
1650
|
+
request_ptr != 0 &&
|
|
1651
|
+
write_guest_memory(memory, request_ptr, request_bytes, request_size);
|
|
1652
|
+
}
|
|
1653
|
+
if (ok) {
|
|
1654
|
+
ok = guest_malloc(executor, malloc_fn, 4, &response_size_ptr) &&
|
|
1655
|
+
response_size_ptr != 0;
|
|
1656
|
+
}
|
|
1657
|
+
if (ok) {
|
|
1658
|
+
const uint8_t zero_u32[4] = {0, 0, 0, 0};
|
|
1659
|
+
ok = write_guest_memory(memory, response_size_ptr, zero_u32, 4);
|
|
1660
|
+
}
|
|
1661
|
+
if (ok) {
|
|
1662
|
+
WasmEdge_Value params[3];
|
|
1663
|
+
WasmEdge_Value returns[1];
|
|
1664
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)request_ptr);
|
|
1665
|
+
params[1] = WasmEdge_ValueGenI32((int32_t)request_size);
|
|
1666
|
+
params[2] = WasmEdge_ValueGenI32((int32_t)response_size_ptr);
|
|
1667
|
+
ok = invoke_function(
|
|
1668
|
+
executor,
|
|
1669
|
+
invoke_fn,
|
|
1670
|
+
params,
|
|
1671
|
+
3,
|
|
1672
|
+
returns,
|
|
1673
|
+
1,
|
|
1674
|
+
"plugin_invoke_stream");
|
|
1675
|
+
if (ok) {
|
|
1676
|
+
response_ptr = (uint32_t)WasmEdge_ValueGetI32(returns[0]);
|
|
1677
|
+
ok = read_guest_u32(memory, response_size_ptr, &response_size);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
if (ok && response_size > 0 && response_ptr == 0) {
|
|
1682
|
+
fprintf(stderr, "plugin_invoke_stream returned null response pointer\n");
|
|
1683
|
+
ok = false;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
uint8_t *response_bytes = NULL;
|
|
1687
|
+
if (ok && response_size > 0) {
|
|
1688
|
+
response_bytes = malloc(response_size);
|
|
1689
|
+
if (response_bytes == NULL) {
|
|
1690
|
+
fprintf(stderr, "failed to allocate host response buffer\n");
|
|
1691
|
+
ok = false;
|
|
1692
|
+
} else {
|
|
1693
|
+
ok = read_guest_memory(memory, response_ptr, response_bytes, response_size);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
if (ok) {
|
|
1698
|
+
uint8_t response_length_bytes[4];
|
|
1699
|
+
response_length_bytes[0] = (uint8_t)(response_size & 0xFFU);
|
|
1700
|
+
response_length_bytes[1] = (uint8_t)((response_size >> 8) & 0xFFU);
|
|
1701
|
+
response_length_bytes[2] = (uint8_t)((response_size >> 16) & 0xFFU);
|
|
1702
|
+
response_length_bytes[3] = (uint8_t)((response_size >> 24) & 0xFFU);
|
|
1703
|
+
ok = write_all(stdout, response_length_bytes, sizeof(response_length_bytes)) &&
|
|
1704
|
+
write_all(stdout, response_bytes, response_size);
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
free(response_bytes);
|
|
1708
|
+
free(request_bytes);
|
|
1709
|
+
if (response_ptr != 0) {
|
|
1710
|
+
guest_free(executor, free_fn, response_ptr, response_size);
|
|
1711
|
+
}
|
|
1712
|
+
if (response_size_ptr != 0) {
|
|
1713
|
+
guest_free(executor, free_fn, response_size_ptr, 4);
|
|
1714
|
+
}
|
|
1715
|
+
if (request_ptr != 0) {
|
|
1716
|
+
guest_free(executor, free_fn, request_ptr, request_size);
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
if (!ok) {
|
|
1720
|
+
return false;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
static bool invoke_plugin_stream_once(
|
|
1726
|
+
WasmEdge_ExecutorContext *executor,
|
|
1727
|
+
WasmEdge_ModuleInstanceContext *module,
|
|
1728
|
+
RunnerContext *runner,
|
|
1729
|
+
const uint8_t *request_bytes,
|
|
1730
|
+
uint32_t request_size,
|
|
1731
|
+
uint8_t **response_bytes_out,
|
|
1732
|
+
uint32_t *response_size_out) {
|
|
1733
|
+
WasmEdge_MemoryInstanceContext *memory = resolve_guest_memory(module, runner);
|
|
1734
|
+
if (memory == NULL) {
|
|
1735
|
+
fprintf(stderr, "guest memory export/import was not found\n");
|
|
1736
|
+
return false;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
WasmEdge_FunctionInstanceContext *malloc_fn =
|
|
1740
|
+
find_function(module, "plugin_alloc");
|
|
1741
|
+
WasmEdge_FunctionInstanceContext *free_fn =
|
|
1742
|
+
find_function(module, "plugin_free");
|
|
1743
|
+
WasmEdge_FunctionInstanceContext *invoke_fn =
|
|
1744
|
+
find_function(module, "plugin_invoke_stream");
|
|
1745
|
+
if (malloc_fn == NULL || free_fn == NULL || invoke_fn == NULL) {
|
|
1746
|
+
fprintf(
|
|
1747
|
+
stderr,
|
|
1748
|
+
"guest must export plugin_alloc, plugin_free, and plugin_invoke_stream\n");
|
|
1749
|
+
return false;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
uint32_t request_ptr = 0;
|
|
1753
|
+
uint32_t response_size_ptr = 0;
|
|
1754
|
+
uint32_t response_ptr = 0;
|
|
1755
|
+
uint32_t response_size = 0;
|
|
1756
|
+
uint8_t *response_bytes = NULL;
|
|
1757
|
+
bool ok = true;
|
|
1758
|
+
|
|
1759
|
+
if (request_size > 0) {
|
|
1760
|
+
ok = guest_malloc(executor, malloc_fn, request_size, &request_ptr) &&
|
|
1761
|
+
request_ptr != 0 &&
|
|
1762
|
+
write_guest_memory(memory, request_ptr, request_bytes, request_size);
|
|
1763
|
+
}
|
|
1764
|
+
if (ok) {
|
|
1765
|
+
ok = guest_malloc(executor, malloc_fn, 4, &response_size_ptr) &&
|
|
1766
|
+
response_size_ptr != 0;
|
|
1767
|
+
}
|
|
1768
|
+
if (ok) {
|
|
1769
|
+
const uint8_t zero_u32[4] = {0, 0, 0, 0};
|
|
1770
|
+
ok = write_guest_memory(memory, response_size_ptr, zero_u32, 4);
|
|
1771
|
+
}
|
|
1772
|
+
if (ok) {
|
|
1773
|
+
WasmEdge_Value params[3];
|
|
1774
|
+
WasmEdge_Value returns[1];
|
|
1775
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)request_ptr);
|
|
1776
|
+
params[1] = WasmEdge_ValueGenI32((int32_t)request_size);
|
|
1777
|
+
params[2] = WasmEdge_ValueGenI32((int32_t)response_size_ptr);
|
|
1778
|
+
ok = invoke_function(
|
|
1779
|
+
executor,
|
|
1780
|
+
invoke_fn,
|
|
1781
|
+
params,
|
|
1782
|
+
3,
|
|
1783
|
+
returns,
|
|
1784
|
+
1,
|
|
1785
|
+
"plugin_invoke_stream");
|
|
1786
|
+
if (ok) {
|
|
1787
|
+
response_ptr = (uint32_t)WasmEdge_ValueGetI32(returns[0]);
|
|
1788
|
+
ok = read_guest_u32(memory, response_size_ptr, &response_size);
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
if (ok && response_size > 0 && response_ptr == 0) {
|
|
1792
|
+
fprintf(stderr, "plugin_invoke_stream returned null response pointer\n");
|
|
1793
|
+
ok = false;
|
|
1794
|
+
}
|
|
1795
|
+
if (ok && response_size > 0) {
|
|
1796
|
+
response_bytes = malloc(response_size);
|
|
1797
|
+
if (response_bytes == NULL) {
|
|
1798
|
+
fprintf(stderr, "failed to allocate host response buffer\n");
|
|
1799
|
+
ok = false;
|
|
1800
|
+
} else {
|
|
1801
|
+
ok = read_guest_memory(memory, response_ptr, response_bytes, response_size);
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
if (response_ptr != 0) {
|
|
1806
|
+
guest_free(executor, free_fn, response_ptr, response_size);
|
|
1807
|
+
}
|
|
1808
|
+
if (response_size_ptr != 0) {
|
|
1809
|
+
guest_free(executor, free_fn, response_size_ptr, 4);
|
|
1810
|
+
}
|
|
1811
|
+
if (request_ptr != 0) {
|
|
1812
|
+
guest_free(executor, free_fn, request_ptr, request_size);
|
|
1813
|
+
}
|
|
1814
|
+
if (!ok) {
|
|
1815
|
+
free(response_bytes);
|
|
1816
|
+
return false;
|
|
1817
|
+
}
|
|
1818
|
+
*response_bytes_out = response_bytes;
|
|
1819
|
+
*response_size_out = response_size;
|
|
1820
|
+
return true;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
static bool initialize_runtime_host_module(
|
|
1824
|
+
RuntimeHostModule *module,
|
|
1825
|
+
char *module_id,
|
|
1826
|
+
char *wasm_path,
|
|
1827
|
+
char *metadata_json,
|
|
1828
|
+
char **method_ids,
|
|
1829
|
+
size_t method_id_count) {
|
|
1830
|
+
runtime_host_module_init(module);
|
|
1831
|
+
module->module_id = module_id;
|
|
1832
|
+
module->wasm_path = wasm_path;
|
|
1833
|
+
module->metadata_json = metadata_json;
|
|
1834
|
+
module->method_ids = method_ids;
|
|
1835
|
+
module->method_id_count = method_id_count;
|
|
1836
|
+
|
|
1837
|
+
module->conf = WasmEdge_ConfigureCreate();
|
|
1838
|
+
if (module->conf == NULL) {
|
|
1839
|
+
goto fail;
|
|
1840
|
+
}
|
|
1841
|
+
WasmEdge_ConfigureAddProposal(module->conf, WasmEdge_Proposal_Threads);
|
|
1842
|
+
WasmEdge_ConfigureAddProposal(
|
|
1843
|
+
module->conf, WasmEdge_Proposal_ExceptionHandling);
|
|
1844
|
+
module->loader = WasmEdge_LoaderCreate(module->conf);
|
|
1845
|
+
module->validator = WasmEdge_ValidatorCreate(module->conf);
|
|
1846
|
+
module->executor = WasmEdge_ExecutorCreate(module->conf, NULL);
|
|
1847
|
+
module->store = WasmEdge_StoreCreate();
|
|
1848
|
+
if (module->loader == NULL || module->validator == NULL ||
|
|
1849
|
+
module->executor == NULL || module->store == NULL) {
|
|
1850
|
+
goto fail;
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
module->runner.conf = module->conf;
|
|
1854
|
+
module->runner.store = module->store;
|
|
1855
|
+
if (pthread_mutex_init(&module->runner.store_mutex, NULL) != 0) {
|
|
1856
|
+
goto fail;
|
|
1857
|
+
}
|
|
1858
|
+
module->store_mutex_initialized = true;
|
|
1859
|
+
|
|
1860
|
+
WasmEdge_Result res = WasmEdge_LoaderParseFromFile(
|
|
1861
|
+
module->loader,
|
|
1862
|
+
&module->ast,
|
|
1863
|
+
module->wasm_path);
|
|
1864
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
1865
|
+
goto fail;
|
|
1866
|
+
}
|
|
1867
|
+
module->runner.ast = module->ast;
|
|
1868
|
+
res = WasmEdge_ValidatorValidate(module->validator, module->ast);
|
|
1869
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
1870
|
+
goto fail;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
const char *wasi_args[2] = {module->wasm_path, "--serve-plugin-invoke"};
|
|
1874
|
+
WasmEdge_ModuleInstanceContext *wasi = WasmEdge_ModuleInstanceCreateWASI(
|
|
1875
|
+
wasi_args,
|
|
1876
|
+
2,
|
|
1877
|
+
NULL,
|
|
1878
|
+
0,
|
|
1879
|
+
NULL,
|
|
1880
|
+
0);
|
|
1881
|
+
if (wasi == NULL) {
|
|
1882
|
+
goto fail;
|
|
1883
|
+
}
|
|
1884
|
+
res = WasmEdge_ExecutorRegisterImport(module->executor, module->store, wasi);
|
|
1885
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
1886
|
+
goto fail;
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
WasmEdge_ModuleInstanceContext *env =
|
|
1890
|
+
WasmEdge_ModuleInstanceCreate(WasmEdge_StringCreateByCString("env"));
|
|
1891
|
+
if (env == NULL) {
|
|
1892
|
+
goto fail;
|
|
1893
|
+
}
|
|
1894
|
+
ImportedModuleConfig import_config;
|
|
1895
|
+
if (!read_imported_module_config(module->wasm_path, &import_config) ||
|
|
1896
|
+
!add_imported_env_memory_from_file(
|
|
1897
|
+
module->wasm_path,
|
|
1898
|
+
env,
|
|
1899
|
+
&module->runner.shared_memory)) {
|
|
1900
|
+
goto fail;
|
|
1901
|
+
}
|
|
1902
|
+
register_env_host_functions(
|
|
1903
|
+
env,
|
|
1904
|
+
&module->runner,
|
|
1905
|
+
import_config.receive_on_main_thread_param_len == 4 ? 4 : 5,
|
|
1906
|
+
import_config.notify_mailbox_postmessage_param_len == 3 ? 3 : 2);
|
|
1907
|
+
res = WasmEdge_ExecutorRegisterImport(module->executor, module->store, env);
|
|
1908
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
1909
|
+
goto fail;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
res = WasmEdge_ExecutorInstantiate(
|
|
1913
|
+
module->executor,
|
|
1914
|
+
&module->module,
|
|
1915
|
+
module->store,
|
|
1916
|
+
module->ast);
|
|
1917
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
1918
|
+
goto fail;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
if (!invoke_optional_module_init(module->executor, module->module, true)) {
|
|
1922
|
+
goto fail;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
return true;
|
|
1926
|
+
|
|
1927
|
+
fail:
|
|
1928
|
+
destroy_runtime_host_module(module);
|
|
1929
|
+
return false;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
static bool invoke_runtime_host_module(
|
|
1933
|
+
RuntimeHostModule *module,
|
|
1934
|
+
const uint8_t *request_bytes,
|
|
1935
|
+
uint32_t request_size,
|
|
1936
|
+
uint8_t **response_bytes_out,
|
|
1937
|
+
uint32_t *response_size_out) {
|
|
1938
|
+
if (module == NULL || module->executor == NULL || module->module == NULL) {
|
|
1939
|
+
return false;
|
|
1940
|
+
}
|
|
1941
|
+
return invoke_plugin_stream_once(
|
|
1942
|
+
module->executor,
|
|
1943
|
+
module->module,
|
|
1944
|
+
&module->runner,
|
|
1945
|
+
request_bytes,
|
|
1946
|
+
request_size,
|
|
1947
|
+
response_bytes_out,
|
|
1948
|
+
response_size_out);
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
static RuntimeHostModule *find_runtime_host_module(
|
|
1952
|
+
RuntimeHostState *state,
|
|
1953
|
+
const char *module_id,
|
|
1954
|
+
size_t *index_out) {
|
|
1955
|
+
for (size_t index = 0; index < state->module_count; ++index) {
|
|
1956
|
+
if (strcmp(state->modules[index].module_id, module_id) == 0) {
|
|
1957
|
+
if (index_out != NULL) {
|
|
1958
|
+
*index_out = index;
|
|
1959
|
+
}
|
|
1960
|
+
return &state->modules[index];
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
return NULL;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
static RuntimeHostRegion *find_runtime_host_region(
|
|
1967
|
+
RuntimeHostState *state,
|
|
1968
|
+
uint64_t region_id) {
|
|
1969
|
+
for (size_t index = 0; index < state->region_count; ++index) {
|
|
1970
|
+
if (state->regions[index].region_id == region_id) {
|
|
1971
|
+
return &state->regions[index];
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return NULL;
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
static RuntimeHostRow *find_runtime_host_row(
|
|
1978
|
+
RuntimeHostState *state,
|
|
1979
|
+
const char *schema_file_id,
|
|
1980
|
+
uint64_t row_id) {
|
|
1981
|
+
for (size_t index = 0; index < state->row_count; ++index) {
|
|
1982
|
+
RuntimeHostRow *row = &state->rows[index];
|
|
1983
|
+
if (row->row_id == row_id &&
|
|
1984
|
+
strcmp(row->schema_file_id, schema_file_id) == 0) {
|
|
1985
|
+
return row;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
return NULL;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
static uint64_t next_runtime_host_row_id_for_schema(
|
|
1992
|
+
RuntimeHostState *state,
|
|
1993
|
+
const char *schema_file_id) {
|
|
1994
|
+
uint64_t next_row_id = 1;
|
|
1995
|
+
for (size_t index = 0; index < state->row_count; ++index) {
|
|
1996
|
+
RuntimeHostRow *row = &state->rows[index];
|
|
1997
|
+
if (strcmp(row->schema_file_id, schema_file_id) != 0) {
|
|
1998
|
+
continue;
|
|
1999
|
+
}
|
|
2000
|
+
if (row->row_id >= next_row_id) {
|
|
2001
|
+
next_row_id = row->row_id + 1;
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
return next_row_id;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
static bool append_runtime_host_row_query_result_json(
|
|
2008
|
+
JsonBuffer *buffer,
|
|
2009
|
+
RuntimeHostState *state,
|
|
2010
|
+
const char *schema_file_id_filter) {
|
|
2011
|
+
if (!json_buffer_append_cstr(
|
|
2012
|
+
buffer,
|
|
2013
|
+
"{\"columns\":[\"schemaFileId\",\"rowId\"],\"rows\":[")) {
|
|
2014
|
+
return false;
|
|
2015
|
+
}
|
|
2016
|
+
uint64_t row_count = 0;
|
|
2017
|
+
bool first = true;
|
|
2018
|
+
for (size_t index = 0; index < state->row_count; ++index) {
|
|
2019
|
+
RuntimeHostRow *row = &state->rows[index];
|
|
2020
|
+
if (schema_file_id_filter != NULL &&
|
|
2021
|
+
strcmp(row->schema_file_id, schema_file_id_filter) != 0) {
|
|
2022
|
+
continue;
|
|
2023
|
+
}
|
|
2024
|
+
if (!first && !json_buffer_append_char(buffer, ',')) {
|
|
2025
|
+
return false;
|
|
2026
|
+
}
|
|
2027
|
+
first = false;
|
|
2028
|
+
if (!json_buffer_append_char(buffer, '[') ||
|
|
2029
|
+
!json_buffer_append_json_string(buffer, row->schema_file_id) ||
|
|
2030
|
+
!json_buffer_append_char(buffer, ',') ||
|
|
2031
|
+
!json_buffer_append_u64(buffer, row->row_id) ||
|
|
2032
|
+
!json_buffer_append_char(buffer, ']')) {
|
|
2033
|
+
return false;
|
|
2034
|
+
}
|
|
2035
|
+
row_count += 1;
|
|
2036
|
+
}
|
|
2037
|
+
return json_buffer_append_cstr(buffer, "],\"rowCount\":") &&
|
|
2038
|
+
json_buffer_append_u64(buffer, row_count) &&
|
|
2039
|
+
json_buffer_append_char(buffer, '}');
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
static bool append_runtime_host_module_json(
|
|
2043
|
+
JsonBuffer *buffer,
|
|
2044
|
+
const RuntimeHostModule *module) {
|
|
2045
|
+
if (!json_buffer_append_cstr(buffer, "{\"moduleId\":") ||
|
|
2046
|
+
!json_buffer_append_json_string(buffer, module->module_id) ||
|
|
2047
|
+
!json_buffer_append_cstr(buffer, ",\"metadata\":") ||
|
|
2048
|
+
!json_buffer_append_cstr(
|
|
2049
|
+
buffer,
|
|
2050
|
+
module->metadata_json != NULL ? module->metadata_json : "null") ||
|
|
2051
|
+
!json_buffer_append_cstr(buffer, ",\"methodIds\":[")) {
|
|
2052
|
+
return false;
|
|
2053
|
+
}
|
|
2054
|
+
for (size_t index = 0; index < module->method_id_count; ++index) {
|
|
2055
|
+
if ((index > 0 && !json_buffer_append_char(buffer, ',')) ||
|
|
2056
|
+
!json_buffer_append_json_string(buffer, module->method_ids[index])) {
|
|
2057
|
+
return false;
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
return json_buffer_append_cstr(buffer, "]}");
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
static bool append_runtime_host_row_json(
|
|
2064
|
+
JsonBuffer *buffer,
|
|
2065
|
+
const RuntimeHostRow *row) {
|
|
2066
|
+
return json_buffer_append_cstr(buffer, "{\"handle\":{\"schemaFileId\":") &&
|
|
2067
|
+
json_buffer_append_json_string(buffer, row->schema_file_id) &&
|
|
2068
|
+
json_buffer_append_cstr(buffer, ",\"rowId\":") &&
|
|
2069
|
+
json_buffer_append_u64(buffer, row->row_id) &&
|
|
2070
|
+
json_buffer_append_cstr(buffer, "},\"payload\":") &&
|
|
2071
|
+
json_buffer_append_cstr(
|
|
2072
|
+
buffer,
|
|
2073
|
+
row->payload_json != NULL ? row->payload_json : "null") &&
|
|
2074
|
+
json_buffer_append_char(buffer, '}');
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
static bool append_runtime_host_region_descriptor_json(
|
|
2078
|
+
JsonBuffer *buffer,
|
|
2079
|
+
const RuntimeHostRegion *region) {
|
|
2080
|
+
return json_buffer_append_cstr(buffer, "{\"regionId\":") &&
|
|
2081
|
+
json_buffer_append_u64(buffer, region->region_id) &&
|
|
2082
|
+
json_buffer_append_cstr(buffer, ",\"layoutId\":") &&
|
|
2083
|
+
json_buffer_append_json_string(buffer, region->layout_id) &&
|
|
2084
|
+
json_buffer_append_cstr(buffer, ",\"recordByteLength\":") &&
|
|
2085
|
+
json_buffer_append_u32(buffer, region->record_byte_length) &&
|
|
2086
|
+
json_buffer_append_cstr(buffer, ",\"alignment\":") &&
|
|
2087
|
+
json_buffer_append_u32(buffer, region->alignment) &&
|
|
2088
|
+
json_buffer_append_cstr(buffer, ",\"recordCount\":") &&
|
|
2089
|
+
json_buffer_append_u64(buffer, (uint64_t)region->record_count) &&
|
|
2090
|
+
json_buffer_append_char(buffer, '}');
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
static bool append_runtime_host_region_record_json(
|
|
2094
|
+
JsonBuffer *buffer,
|
|
2095
|
+
const RuntimeHostRegion *region,
|
|
2096
|
+
uint32_t record_index) {
|
|
2097
|
+
if (!json_buffer_append_cstr(buffer, "{\"regionId\":") ||
|
|
2098
|
+
!json_buffer_append_u64(buffer, region->region_id) ||
|
|
2099
|
+
!json_buffer_append_cstr(buffer, ",\"recordIndex\":") ||
|
|
2100
|
+
!json_buffer_append_u32(buffer, record_index) ||
|
|
2101
|
+
!json_buffer_append_cstr(buffer, ",\"layoutId\":") ||
|
|
2102
|
+
!json_buffer_append_json_string(buffer, region->layout_id) ||
|
|
2103
|
+
!json_buffer_append_cstr(buffer, ",\"recordByteLength\":") ||
|
|
2104
|
+
!json_buffer_append_u32(buffer, region->record_byte_length) ||
|
|
2105
|
+
!json_buffer_append_cstr(buffer, ",\"alignment\":") ||
|
|
2106
|
+
!json_buffer_append_u32(buffer, region->alignment) ||
|
|
2107
|
+
!json_buffer_append_cstr(buffer, ",\"byteLength\":") ||
|
|
2108
|
+
!json_buffer_append_u32(buffer, region->record_byte_length) ||
|
|
2109
|
+
!json_buffer_append_cstr(buffer, ",\"bytes\":[")) {
|
|
2110
|
+
return false;
|
|
2111
|
+
}
|
|
2112
|
+
const uint8_t *record = region->records[record_index];
|
|
2113
|
+
for (uint32_t index = 0; index < region->record_byte_length; ++index) {
|
|
2114
|
+
if (index > 0 && !json_buffer_append_char(buffer, ',')) {
|
|
2115
|
+
return false;
|
|
2116
|
+
}
|
|
2117
|
+
if (!json_buffer_append_u32(buffer, record[index])) {
|
|
2118
|
+
return false;
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
return json_buffer_append_cstr(buffer, "]}");
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
static bool parse_json_string_field(
|
|
2125
|
+
const char *json,
|
|
2126
|
+
size_t length,
|
|
2127
|
+
const char *field_name,
|
|
2128
|
+
char **value_out) {
|
|
2129
|
+
JsonSlice slice;
|
|
2130
|
+
return find_json_object_field(json, length, field_name, &slice) &&
|
|
2131
|
+
duplicate_json_string_value(slice, value_out);
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
static bool parse_json_optional_string_field(
|
|
2135
|
+
const char *json,
|
|
2136
|
+
size_t length,
|
|
2137
|
+
const char *field_name,
|
|
2138
|
+
char **value_out) {
|
|
2139
|
+
JsonSlice slice;
|
|
2140
|
+
if (!find_json_object_field(json, length, field_name, &slice)) {
|
|
2141
|
+
*value_out = NULL;
|
|
2142
|
+
return true;
|
|
2143
|
+
}
|
|
2144
|
+
if (json_slice_is_null(slice)) {
|
|
2145
|
+
*value_out = NULL;
|
|
2146
|
+
return true;
|
|
2147
|
+
}
|
|
2148
|
+
return duplicate_json_string_value(slice, value_out);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
static bool parse_json_string_array_field(
|
|
2152
|
+
const char *json,
|
|
2153
|
+
size_t length,
|
|
2154
|
+
const char *field_name,
|
|
2155
|
+
char ***values_out,
|
|
2156
|
+
size_t *count_out) {
|
|
2157
|
+
JsonSlice slice;
|
|
2158
|
+
if (!find_json_object_field(json, length, field_name, &slice)) {
|
|
2159
|
+
*values_out = NULL;
|
|
2160
|
+
*count_out = 0;
|
|
2161
|
+
return true;
|
|
2162
|
+
}
|
|
2163
|
+
size_t offset = 0;
|
|
2164
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2165
|
+
if (offset >= slice.length || slice.data[offset] != '[') {
|
|
2166
|
+
return false;
|
|
2167
|
+
}
|
|
2168
|
+
offset += 1;
|
|
2169
|
+
char **values = NULL;
|
|
2170
|
+
size_t value_count = 0;
|
|
2171
|
+
size_t value_capacity = 0;
|
|
2172
|
+
for (;;) {
|
|
2173
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2174
|
+
if (offset >= slice.length) {
|
|
2175
|
+
break;
|
|
2176
|
+
}
|
|
2177
|
+
if (slice.data[offset] == ']') {
|
|
2178
|
+
offset += 1;
|
|
2179
|
+
*values_out = values;
|
|
2180
|
+
*count_out = value_count;
|
|
2181
|
+
return true;
|
|
2182
|
+
}
|
|
2183
|
+
const size_t value_start = offset;
|
|
2184
|
+
if (!consume_json_string(slice.data, slice.length, &offset) ||
|
|
2185
|
+
!ensure_runtime_host_capacity(
|
|
2186
|
+
(void **)&values,
|
|
2187
|
+
&value_capacity,
|
|
2188
|
+
value_count,
|
|
2189
|
+
sizeof(*values)) ||
|
|
2190
|
+
!duplicate_json_string_value(
|
|
2191
|
+
(JsonSlice){
|
|
2192
|
+
.data = slice.data + value_start,
|
|
2193
|
+
.length = offset - value_start,
|
|
2194
|
+
},
|
|
2195
|
+
&values[value_count])) {
|
|
2196
|
+
break;
|
|
2197
|
+
}
|
|
2198
|
+
value_count += 1;
|
|
2199
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2200
|
+
if (offset >= slice.length) {
|
|
2201
|
+
break;
|
|
2202
|
+
}
|
|
2203
|
+
if (slice.data[offset] == ']') {
|
|
2204
|
+
offset += 1;
|
|
2205
|
+
*values_out = values;
|
|
2206
|
+
*count_out = value_count;
|
|
2207
|
+
return true;
|
|
2208
|
+
}
|
|
2209
|
+
if (slice.data[offset] != ',') {
|
|
2210
|
+
break;
|
|
2211
|
+
}
|
|
2212
|
+
offset += 1;
|
|
2213
|
+
}
|
|
2214
|
+
for (size_t index = 0; index < value_count; ++index) {
|
|
2215
|
+
free(values[index]);
|
|
2216
|
+
}
|
|
2217
|
+
free(values);
|
|
2218
|
+
return false;
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
static bool parse_json_u64_field(
|
|
2222
|
+
const char *json,
|
|
2223
|
+
size_t length,
|
|
2224
|
+
const char *field_name,
|
|
2225
|
+
uint64_t *value_out) {
|
|
2226
|
+
JsonSlice slice;
|
|
2227
|
+
return find_json_object_field(json, length, field_name, &slice) &&
|
|
2228
|
+
parse_json_u64(slice, value_out);
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
static bool duplicate_json_field_raw(
|
|
2232
|
+
const char *json,
|
|
2233
|
+
size_t length,
|
|
2234
|
+
const char *field_name,
|
|
2235
|
+
char **value_out,
|
|
2236
|
+
const char *fallback_json) {
|
|
2237
|
+
JsonSlice slice;
|
|
2238
|
+
if (!find_json_object_field(json, length, field_name, &slice)) {
|
|
2239
|
+
*value_out = strdup(fallback_json);
|
|
2240
|
+
return *value_out != NULL;
|
|
2241
|
+
}
|
|
2242
|
+
return duplicate_json_slice(slice, value_out);
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
static bool parse_record_bytes_array(
|
|
2246
|
+
JsonSlice slice,
|
|
2247
|
+
uint32_t record_byte_length,
|
|
2248
|
+
uint8_t **record_out) {
|
|
2249
|
+
uint8_t *record = calloc(record_byte_length, 1);
|
|
2250
|
+
if (record == NULL) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
if (json_slice_is_null(slice)) {
|
|
2254
|
+
*record_out = record;
|
|
2255
|
+
return true;
|
|
2256
|
+
}
|
|
2257
|
+
size_t offset = 0;
|
|
2258
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2259
|
+
if (offset >= slice.length || slice.data[offset] != '[') {
|
|
2260
|
+
free(record);
|
|
2261
|
+
return false;
|
|
2262
|
+
}
|
|
2263
|
+
offset += 1;
|
|
2264
|
+
size_t write_index = 0;
|
|
2265
|
+
for (;;) {
|
|
2266
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2267
|
+
if (offset >= slice.length) {
|
|
2268
|
+
free(record);
|
|
2269
|
+
return false;
|
|
2270
|
+
}
|
|
2271
|
+
if (slice.data[offset] == ']') {
|
|
2272
|
+
offset += 1;
|
|
2273
|
+
*record_out = record;
|
|
2274
|
+
return true;
|
|
2275
|
+
}
|
|
2276
|
+
size_t value_start = offset;
|
|
2277
|
+
if (!consume_json_value(slice.data, slice.length, &offset)) {
|
|
2278
|
+
free(record);
|
|
2279
|
+
return false;
|
|
2280
|
+
}
|
|
2281
|
+
uint64_t value = 0;
|
|
2282
|
+
JsonSlice value_slice = {
|
|
2283
|
+
.data = slice.data + value_start,
|
|
2284
|
+
.length = offset - value_start,
|
|
2285
|
+
};
|
|
2286
|
+
if (!parse_json_u64(value_slice, &value) || value > 255 ||
|
|
2287
|
+
write_index >= record_byte_length) {
|
|
2288
|
+
free(record);
|
|
2289
|
+
return false;
|
|
2290
|
+
}
|
|
2291
|
+
record[write_index++] = (uint8_t)value;
|
|
2292
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2293
|
+
if (offset >= slice.length) {
|
|
2294
|
+
free(record);
|
|
2295
|
+
return false;
|
|
2296
|
+
}
|
|
2297
|
+
if (slice.data[offset] == ']') {
|
|
2298
|
+
offset += 1;
|
|
2299
|
+
*record_out = record;
|
|
2300
|
+
return true;
|
|
2301
|
+
}
|
|
2302
|
+
if (slice.data[offset] != ',') {
|
|
2303
|
+
free(record);
|
|
2304
|
+
return false;
|
|
2305
|
+
}
|
|
2306
|
+
offset += 1;
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
static bool parse_initial_records_field(
|
|
2311
|
+
const char *json,
|
|
2312
|
+
size_t length,
|
|
2313
|
+
uint32_t record_byte_length,
|
|
2314
|
+
uint8_t ***records_out,
|
|
2315
|
+
size_t *record_count_out) {
|
|
2316
|
+
JsonSlice slice;
|
|
2317
|
+
if (!find_json_object_field(json, length, "initialRecords", &slice)) {
|
|
2318
|
+
*records_out = NULL;
|
|
2319
|
+
*record_count_out = 0;
|
|
2320
|
+
return true;
|
|
2321
|
+
}
|
|
2322
|
+
size_t offset = 0;
|
|
2323
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2324
|
+
if (offset >= slice.length || slice.data[offset] != '[') {
|
|
2325
|
+
return false;
|
|
2326
|
+
}
|
|
2327
|
+
offset += 1;
|
|
2328
|
+
uint8_t **records = NULL;
|
|
2329
|
+
size_t record_count = 0;
|
|
2330
|
+
size_t record_capacity = 0;
|
|
2331
|
+
for (;;) {
|
|
2332
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2333
|
+
if (offset >= slice.length) {
|
|
2334
|
+
break;
|
|
2335
|
+
}
|
|
2336
|
+
if (slice.data[offset] == ']') {
|
|
2337
|
+
offset += 1;
|
|
2338
|
+
*records_out = records;
|
|
2339
|
+
*record_count_out = record_count;
|
|
2340
|
+
return true;
|
|
2341
|
+
}
|
|
2342
|
+
const size_t value_start = offset;
|
|
2343
|
+
if (!consume_json_value(slice.data, slice.length, &offset) ||
|
|
2344
|
+
!ensure_runtime_host_capacity(
|
|
2345
|
+
(void **)&records,
|
|
2346
|
+
&record_capacity,
|
|
2347
|
+
record_count,
|
|
2348
|
+
sizeof(*records))) {
|
|
2349
|
+
break;
|
|
2350
|
+
}
|
|
2351
|
+
JsonSlice value_slice = {
|
|
2352
|
+
.data = slice.data + value_start,
|
|
2353
|
+
.length = offset - value_start,
|
|
2354
|
+
};
|
|
2355
|
+
if (!parse_record_bytes_array(
|
|
2356
|
+
value_slice,
|
|
2357
|
+
record_byte_length,
|
|
2358
|
+
&records[record_count])) {
|
|
2359
|
+
break;
|
|
2360
|
+
}
|
|
2361
|
+
record_count += 1;
|
|
2362
|
+
skip_json_whitespace(slice.data, slice.length, &offset);
|
|
2363
|
+
if (offset < slice.length && slice.data[offset] == ',') {
|
|
2364
|
+
offset += 1;
|
|
2365
|
+
continue;
|
|
2366
|
+
}
|
|
2367
|
+
if (offset < slice.length && slice.data[offset] == ']') {
|
|
2368
|
+
offset += 1;
|
|
2369
|
+
*records_out = records;
|
|
2370
|
+
*record_count_out = record_count;
|
|
2371
|
+
return true;
|
|
2372
|
+
}
|
|
2373
|
+
break;
|
|
2374
|
+
}
|
|
2375
|
+
for (size_t index = 0; index < record_count; ++index) {
|
|
2376
|
+
free(records[index]);
|
|
2377
|
+
}
|
|
2378
|
+
free(records);
|
|
2379
|
+
return false;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
static bool respond_with_json_buffer(
|
|
2383
|
+
JsonBuffer *buffer,
|
|
2384
|
+
uint8_t **response_bytes_out,
|
|
2385
|
+
uint32_t *response_size_out) {
|
|
2386
|
+
*response_bytes_out = json_buffer_detach(buffer, response_size_out);
|
|
2387
|
+
return *response_bytes_out != NULL || *response_size_out == 0;
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
static bool dispatch_runtime_host_request(
|
|
2391
|
+
RuntimeHostState *state,
|
|
2392
|
+
uint8_t opcode,
|
|
2393
|
+
const uint8_t *payload_bytes,
|
|
2394
|
+
uint32_t payload_size,
|
|
2395
|
+
uint8_t **response_bytes_out,
|
|
2396
|
+
uint32_t *response_size_out) {
|
|
2397
|
+
const char *json = (const char *)payload_bytes;
|
|
2398
|
+
const size_t json_length = payload_size;
|
|
2399
|
+
JsonBuffer response;
|
|
2400
|
+
json_buffer_init(&response);
|
|
2401
|
+
|
|
2402
|
+
if (opcode == HOST_CONTROL_LIST_MODULES) {
|
|
2403
|
+
if (!json_buffer_append_char(&response, '[')) {
|
|
2404
|
+
goto fail;
|
|
2405
|
+
}
|
|
2406
|
+
for (size_t index = 0; index < state->module_count; ++index) {
|
|
2407
|
+
if (index > 0 && !json_buffer_append_char(&response, ',')) {
|
|
2408
|
+
goto fail;
|
|
2409
|
+
}
|
|
2410
|
+
if (!append_runtime_host_module_json(&response, &state->modules[index])) {
|
|
2411
|
+
goto fail;
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
if (!json_buffer_append_char(&response, ']')) {
|
|
2415
|
+
goto fail;
|
|
2416
|
+
}
|
|
2417
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
if (opcode == HOST_CONTROL_INSTALL_MODULE) {
|
|
2421
|
+
char *module_id = NULL;
|
|
2422
|
+
char *wasm_path = NULL;
|
|
2423
|
+
char *metadata_json = NULL;
|
|
2424
|
+
char **method_ids = NULL;
|
|
2425
|
+
size_t method_id_count = 0;
|
|
2426
|
+
if (!parse_json_string_field(json, json_length, "moduleId", &module_id) ||
|
|
2427
|
+
!parse_json_string_field(json, json_length, "wasmPath", &wasm_path) ||
|
|
2428
|
+
!parse_json_string_array_field(
|
|
2429
|
+
json,
|
|
2430
|
+
json_length,
|
|
2431
|
+
"methodIds",
|
|
2432
|
+
&method_ids,
|
|
2433
|
+
&method_id_count) ||
|
|
2434
|
+
!duplicate_json_field_raw(
|
|
2435
|
+
json,
|
|
2436
|
+
json_length,
|
|
2437
|
+
"metadata",
|
|
2438
|
+
&metadata_json,
|
|
2439
|
+
"null")) {
|
|
2440
|
+
free(module_id);
|
|
2441
|
+
free(wasm_path);
|
|
2442
|
+
free(metadata_json);
|
|
2443
|
+
for (size_t index = 0; index < method_id_count; ++index) {
|
|
2444
|
+
free(method_ids[index]);
|
|
2445
|
+
}
|
|
2446
|
+
free(method_ids);
|
|
2447
|
+
goto fail;
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
size_t module_index = 0;
|
|
2451
|
+
const bool creating_module =
|
|
2452
|
+
find_runtime_host_module(state, module_id, &module_index) == NULL;
|
|
2453
|
+
RuntimeHostModule *module =
|
|
2454
|
+
creating_module ? NULL : &state->modules[module_index];
|
|
2455
|
+
if (creating_module) {
|
|
2456
|
+
if (!ensure_runtime_host_capacity(
|
|
2457
|
+
(void **)&state->modules,
|
|
2458
|
+
&state->module_capacity,
|
|
2459
|
+
state->module_count,
|
|
2460
|
+
sizeof(*state->modules))) {
|
|
2461
|
+
free(module_id);
|
|
2462
|
+
free(wasm_path);
|
|
2463
|
+
free(metadata_json);
|
|
2464
|
+
for (size_t index = 0; index < method_id_count; ++index) {
|
|
2465
|
+
free(method_ids[index]);
|
|
2466
|
+
}
|
|
2467
|
+
free(method_ids);
|
|
2468
|
+
goto fail;
|
|
2469
|
+
}
|
|
2470
|
+
module = &state->modules[state->module_count++];
|
|
2471
|
+
runtime_host_module_init(module);
|
|
2472
|
+
} else {
|
|
2473
|
+
destroy_runtime_host_module(module);
|
|
2474
|
+
runtime_host_module_init(module);
|
|
2475
|
+
}
|
|
2476
|
+
if (!initialize_runtime_host_module(
|
|
2477
|
+
module,
|
|
2478
|
+
module_id,
|
|
2479
|
+
wasm_path,
|
|
2480
|
+
metadata_json,
|
|
2481
|
+
method_ids,
|
|
2482
|
+
method_id_count)) {
|
|
2483
|
+
if (creating_module) {
|
|
2484
|
+
state->module_count -= 1;
|
|
2485
|
+
}
|
|
2486
|
+
goto fail;
|
|
2487
|
+
}
|
|
2488
|
+
if (!append_runtime_host_module_json(&response, module)) {
|
|
2489
|
+
goto fail;
|
|
2490
|
+
}
|
|
2491
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
if (opcode == HOST_CONTROL_UNLOAD_MODULE) {
|
|
2495
|
+
char *module_id = NULL;
|
|
2496
|
+
bool unloaded = false;
|
|
2497
|
+
if (!parse_json_string_field(json, json_length, "moduleId", &module_id)) {
|
|
2498
|
+
free(module_id);
|
|
2499
|
+
goto fail;
|
|
2500
|
+
}
|
|
2501
|
+
size_t module_index = 0;
|
|
2502
|
+
RuntimeHostModule *module =
|
|
2503
|
+
find_runtime_host_module(state, module_id, &module_index);
|
|
2504
|
+
free(module_id);
|
|
2505
|
+
if (module != NULL) {
|
|
2506
|
+
destroy_runtime_host_module(module);
|
|
2507
|
+
memmove(
|
|
2508
|
+
&state->modules[module_index],
|
|
2509
|
+
&state->modules[module_index + 1],
|
|
2510
|
+
(state->module_count - module_index - 1) * sizeof(*state->modules));
|
|
2511
|
+
state->module_count -= 1;
|
|
2512
|
+
unloaded = true;
|
|
2513
|
+
}
|
|
2514
|
+
if (!json_buffer_append_cstr(&response, unloaded ? "true" : "false")) {
|
|
2515
|
+
goto fail;
|
|
2516
|
+
}
|
|
2517
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
if (opcode == HOST_CONTROL_INVOKE_MODULE) {
|
|
2521
|
+
if (payload_size < 4) {
|
|
2522
|
+
goto fail;
|
|
2523
|
+
}
|
|
2524
|
+
const uint32_t module_id_length = read_le_u32_bytes(payload_bytes);
|
|
2525
|
+
if ((uint64_t)payload_size < 4ULL + (uint64_t)module_id_length) {
|
|
2526
|
+
goto fail;
|
|
2527
|
+
}
|
|
2528
|
+
char *module_id = malloc((size_t)module_id_length + 1);
|
|
2529
|
+
if (module_id == NULL) {
|
|
2530
|
+
goto fail;
|
|
2531
|
+
}
|
|
2532
|
+
memcpy(module_id, payload_bytes + 4, module_id_length);
|
|
2533
|
+
module_id[module_id_length] = '\0';
|
|
2534
|
+
RuntimeHostModule *module =
|
|
2535
|
+
find_runtime_host_module(state, module_id, NULL);
|
|
2536
|
+
free(module_id);
|
|
2537
|
+
if (module == NULL) {
|
|
2538
|
+
goto fail;
|
|
2539
|
+
}
|
|
2540
|
+
return invoke_runtime_host_module(
|
|
2541
|
+
module,
|
|
2542
|
+
payload_bytes + 4 + module_id_length,
|
|
2543
|
+
payload_size - 4 - module_id_length,
|
|
2544
|
+
response_bytes_out,
|
|
2545
|
+
response_size_out);
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
if (opcode == HOST_CONTROL_APPEND_ROW) {
|
|
2549
|
+
char *schema_file_id = NULL;
|
|
2550
|
+
char *payload_json = NULL;
|
|
2551
|
+
if (!parse_json_string_field(
|
|
2552
|
+
json,
|
|
2553
|
+
json_length,
|
|
2554
|
+
"schemaFileId",
|
|
2555
|
+
&schema_file_id) ||
|
|
2556
|
+
!duplicate_json_field_raw(
|
|
2557
|
+
json,
|
|
2558
|
+
json_length,
|
|
2559
|
+
"payload",
|
|
2560
|
+
&payload_json,
|
|
2561
|
+
"null")) {
|
|
2562
|
+
free(schema_file_id);
|
|
2563
|
+
free(payload_json);
|
|
2564
|
+
goto fail;
|
|
2565
|
+
}
|
|
2566
|
+
if (!ensure_runtime_host_capacity(
|
|
2567
|
+
(void **)&state->rows,
|
|
2568
|
+
&state->row_capacity,
|
|
2569
|
+
state->row_count,
|
|
2570
|
+
sizeof(*state->rows))) {
|
|
2571
|
+
free(schema_file_id);
|
|
2572
|
+
free(payload_json);
|
|
2573
|
+
goto fail;
|
|
2574
|
+
}
|
|
2575
|
+
RuntimeHostRow *row = &state->rows[state->row_count++];
|
|
2576
|
+
row->schema_file_id = schema_file_id;
|
|
2577
|
+
row->row_id = next_runtime_host_row_id_for_schema(state, schema_file_id);
|
|
2578
|
+
row->payload_json = payload_json;
|
|
2579
|
+
if (!json_buffer_append_cstr(&response, "{\"schemaFileId\":") ||
|
|
2580
|
+
!json_buffer_append_json_string(&response, row->schema_file_id) ||
|
|
2581
|
+
!json_buffer_append_cstr(&response, ",\"rowId\":") ||
|
|
2582
|
+
!json_buffer_append_u64(&response, row->row_id) ||
|
|
2583
|
+
!json_buffer_append_char(&response, '}')) {
|
|
2584
|
+
goto fail;
|
|
2585
|
+
}
|
|
2586
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
if (opcode == HOST_CONTROL_LIST_ROWS) {
|
|
2590
|
+
char *schema_file_id = NULL;
|
|
2591
|
+
if (!parse_json_optional_string_field(
|
|
2592
|
+
json,
|
|
2593
|
+
json_length,
|
|
2594
|
+
"schemaFileId",
|
|
2595
|
+
&schema_file_id)) {
|
|
2596
|
+
free(schema_file_id);
|
|
2597
|
+
goto fail;
|
|
2598
|
+
}
|
|
2599
|
+
if (!json_buffer_append_char(&response, '[')) {
|
|
2600
|
+
free(schema_file_id);
|
|
2601
|
+
goto fail;
|
|
2602
|
+
}
|
|
2603
|
+
bool first = true;
|
|
2604
|
+
for (size_t index = 0; index < state->row_count; ++index) {
|
|
2605
|
+
RuntimeHostRow *row = &state->rows[index];
|
|
2606
|
+
if (schema_file_id != NULL &&
|
|
2607
|
+
strcmp(row->schema_file_id, schema_file_id) != 0) {
|
|
2608
|
+
continue;
|
|
2609
|
+
}
|
|
2610
|
+
if (!first && !json_buffer_append_char(&response, ',')) {
|
|
2611
|
+
free(schema_file_id);
|
|
2612
|
+
goto fail;
|
|
2613
|
+
}
|
|
2614
|
+
first = false;
|
|
2615
|
+
if (!append_runtime_host_row_json(&response, row)) {
|
|
2616
|
+
free(schema_file_id);
|
|
2617
|
+
goto fail;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
free(schema_file_id);
|
|
2621
|
+
if (!json_buffer_append_char(&response, ']')) {
|
|
2622
|
+
goto fail;
|
|
2623
|
+
}
|
|
2624
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
if (opcode == HOST_CONTROL_RESOLVE_ROW) {
|
|
2628
|
+
char *schema_file_id = NULL;
|
|
2629
|
+
uint64_t row_id = 0;
|
|
2630
|
+
if (!parse_json_string_field(json, json_length, "schemaFileId", &schema_file_id) ||
|
|
2631
|
+
!parse_json_u64_field(json, json_length, "rowId", &row_id)) {
|
|
2632
|
+
free(schema_file_id);
|
|
2633
|
+
goto fail;
|
|
2634
|
+
}
|
|
2635
|
+
RuntimeHostRow *row = find_runtime_host_row(state, schema_file_id, row_id);
|
|
2636
|
+
free(schema_file_id);
|
|
2637
|
+
if (row == NULL) {
|
|
2638
|
+
if (!json_buffer_append_cstr(&response, "null")) {
|
|
2639
|
+
goto fail;
|
|
2640
|
+
}
|
|
2641
|
+
} else if (!append_runtime_host_row_json(&response, row)) {
|
|
2642
|
+
goto fail;
|
|
2643
|
+
}
|
|
2644
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
if (opcode == HOST_CONTROL_QUERY_ROWS) {
|
|
2648
|
+
char *sql = NULL;
|
|
2649
|
+
char *schema_file_id_filter = NULL;
|
|
2650
|
+
if (!parse_json_string_field(json, json_length, "sql", &sql)) {
|
|
2651
|
+
free(sql);
|
|
2652
|
+
goto fail;
|
|
2653
|
+
}
|
|
2654
|
+
const char *runtime_rows_query_prefix =
|
|
2655
|
+
"SELECT schemaFileId, rowId FROM RuntimeHostRow";
|
|
2656
|
+
if (strstr(sql, runtime_rows_query_prefix) != sql) {
|
|
2657
|
+
free(sql);
|
|
2658
|
+
goto fail;
|
|
2659
|
+
}
|
|
2660
|
+
const char *where_prefix = "WHERE schemaFileId = '";
|
|
2661
|
+
const char *where_clause = strstr(sql, where_prefix);
|
|
2662
|
+
if (where_clause != NULL) {
|
|
2663
|
+
const char *schema_start = where_clause + strlen(where_prefix);
|
|
2664
|
+
const char *schema_end = strchr(schema_start, '\'');
|
|
2665
|
+
if (schema_end == NULL) {
|
|
2666
|
+
free(sql);
|
|
2667
|
+
goto fail;
|
|
2668
|
+
}
|
|
2669
|
+
const size_t schema_length = (size_t)(schema_end - schema_start);
|
|
2670
|
+
schema_file_id_filter = malloc(schema_length + 1);
|
|
2671
|
+
if (schema_file_id_filter == NULL) {
|
|
2672
|
+
free(sql);
|
|
2673
|
+
goto fail;
|
|
2674
|
+
}
|
|
2675
|
+
memcpy(schema_file_id_filter, schema_start, schema_length);
|
|
2676
|
+
schema_file_id_filter[schema_length] = '\0';
|
|
2677
|
+
}
|
|
2678
|
+
const bool appended = append_runtime_host_row_query_result_json(
|
|
2679
|
+
&response,
|
|
2680
|
+
state,
|
|
2681
|
+
schema_file_id_filter);
|
|
2682
|
+
free(schema_file_id_filter);
|
|
2683
|
+
free(sql);
|
|
2684
|
+
if (!appended) {
|
|
2685
|
+
goto fail;
|
|
2686
|
+
}
|
|
2687
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
if (opcode == HOST_CONTROL_ALLOCATE_REGION) {
|
|
2691
|
+
char *layout_id = NULL;
|
|
2692
|
+
uint64_t record_byte_length_u64 = 0;
|
|
2693
|
+
uint64_t alignment_u64 = 1;
|
|
2694
|
+
uint8_t **records = NULL;
|
|
2695
|
+
size_t record_count = 0;
|
|
2696
|
+
if (!parse_json_string_field(json, json_length, "layoutId", &layout_id) ||
|
|
2697
|
+
!parse_json_u64_field(
|
|
2698
|
+
json,
|
|
2699
|
+
json_length,
|
|
2700
|
+
"recordByteLength",
|
|
2701
|
+
&record_byte_length_u64)) {
|
|
2702
|
+
free(layout_id);
|
|
2703
|
+
goto fail;
|
|
2704
|
+
}
|
|
2705
|
+
JsonSlice alignment_slice;
|
|
2706
|
+
if (find_json_object_field(json, json_length, "alignment", &alignment_slice) &&
|
|
2707
|
+
!parse_json_u64(alignment_slice, &alignment_u64)) {
|
|
2708
|
+
free(layout_id);
|
|
2709
|
+
goto fail;
|
|
2710
|
+
}
|
|
2711
|
+
if (record_byte_length_u64 == 0 || record_byte_length_u64 > UINT32_MAX ||
|
|
2712
|
+
alignment_u64 == 0 || alignment_u64 > UINT16_MAX ||
|
|
2713
|
+
!parse_initial_records_field(
|
|
2714
|
+
json,
|
|
2715
|
+
json_length,
|
|
2716
|
+
(uint32_t)record_byte_length_u64,
|
|
2717
|
+
&records,
|
|
2718
|
+
&record_count) ||
|
|
2719
|
+
!ensure_runtime_host_capacity(
|
|
2720
|
+
(void **)&state->regions,
|
|
2721
|
+
&state->region_capacity,
|
|
2722
|
+
state->region_count,
|
|
2723
|
+
sizeof(*state->regions))) {
|
|
2724
|
+
free(layout_id);
|
|
2725
|
+
for (size_t index = 0; index < record_count; ++index) {
|
|
2726
|
+
free(records[index]);
|
|
2727
|
+
}
|
|
2728
|
+
free(records);
|
|
2729
|
+
goto fail;
|
|
2730
|
+
}
|
|
2731
|
+
RuntimeHostRegion *region = &state->regions[state->region_count++];
|
|
2732
|
+
memset(region, 0, sizeof(*region));
|
|
2733
|
+
region->region_id = state->next_region_id++;
|
|
2734
|
+
region->layout_id = layout_id;
|
|
2735
|
+
region->record_byte_length = (uint32_t)record_byte_length_u64;
|
|
2736
|
+
region->alignment = (uint16_t)alignment_u64;
|
|
2737
|
+
region->records = records;
|
|
2738
|
+
region->record_count = record_count;
|
|
2739
|
+
if (!append_runtime_host_region_descriptor_json(&response, region)) {
|
|
2740
|
+
goto fail;
|
|
2741
|
+
}
|
|
2742
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
if (opcode == HOST_CONTROL_DESCRIBE_REGION) {
|
|
2746
|
+
uint64_t region_id = 0;
|
|
2747
|
+
if (!parse_json_u64_field(json, json_length, "regionId", ®ion_id)) {
|
|
2748
|
+
goto fail;
|
|
2749
|
+
}
|
|
2750
|
+
RuntimeHostRegion *region = find_runtime_host_region(state, region_id);
|
|
2751
|
+
if (region == NULL) {
|
|
2752
|
+
if (!json_buffer_append_cstr(&response, "null")) {
|
|
2753
|
+
goto fail;
|
|
2754
|
+
}
|
|
2755
|
+
} else if (!append_runtime_host_region_descriptor_json(&response, region)) {
|
|
2756
|
+
goto fail;
|
|
2757
|
+
}
|
|
2758
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
if (opcode == HOST_CONTROL_RESOLVE_RECORD) {
|
|
2762
|
+
uint64_t region_id = 0;
|
|
2763
|
+
uint64_t record_index_u64 = 0;
|
|
2764
|
+
if (!parse_json_u64_field(json, json_length, "regionId", ®ion_id) ||
|
|
2765
|
+
!parse_json_u64_field(json, json_length, "recordIndex", &record_index_u64)) {
|
|
2766
|
+
goto fail;
|
|
2767
|
+
}
|
|
2768
|
+
RuntimeHostRegion *region = find_runtime_host_region(state, region_id);
|
|
2769
|
+
if (region == NULL || record_index_u64 >= region->record_count) {
|
|
2770
|
+
if (!json_buffer_append_cstr(&response, "null")) {
|
|
2771
|
+
goto fail;
|
|
2772
|
+
}
|
|
2773
|
+
} else if (!append_runtime_host_region_record_json(
|
|
2774
|
+
&response,
|
|
2775
|
+
region,
|
|
2776
|
+
(uint32_t)record_index_u64)) {
|
|
2777
|
+
goto fail;
|
|
2778
|
+
}
|
|
2779
|
+
return respond_with_json_buffer(&response, response_bytes_out, response_size_out);
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
fail:
|
|
2783
|
+
json_buffer_free(&response);
|
|
2784
|
+
return false;
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
static bool serve_runtime_host_requests(void) {
|
|
2788
|
+
RuntimeHostState state;
|
|
2789
|
+
runtime_host_state_init(&state);
|
|
2790
|
+
bool ok = true;
|
|
2791
|
+
|
|
2792
|
+
for (;;) {
|
|
2793
|
+
uint8_t length_bytes[4];
|
|
2794
|
+
const size_t prefix_read = fread(length_bytes, 1, sizeof(length_bytes), stdin);
|
|
2795
|
+
if (prefix_read == 0) {
|
|
2796
|
+
ok = feof(stdin);
|
|
2797
|
+
break;
|
|
2798
|
+
}
|
|
2799
|
+
if (prefix_read != sizeof(length_bytes)) {
|
|
2800
|
+
ok = false;
|
|
2801
|
+
break;
|
|
2802
|
+
}
|
|
2803
|
+
const uint32_t request_size = read_le_u32_bytes(length_bytes);
|
|
2804
|
+
uint8_t *request_bytes = NULL;
|
|
2805
|
+
if (request_size > 0) {
|
|
2806
|
+
request_bytes = malloc(request_size);
|
|
2807
|
+
if (request_bytes == NULL || !read_exact(stdin, request_bytes, request_size)) {
|
|
2808
|
+
free(request_bytes);
|
|
2809
|
+
ok = false;
|
|
2810
|
+
break;
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
if (request_size < 5 ||
|
|
2814
|
+
memcmp(request_bytes, HOST_CONTROL_MAGIC, sizeof(HOST_CONTROL_MAGIC)) != 0) {
|
|
2815
|
+
free(request_bytes);
|
|
2816
|
+
ok = false;
|
|
2817
|
+
break;
|
|
2818
|
+
}
|
|
2819
|
+
uint8_t *response_bytes = NULL;
|
|
2820
|
+
uint32_t response_size = 0;
|
|
2821
|
+
ok = dispatch_runtime_host_request(
|
|
2822
|
+
&state,
|
|
2823
|
+
request_bytes[4],
|
|
2824
|
+
request_bytes + 5,
|
|
2825
|
+
request_size - 5,
|
|
2826
|
+
&response_bytes,
|
|
2827
|
+
&response_size);
|
|
2828
|
+
free(request_bytes);
|
|
2829
|
+
if (!ok) {
|
|
2830
|
+
free(response_bytes);
|
|
2831
|
+
break;
|
|
2832
|
+
}
|
|
2833
|
+
const uint8_t response_length_bytes[4] = {
|
|
2834
|
+
(uint8_t)(response_size & 0xFFU),
|
|
2835
|
+
(uint8_t)((response_size >> 8) & 0xFFU),
|
|
2836
|
+
(uint8_t)((response_size >> 16) & 0xFFU),
|
|
2837
|
+
(uint8_t)((response_size >> 24) & 0xFFU),
|
|
2838
|
+
};
|
|
2839
|
+
ok = write_all(stdout, response_length_bytes, sizeof(response_length_bytes)) &&
|
|
2840
|
+
write_all(stdout, response_bytes, response_size);
|
|
2841
|
+
free(response_bytes);
|
|
2842
|
+
if (!ok) {
|
|
2843
|
+
break;
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
runtime_host_state_destroy(&state);
|
|
2848
|
+
return ok;
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
static void destroy_thread_launch_context(ThreadLaunchContext *context) {
|
|
2852
|
+
if (context == NULL) {
|
|
2853
|
+
return;
|
|
2854
|
+
}
|
|
2855
|
+
if (context->module != NULL) {
|
|
2856
|
+
pthread_mutex_lock(&context->runner->store_mutex);
|
|
2857
|
+
WasmEdge_ModuleInstanceDelete(context->module);
|
|
2858
|
+
pthread_mutex_unlock(&context->runner->store_mutex);
|
|
2859
|
+
}
|
|
2860
|
+
if (context->executor != NULL) {
|
|
2861
|
+
WasmEdge_ExecutorDelete(context->executor);
|
|
2862
|
+
}
|
|
2863
|
+
free(context);
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
void *run_guest_thread(void *Data) {
|
|
2867
|
+
ThreadLaunchContext *context = Data;
|
|
2868
|
+
if (context == NULL || context->runner == NULL ||
|
|
2869
|
+
context->runner->shared_memory == NULL) {
|
|
2870
|
+
destroy_thread_launch_context(context);
|
|
2871
|
+
return NULL;
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
uint32_t stack_high = 0;
|
|
2875
|
+
uint32_t stack_size = 0;
|
|
2876
|
+
if (!read_guest_u32(
|
|
2877
|
+
context->runner->shared_memory,
|
|
2878
|
+
context->pthread_ptr + EM_PTHREAD_STACK_OFFSET,
|
|
2879
|
+
&stack_high) ||
|
|
2880
|
+
!read_guest_u32(
|
|
2881
|
+
context->runner->shared_memory,
|
|
2882
|
+
context->pthread_ptr + EM_PTHREAD_STACK_SIZE_OFFSET,
|
|
2883
|
+
&stack_size)) {
|
|
2884
|
+
destroy_thread_launch_context(context);
|
|
2885
|
+
return NULL;
|
|
2886
|
+
}
|
|
2887
|
+
const uint32_t stack_low = stack_high - stack_size;
|
|
2888
|
+
|
|
2889
|
+
WasmEdge_Value params[6];
|
|
2890
|
+
WasmEdge_Value returns[1];
|
|
2891
|
+
|
|
2892
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)stack_high);
|
|
2893
|
+
params[1] = WasmEdge_ValueGenI32((int32_t)stack_low);
|
|
2894
|
+
if (!invoke_function(
|
|
2895
|
+
context->executor,
|
|
2896
|
+
context->stack_set_limits,
|
|
2897
|
+
params,
|
|
2898
|
+
2,
|
|
2899
|
+
NULL,
|
|
2900
|
+
0,
|
|
2901
|
+
"emscripten_stack_set_limits")) {
|
|
2902
|
+
goto thread_crashed;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)stack_high);
|
|
2906
|
+
if (!invoke_function(
|
|
2907
|
+
context->executor,
|
|
2908
|
+
context->stack_restore,
|
|
2909
|
+
params,
|
|
2910
|
+
1,
|
|
2911
|
+
NULL,
|
|
2912
|
+
0,
|
|
2913
|
+
"_emscripten_stack_restore")) {
|
|
2914
|
+
goto thread_crashed;
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)context->pthread_ptr);
|
|
2918
|
+
params[1] = WasmEdge_ValueGenI32(0);
|
|
2919
|
+
params[2] = WasmEdge_ValueGenI32(0);
|
|
2920
|
+
params[3] = WasmEdge_ValueGenI32(1);
|
|
2921
|
+
params[4] = WasmEdge_ValueGenI32(0);
|
|
2922
|
+
params[5] = WasmEdge_ValueGenI32(0);
|
|
2923
|
+
if (!invoke_function(
|
|
2924
|
+
context->executor,
|
|
2925
|
+
context->thread_init,
|
|
2926
|
+
params,
|
|
2927
|
+
6,
|
|
2928
|
+
NULL,
|
|
2929
|
+
0,
|
|
2930
|
+
"_emscripten_thread_init")) {
|
|
2931
|
+
goto thread_crashed;
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
if (!invoke_function(
|
|
2935
|
+
context->executor,
|
|
2936
|
+
context->tls_init,
|
|
2937
|
+
NULL,
|
|
2938
|
+
0,
|
|
2939
|
+
returns,
|
|
2940
|
+
1,
|
|
2941
|
+
"_emscripten_tls_init")) {
|
|
2942
|
+
goto thread_crashed;
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2945
|
+
WasmEdge_Value function_ref;
|
|
2946
|
+
const WasmEdge_Result table_result = WasmEdge_TableInstanceGetData(
|
|
2947
|
+
context->indirect_table,
|
|
2948
|
+
&function_ref,
|
|
2949
|
+
context->start_routine);
|
|
2950
|
+
if (!WasmEdge_ResultOK(table_result)) {
|
|
2951
|
+
fprintf(
|
|
2952
|
+
stderr,
|
|
2953
|
+
"table lookup failed: %s (0x%x)\n",
|
|
2954
|
+
WasmEdge_ResultGetMessage(table_result),
|
|
2955
|
+
WasmEdge_ResultGetCode(table_result));
|
|
2956
|
+
goto thread_crashed;
|
|
2957
|
+
}
|
|
2958
|
+
const WasmEdge_FunctionInstanceContext *entry_function =
|
|
2959
|
+
WasmEdge_ValueGetFuncRef(function_ref);
|
|
2960
|
+
if (entry_function == NULL) {
|
|
2961
|
+
fprintf(stderr, "thread entry function pointer was null\n");
|
|
2962
|
+
goto thread_crashed;
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
params[0] = WasmEdge_ValueGenI32((int32_t)context->arg);
|
|
2966
|
+
if (!invoke_function(
|
|
2967
|
+
context->executor,
|
|
2968
|
+
(WasmEdge_FunctionInstanceContext *)entry_function,
|
|
2969
|
+
params,
|
|
2970
|
+
1,
|
|
2971
|
+
returns,
|
|
2972
|
+
1,
|
|
2973
|
+
"thread entry")) {
|
|
2974
|
+
goto thread_crashed;
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
params[0] = WasmEdge_ValueGenI32(WasmEdge_ValueGetI32(returns[0]));
|
|
2978
|
+
invoke_function(
|
|
2979
|
+
context->executor,
|
|
2980
|
+
context->thread_exit,
|
|
2981
|
+
params,
|
|
2982
|
+
1,
|
|
2983
|
+
NULL,
|
|
2984
|
+
0,
|
|
2985
|
+
"_emscripten_thread_exit");
|
|
2986
|
+
destroy_thread_launch_context(context);
|
|
2987
|
+
return NULL;
|
|
2988
|
+
|
|
2989
|
+
thread_crashed:
|
|
2990
|
+
if (context->thread_crashed != NULL) {
|
|
2991
|
+
invoke_function(
|
|
2992
|
+
context->executor,
|
|
2993
|
+
context->thread_crashed,
|
|
2994
|
+
NULL,
|
|
2995
|
+
0,
|
|
2996
|
+
NULL,
|
|
2997
|
+
0,
|
|
2998
|
+
"_emscripten_thread_crashed");
|
|
2999
|
+
}
|
|
3000
|
+
destroy_thread_launch_context(context);
|
|
3001
|
+
return NULL;
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
int main(int argc, char **argv) {
|
|
3005
|
+
if (argc < 2) {
|
|
3006
|
+
fprintf(
|
|
3007
|
+
stderr,
|
|
3008
|
+
"usage: %s module.wasm [module-args...] | %s --serve-runtime-host\n",
|
|
3009
|
+
argv[0],
|
|
3010
|
+
argv[0]);
|
|
3011
|
+
return 2;
|
|
3012
|
+
}
|
|
3013
|
+
const bool serve_runtime_host =
|
|
3014
|
+
argc >= 2 && strcmp(argv[1], "--serve-runtime-host") == 0;
|
|
3015
|
+
if (serve_runtime_host) {
|
|
3016
|
+
return serve_runtime_host_requests() ? 0 : 1;
|
|
3017
|
+
}
|
|
3018
|
+
const bool serve_plugin_invoke =
|
|
3019
|
+
argc >= 3 && strcmp(argv[2], "--serve-plugin-invoke") == 0;
|
|
3020
|
+
|
|
3021
|
+
WasmEdge_ConfigureContext *conf = WasmEdge_ConfigureCreate();
|
|
3022
|
+
WasmEdge_ConfigureAddProposal(conf, WasmEdge_Proposal_Threads);
|
|
3023
|
+
WasmEdge_ConfigureAddProposal(conf, WasmEdge_Proposal_ExceptionHandling);
|
|
3024
|
+
WasmEdge_LoaderContext *loader = WasmEdge_LoaderCreate(conf);
|
|
3025
|
+
WasmEdge_ValidatorContext *validator = WasmEdge_ValidatorCreate(conf);
|
|
3026
|
+
WasmEdge_ExecutorContext *executor = WasmEdge_ExecutorCreate(conf, NULL);
|
|
3027
|
+
WasmEdge_StoreContext *store = WasmEdge_StoreCreate();
|
|
3028
|
+
RunnerContext runner = {
|
|
3029
|
+
.conf = conf,
|
|
3030
|
+
.ast = NULL,
|
|
3031
|
+
.store = store,
|
|
3032
|
+
.shared_memory = NULL,
|
|
3033
|
+
};
|
|
3034
|
+
pthread_mutex_init(&runner.store_mutex, NULL);
|
|
3035
|
+
|
|
3036
|
+
WasmEdge_ASTModuleContext *ast = NULL;
|
|
3037
|
+
WasmEdge_Result res = WasmEdge_LoaderParseFromFile(loader, &ast, argv[1]);
|
|
3038
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
3039
|
+
fail_result("parse", res);
|
|
3040
|
+
}
|
|
3041
|
+
runner.ast = ast;
|
|
3042
|
+
res = WasmEdge_ValidatorValidate(validator, ast);
|
|
3043
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
3044
|
+
fail_result("validate", res);
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3047
|
+
WasmEdge_ModuleInstanceContext *wasi = WasmEdge_ModuleInstanceCreateWASI(
|
|
3048
|
+
(const char *const *)(argv + 1),
|
|
3049
|
+
(uint32_t)(argc - 1),
|
|
3050
|
+
NULL,
|
|
3051
|
+
0,
|
|
3052
|
+
NULL,
|
|
3053
|
+
0);
|
|
3054
|
+
res = WasmEdge_ExecutorRegisterImport(executor, store, wasi);
|
|
3055
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
3056
|
+
fail_result("register wasi", res);
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
WasmEdge_ModuleInstanceContext *env =
|
|
3060
|
+
WasmEdge_ModuleInstanceCreate(WasmEdge_StringCreateByCString("env"));
|
|
3061
|
+
ImportedModuleConfig import_config;
|
|
3062
|
+
if (!read_imported_module_config(argv[1], &import_config)) {
|
|
3063
|
+
fprintf(stderr, "failed to inspect wasm import contract\n");
|
|
3064
|
+
return 1;
|
|
3065
|
+
}
|
|
3066
|
+
if (!add_imported_env_memory_from_file(argv[1], env, &runner.shared_memory)) {
|
|
3067
|
+
fprintf(stderr, "failed to create imported env memory\n");
|
|
3068
|
+
return 1;
|
|
3069
|
+
}
|
|
3070
|
+
register_env_host_functions(
|
|
3071
|
+
env,
|
|
3072
|
+
&runner,
|
|
3073
|
+
import_config.receive_on_main_thread_param_len == 4
|
|
3074
|
+
? 4
|
|
3075
|
+
: 5,
|
|
3076
|
+
import_config.notify_mailbox_postmessage_param_len == 3
|
|
3077
|
+
? 3
|
|
3078
|
+
: 2);
|
|
3079
|
+
res = WasmEdge_ExecutorRegisterImport(executor, store, env);
|
|
3080
|
+
if (!WasmEdge_ResultOK(res)) {
|
|
3081
|
+
fail_result("register env", res);
|
|
984
3082
|
}
|
|
985
3083
|
|
|
986
|
-
|
|
3084
|
+
WasmEdge_ModuleInstanceContext *mod = NULL;
|
|
3085
|
+
res = WasmEdge_ExecutorInstantiate(executor, &mod, store, ast);
|
|
987
3086
|
if (!WasmEdge_ResultOK(res)) {
|
|
988
|
-
fail_result("
|
|
3087
|
+
fail_result("instantiate", res);
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
if (!invoke_optional_module_init(executor, mod, serve_plugin_invoke)) {
|
|
3091
|
+
return 3;
|
|
989
3092
|
}
|
|
990
3093
|
|
|
991
|
-
|
|
3094
|
+
uint32_t exit_code = WasmEdge_ModuleInstanceWASIGetExitCode(wasi);
|
|
3095
|
+
if (serve_plugin_invoke) {
|
|
3096
|
+
if (!serve_plugin_invoke_requests(executor, mod, &runner)) {
|
|
3097
|
+
exit_code = 1;
|
|
3098
|
+
} else {
|
|
3099
|
+
exit_code = 0;
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
992
3102
|
|
|
993
3103
|
WasmEdge_ASTModuleDelete(ast);
|
|
994
3104
|
WasmEdge_StoreDelete(store);
|