summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstraptest/test_yjit.rb10
-rw-r--r--test/ruby/test_yjit.rb10
-rw-r--r--yjit_codegen.c37
3 files changed, 48 insertions, 9 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index c94c710c4d..0a3aa81860 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -2278,3 +2278,13 @@ assert_equal '{:foo=>123}', %q{
foo
foo
}
+
+# newhash
+assert_equal '{:foo=>2}', %q{
+ def foo
+ {foo: 1+1}
+ end
+
+ foo
+ foo
+}
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index 9b26e6c37f..7b8cde6c0c 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -85,6 +85,16 @@ class TestYJIT < Test::Unit::TestCase
assert_compiles('e = 5; (..e)', insns: %i[newrange], result: ..5)
end
+ def test_compile_duphash
+ assert_compiles('{ two: 2 }', insns: %i[duphash], result: { two: 2 })
+ end
+
+ def test_compile_newhash
+ assert_compiles('{}', insns: %i[newhash], result: {})
+ assert_compiles('{ two: 1 + 1 }', insns: %i[newhash], result: { two: 2 })
+ assert_compiles('{ 1 + 1 => :two }', insns: %i[newhash], result: { 2 => :two })
+ end
+
def test_compile_opt_nil_p
assert_compiles('nil.nil?', insns: %i[opt_nil_p], result: true)
assert_compiles('false.nil?', insns: %i[opt_nil_p], result: false)
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 374786571c..b0d799c013 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -1078,23 +1078,42 @@ gen_expandarray(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
static codegen_status_t
gen_newhash(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
{
- rb_num_t n = (rb_num_t)jit_get_arg(jit, 0);
+ int32_t num = (int32_t)jit_get_arg(jit, 0);
- if (n == 0) {
- // Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, REG0);
+ // Save the PC and SP because we are allocating
+ jit_prepare_routine_call(jit, ctx, REG0);
- // val = rb_hash_new();
- call_ptr(cb, REG0, (void *)rb_hash_new);
+ if (num) {
+ // val = rb_hash_new_with_size(num / 2);
+ mov(cb, C_ARG_REGS[0], imm_opnd(num / 2));
+ call_ptr(cb, REG0, (void *)rb_hash_new_with_size);
+
+ // save the allocated hash as we want to push it after insertion
+ push(cb, RAX);
+ push(cb, RAX); // alignment
+
+ // rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
+ mov(cb, C_ARG_REGS[0], imm_opnd(num));
+ lea(cb, C_ARG_REGS[1], ctx_stack_opnd(ctx, num - 1));
+ mov(cb, C_ARG_REGS[2], RAX);
+ call_ptr(cb, REG0, (void *)rb_hash_bulk_insert);
+ pop(cb, RAX); // alignment
+ pop(cb, RAX);
+
+ ctx_stack_pop(ctx, num);
x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_HASH);
mov(cb, stack_ret, RAX);
-
- return YJIT_KEEP_COMPILING;
}
else {
- return YJIT_CANT_COMPILE;
+ // val = rb_hash_new();
+ call_ptr(cb, REG0, (void *)rb_hash_new);
+
+ x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_HASH);
+ mov(cb, stack_ret, RAX);
}
+
+ return YJIT_KEEP_COMPILING;
}
static codegen_status_t