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); + 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); + } + else { // 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; - } - else { - return YJIT_CANT_COMPILE; - } + return YJIT_KEEP_COMPILING; } static codegen_status_t