Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions packages/gems/js/ext/js/js-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ static VALUE _rb_js_eval_js(VALUE _, VALUE code_str) {
rstring_to_abi_string(code_str, &abi_str);
rb_js_abi_host_js_abi_result_t ret;
rb_js_abi_host_eval_js(&abi_str, &ret);
rb_js_abi_host_string_free(&abi_str);
raise_js_error_if_failure(&ret);
return jsvalue_s_new(ret.val.success);
}
Expand Down Expand Up @@ -197,6 +198,7 @@ static VALUE _rb_js_obj_aref(VALUE obj, VALUE key) {
rstring_to_abi_string(key, &key_abi_str);
rb_js_abi_host_js_abi_result_t ret;
rb_js_abi_host_reflect_get(p->abi, &key_abi_str, &ret);
rb_js_abi_host_string_free(&key_abi_str);
raise_js_error_if_failure(&ret);
return jsvalue_s_new(ret.val.success);
}
Expand Down Expand Up @@ -224,6 +226,7 @@ static VALUE _rb_js_obj_aset(VALUE obj, VALUE key, VALUE val) {
rstring_to_abi_string(key, &key_abi_str);
rb_js_abi_host_js_abi_result_t ret;
rb_js_abi_host_reflect_set(p->abi, &key_abi_str, v->abi, &ret);
rb_js_abi_host_string_free(&key_abi_str);
raise_js_error_if_failure(&ret);
rb_js_abi_host_js_abi_value_free(&ret.val.success);
RB_GC_GUARD(rv);
Expand Down Expand Up @@ -346,7 +349,9 @@ static VALUE _rb_js_obj_typeof(VALUE obj) {
struct jsvalue *p = check_jsvalue(obj);
rb_js_abi_host_string_t ret0;
rb_js_abi_host_js_value_typeof(p->abi, &ret0);
return rb_str_new((const char *)ret0.ptr, ret0.len);
VALUE typeof_str = rb_str_new((const char *)ret0.ptr, ret0.len);
rb_js_abi_host_string_free(&ret0);
return typeof_str;
}

/*
Expand All @@ -366,7 +371,9 @@ static VALUE _rb_js_obj_to_s(VALUE obj) {
struct jsvalue *p = check_jsvalue(obj);
rb_js_abi_host_string_t ret0;
rb_js_abi_host_js_value_to_string(p->abi, &ret0);
return rb_utf8_str_new((const char *)ret0.ptr, ret0.len);
VALUE to_s_str = rb_utf8_str_new((const char *)ret0.ptr, ret0.len);
rb_js_abi_host_string_free(&ret0);
return to_s_str;
}

/*
Expand Down Expand Up @@ -494,7 +501,10 @@ static VALUE _rb_js_float_to_js(VALUE obj) {
static VALUE _rb_js_string_to_js(VALUE obj) {
rb_js_abi_host_string_t abi_str;
rstring_to_abi_string(obj, &abi_str);
return jsvalue_s_new(rb_js_abi_host_string_to_js_string(&abi_str));
rb_js_abi_host_own_js_abi_value_t js_str =
rb_js_abi_host_string_to_js_string(&abi_str);
rb_js_abi_host_string_free(&abi_str);
return jsvalue_s_new(js_str);
}

/*
Expand Down
1 change: 1 addition & 0 deletions packages/gems/js/ext/js/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef ext_list_string_t rb_abi_guest_list_string_t;
ruby_js_js_runtime_export_js_value_to_host(borrow_js_value(value))
# define rb_js_abi_host_raw_integer_free(ptr) \
ruby_js_js_runtime_raw_integer_free(ptr)
# define rb_js_abi_host_string_free(ptr) ext_string_free(ptr)
# define rb_js_abi_host_rb_object_to_js_rb_value(val) \
ruby_js_js_runtime_rb_object_to_js_rb_value(val)
# define rb_js_abi_host_int_to_js_number(val) \
Expand Down
25 changes: 25 additions & 0 deletions packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,29 @@ def test_apply
floor = JS.global[:Math][:floor]
assert_equal 3, floor.apply(3.14).to_i
end

# Every string crossing the boundary now frees its ABI buffer, in both
# directions. Freeing one too early would hand back another allocation's
# bytes, so each round trip below carries a value distinct from its
# neighbours - garbage or a stale repeat fails the assertion rather than
# passing by luck. GC.stress shakes out an early free that only shows when
# the allocator reuses the block promptly.
def test_string_round_trips_survive_their_abi_buffers
object = JS.eval("return {};")
64.times do |i|
key = "key_#{i}_#{"x" * i}"
value = "value_#{i}_#{"y" * i}"
object[key] = value
assert_equal value, object[key].to_s
assert_equal "string", object[key].typeof
end
GC.stress = true
16.times do |i|
key = "stress_#{i}"
object[key] = JS.eval("return #{key.dump};")
assert_equal key, object[key].to_s
end
ensure
GC.stress = false
end
end
Loading