Skip to content

Commit 365d19f

Browse files
Interpret JavaScript string given in eval as UTF8
1 parent 293e7c2 commit 365d19f

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

ext/witapi/witapi-core.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,57 @@
22

33
#include "ruby.h"
44

5+
// ========= Private Ruby API =========
6+
// from eval_intern.h
7+
VALUE rb_f_eval(int argc, const VALUE *argv, VALUE self);
8+
// from internal/vm.h
9+
PUREFUNC(VALUE rb_vm_top_self(void));
10+
// from vm_core.h
11+
typedef struct rb_control_frame_struct {
12+
const VALUE *pc; /* cfp[0] */
13+
VALUE *sp; /* cfp[1] */
14+
const void *iseq; /* cfp[2] */
15+
VALUE self; /* cfp[3] / block[0] */
16+
const VALUE *ep; /* cfp[4] / block[1] */
17+
} rb_control_frame_t;
18+
19+
typedef struct rb_execution_context_struct {
20+
/* execution information */
21+
VALUE *vm_stack; /* must free, must mark */
22+
size_t vm_stack_size; /* size in word (byte size / sizeof(VALUE)) */
23+
rb_control_frame_t *cfp;
24+
} rb_execution_context_t;
25+
26+
// from vm.c and vm_core.h
27+
RUBY_EXTERN struct rb_execution_context_struct *ruby_current_ec;
28+
#define GET_EC() (ruby_current_ec)
29+
rb_control_frame_t *
30+
rb_vm_get_ruby_level_next_cfp(const rb_execution_context_t *ec,
31+
const rb_control_frame_t *cfp);
32+
// ====== End of Private Ruby API =====
33+
34+
VALUE
35+
ruby_eval_string_value_from_file(VALUE str, VALUE file) {
36+
rb_execution_context_t *ec = GET_EC();
37+
rb_control_frame_t *cfp =
38+
ec ? rb_vm_get_ruby_level_next_cfp(ec, ec->cfp) : NULL;
39+
VALUE self = cfp ? cfp->self : rb_vm_top_self();
40+
#define argc 4
41+
const VALUE argv[argc] = {str, Qnil, file, INT2FIX(1)};
42+
return rb_f_eval(argc, argv, self);
43+
#undef argc
44+
}
45+
46+
static VALUE rb_eval_string_value_protect_thunk(VALUE str) {
47+
return ruby_eval_string_value_from_file(str, rb_utf8_str_new("eval", 4));
48+
}
49+
50+
// TODO(katei): This API should be moved to CRuby itself.
51+
VALUE
52+
rb_eval_string_value_protect(VALUE str, int *pstate) {
53+
return rb_protect(rb_eval_string_value_protect_thunk, str, pstate);
54+
}
55+
556
#define TAG_NONE 0
657

758
#include "bindgen/rb-abi-guest.h"
@@ -177,7 +228,8 @@ void rb_abi_guest_rb_eval_string_protect(
177228
rb_abi_guest_string_t *str, rb_abi_guest_tuple2_rb_abi_value_s32_t *ret0) {
178229
VALUE retval;
179230
RB_WASM_DEBUG_LOG("rb_eval_string_protect: str = %s\n", str->ptr);
180-
RB_WASM_LIB_RT(retval = rb_eval_string_protect(str->ptr, &ret0->f1));
231+
VALUE utf8_str = rb_utf8_str_new(str->ptr, str->len);
232+
RB_WASM_LIB_RT(retval = rb_eval_string_value_protect(utf8_str, &ret0->f1));
181233
RB_WASM_DEBUG_LOG("rb_eval_string_protect: retval = %p, state = %d\n",
182234
(void *)retval, ret0->f1);
183235

packages/npm-packages/ruby-wasm-wasi/test/vm.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,10 @@ eval:11:in \`<main>'`);
228228
);
229229
expect(result.call("nil?").toString()).toBe("true");
230230
});
231+
232+
test("eval encoding", async () => {
233+
const vm = await initRubyVM();
234+
expect(vm.eval(`"hello".encoding.name`).toString()).toBe("UTF-8");
235+
expect(vm.eval(`__ENCODING__.name`).toString()).toBe("UTF-8");
236+
});
231237
});

0 commit comments

Comments
 (0)