summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/ucode/types.h5
-rw-r--r--tests/custom/04_modules/16_multi_program_imports143
-rw-r--r--types.c10
-rw-r--r--vm.c22
4 files changed, 163 insertions, 17 deletions
diff --git a/include/ucode/types.h b/include/ucode/types.h
index 6041b22..bae2dd5 100644
--- a/include/ucode/types.h
+++ b/include/ucode/types.h
@@ -208,12 +208,14 @@ uc_declare_vector(uc_resource_types_t, uc_resource_type_t *);
/* Program structure definitions */
uc_declare_vector(uc_sources_t, uc_source_t *);
+uc_declare_vector(uc_modexports_t, uc_upvalref_t *);
typedef struct uc_program {
uc_value_t header;
uc_value_list_t constants;
uc_weakref_t functions;
uc_sources_t sources;
+ uc_modexports_t exports;
} uc_program_t;
@@ -277,7 +279,6 @@ typedef struct {
uc_declare_vector(uc_callframes_t, uc_callframe_t);
uc_declare_vector(uc_stack_t, uc_value_t *);
-uc_declare_vector(uc_modexports_t, uc_upvalref_t *);
typedef struct printbuf uc_stringbuf_t;
@@ -294,7 +295,7 @@ struct uc_vm {
uc_source_t *sources;
uc_weakref_t values;
uc_resource_types_t restypes;
- uc_modexports_t exports;
+ char _reserved[sizeof(uc_modexports_t)];
union {
uint32_t u32;
int32_t s32;
diff --git a/tests/custom/04_modules/16_multi_program_imports b/tests/custom/04_modules/16_multi_program_imports
new file mode 100644
index 0000000..32d54fe
--- /dev/null
+++ b/tests/custom/04_modules/16_multi_program_imports
@@ -0,0 +1,143 @@
+This testcase asserts that import/export symbols in runtime loaded code
+are properly dealt with.
+
+Since the compiler has no knowledge about runtime loaded code it cannot
+reserve slots in the export table, requiring the VM to maintain one export
+table per program instance.
+
+The dependency tree is:
+
+root
+ + import: mod1
+ + import: mod2
+ + require: mod3
+ + import: mod1
+ + import: mod2
+
+-- Testcase --
+import { mod2sym1, mod2sym2 } from 'mod2';
+import { mod1sym1, mod1sym2 } from 'mod1';
+
+mod3 = require('mod3');
+
+printf("root: %.J\n", { mod1sym1, mod1sym2, mod2sym1, mod2sym2, mod3 });
+-- End --
+
+-- File mod1.uc --
+export const mod1sym1 = "a";
+export const mod1sym2 = "b";
+-- End --
+
+-- File mod2.uc --
+export const mod2sym1 = "c";
+export const mod2sym2 = "d";
+-- End --
+
+-- File mod3.uc --
+import { mod1sym2, mod1sym1 } from 'mod1';
+import { mod2sym2, mod2sym1 } from 'mod2';
+
+printf("mod3: %.J\n", { mod1sym1, mod1sym2, mod2sym1, mod2sym2 });
+
+return { mod1sym1, mod1sym2, mod2sym1, mod2sym2 };
+-- End --
+
+-- Args --
+-R -L files/
+-- End --
+
+-- Expect stdout --
+mod3: {
+ "mod1sym1": "a",
+ "mod1sym2": "b",
+ "mod2sym1": "c",
+ "mod2sym2": "d"
+}
+root: {
+ "mod1sym1": "a",
+ "mod1sym2": "b",
+ "mod2sym1": "c",
+ "mod2sym2": "d",
+ "mod3": {
+ "mod1sym1": "a",
+ "mod1sym2": "b",
+ "mod2sym1": "c",
+ "mod2sym2": "d"
+ }
+}
+-- End --
+
+
+A variation of the above testcase using wildcard imports.
+
+root
+ + import: mod4
+ + import: mod5
+ + require: mod6
+ + import: mod4
+ + import: mod5
+
+-- Testcase --
+import * as mod5 from 'mod5';
+import * as mod4 from 'mod4';
+
+mod6 = require('mod6');
+
+printf("root: %.J\n", { mod4, mod5, mod6 });
+-- End --
+
+-- File mod4.uc --
+export const sym1 = "a";
+export const sym2 = "b";
+-- End --
+
+-- File mod5.uc --
+export const sym1 = "c";
+export const sym2 = "d";
+-- End --
+
+-- File mod6.uc --
+import * as mod4 from 'mod4';
+import * as mod5 from 'mod5';
+
+printf("mod6: %.J\n", { mod4, mod5 });
+
+return { mod4, mod5 };
+-- End --
+
+-- Args --
+-R -L files/
+-- End --
+
+-- Expect stdout --
+mod6: {
+ "mod4": {
+ "sym1": "a",
+ "sym2": "b"
+ },
+ "mod5": {
+ "sym1": "c",
+ "sym2": "d"
+ }
+}
+root: {
+ "mod4": {
+ "sym1": "a",
+ "sym2": "b"
+ },
+ "mod5": {
+ "sym1": "c",
+ "sym2": "d"
+ },
+ "mod6": {
+ "mod4": {
+ "sym1": "a",
+ "sym2": "b"
+ },
+ "mod5": {
+ "sym1": "c",
+ "sym2": "d"
+ }
+ }
+}
+-- End --
diff --git a/types.c b/types.c
index 5274d23..1a430ac 100644
--- a/types.c
+++ b/types.c
@@ -203,6 +203,9 @@ ucv_gc_mark(uc_value_t *uv)
for (i = 0; i < program->sources.count; i++)
ucv_gc_mark(&program->sources.entries[i]->header);
+ for (i = 0; i < program->exports.count; i++)
+ ucv_gc_mark(&program->exports.entries[i]->header);
+
break;
default:
@@ -297,7 +300,11 @@ ucv_free(uc_value_t *uv, bool retain)
for (i = 0; i < program->sources.count; i++)
ucv_put_value(&program->sources.entries[i]->header, retain);
+ for (i = 0; i < program->exports.count; i++)
+ ucv_put_value(&program->exports.entries[i]->header, retain);
+
uc_vector_clear(&program->sources);
+ uc_vector_clear(&program->exports);
break;
case UC_SOURCE:
@@ -2227,9 +2234,6 @@ ucv_gc_common(uc_vm_t *vm, bool final)
for (i = 0; i < vm->restypes.count; i++)
ucv_gc_mark(vm->restypes.entries[i]->proto);
-
- for (i = 0; i < vm->exports.count; i++)
- ucv_gc_mark(vm->exports.entries[i]->value);
}
/* unref unreachable objects */
diff --git a/vm.c b/vm.c
index d8f0074..3bf9836 100644
--- a/vm.c
+++ b/vm.c
@@ -184,9 +184,6 @@ void uc_vm_free(uc_vm_t *vm)
for (i = 0; i < vm->restypes.count; i++)
ucv_put(vm->restypes.entries[i]->proto);
- for (i = 0; i < vm->exports.count; i++)
- ucv_put(&vm->exports.entries[i]->header);
-
uc_vm_reset_callframes(vm);
uc_vm_reset_stack(vm);
uc_vector_clear(&vm->stack);
@@ -200,7 +197,6 @@ void uc_vm_free(uc_vm_t *vm)
free(vm->restypes.entries[i]);
uc_vector_clear(&vm->restypes);
- uc_vector_clear(&vm->exports);
}
static uc_chunk_t *
@@ -2362,6 +2358,7 @@ static void
uc_vm_insn_import(uc_vm_t *vm, uc_vm_insn_t insn)
{
uc_callframe_t *frame = uc_vm_current_frame(vm);
+ uc_program_t *prog = uc_vm_current_program(vm);
uint16_t from = vm->arg.u32 & 0xffff;
uint16_t to = vm->arg.u32 >> 16;
uc_value_t *name, *modobj;
@@ -2376,8 +2373,8 @@ uc_vm_insn_import(uc_vm_t *vm, uc_vm_insn_t insn)
* first module export and `from` times u32 values containing
* the constant indexes of the names */
for (from = frame->ip[0] * 0x100 + frame->ip[1], frame->ip += 2;
- from < to && from < vm->exports.count;
- from++) {
+ from < prog->exports.count && to > 0;
+ from++, to--) {
cidx = (
frame->ip[0] * 0x1000000UL +
@@ -2390,9 +2387,9 @@ uc_vm_insn_import(uc_vm_t *vm, uc_vm_insn_t insn)
name = uc_program_get_constant(uc_vm_current_program(vm), cidx);
- if (ucv_type(name) == UC_STRING && vm->exports.entries[from])
+ if (ucv_type(name) == UC_STRING && prog->exports.entries[from])
ucv_object_add(modobj, ucv_string_get(name),
- ucv_get(&vm->exports.entries[from]->header));
+ ucv_get(&prog->exports.entries[from]->header));
ucv_put(name);
}
@@ -2403,9 +2400,9 @@ uc_vm_insn_import(uc_vm_t *vm, uc_vm_insn_t insn)
}
/* module export available, patch into upvalue */
- else if (from < vm->exports.count && vm->exports.entries[from]) {
- frame->closure->upvals[to] = vm->exports.entries[from];
- ucv_get(&vm->exports.entries[from]->header);
+ else if (from <= prog->exports.count && prog->exports.entries[from]) {
+ frame->closure->upvals[to] = prog->exports.entries[from];
+ ucv_get(&prog->exports.entries[from]->header);
}
/* module export missing, e.g. due to premature return in module,
@@ -2420,9 +2417,10 @@ static void
uc_vm_insn_export(uc_vm_t *vm, uc_vm_insn_t insn)
{
uc_callframe_t *frame = uc_vm_current_frame(vm);
+ uc_program_t *prog = uc_vm_current_program(vm);
uc_upvalref_t *ref = uc_vm_capture_upval(vm, frame->stackframe + vm->arg.u32);
- uc_vector_push(&vm->exports, ref);
+ uc_vector_push(&prog->exports, ref);
ucv_get(&ref->header);
}