konpeito 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/konpeito/codegen/cruby_backend.rb +7 -0
- data/lib/konpeito/codegen/jvm_generator.rb +160 -40
- data/lib/konpeito/codegen/llvm_generator.rb +236 -58
- data/lib/konpeito/hir/builder.rb +61 -27
- data/lib/konpeito/hir/nodes.rb +2 -0
- data/lib/konpeito/version.rb +1 -1
- data/tools/konpeito-asm/build.sh +1 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +12 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMatchData.java +50 -1
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +721 -8
- metadata +1 -20
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFiber.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMatchData.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRubyException.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eb29f99bc1ae9fcdcf859aaea0f04974db8a8f42ddfa989c5a07d6e722d04a5e
|
|
4
|
+
data.tar.gz: f3ae88ae17967ee5241737159a53781fcdc33894f6ab122af4cc2e58a8ef56f9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a267485ba1745ee5ebcf07be2d9235e4f8e6acb112292132943c2a484ec680f0af59ada1c0417326ad5765e1baeade52bcaf0b7d32de8bc1a1dcda92128391d
|
|
7
|
+
data.tar.gz: e162318a4fbe08e1022218a800ece9f8b6b6d2ad362b63ee8348ffc369772ce3f5f477432a6df08af69fd90b429f2f93fbaafb0619f5ab5bfcf5521a40c83780
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to Konpeito will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.4] - 2026-02-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Conformance test suite expanded to 87 spec files (10 new specs: array_functional, frozen_immutable, hash_transform, integer_step, kernel_format, object_protocol, proc_curry, range_advanced, regexp_matchdata, string_succ_ord)
|
|
12
|
+
- JVM runtime: updated KFiber, KMatchData, KRactor, KRactorPort classes for new conformance specs
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- Native backend: `lambda?` and `arity` singleton methods now correctly attached to Proc objects via `rb_define_singleton_method`, achieving 87/87 native conformance
|
|
16
|
+
- Native backend: NativeClass method chaining — monomorphized call results (e.g. `dot_Vec2`) now correctly tagged as `:double`/`:i64` in `@variable_types`, preventing `rb_num2dbl` from being called on an already-unboxed double (was causing segfault in `normalized_dot` benchmark)
|
|
17
|
+
- Benchmark: `slice_bench.rb` RBS overload syntax updated from duplicate `def []:` to union `|` syntax (RBS 3.x compatibility)
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- `.gitignore`: `*.class` pattern extended to cover all subdirectories (was only matching root-level `.class` files)
|
|
21
|
+
|
|
8
22
|
## [0.2.3] - 2026-02-24
|
|
9
23
|
|
|
10
24
|
### Added
|
|
@@ -162,6 +176,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
162
176
|
- `%a{extern}` - external C struct wrappers
|
|
163
177
|
- `%a{simd}` - SIMD vectorization
|
|
164
178
|
|
|
179
|
+
[0.2.4]: https://github.com/i2y/konpeito/compare/v0.2.3...v0.2.4
|
|
180
|
+
[0.2.3]: https://github.com/i2y/konpeito/compare/v0.2.2...v0.2.3
|
|
165
181
|
[0.2.2]: https://github.com/i2y/konpeito/compare/v0.2.1...v0.2.2
|
|
166
182
|
[0.2.1]: https://github.com/i2y/konpeito/compare/v0.2.0...v0.2.1
|
|
167
183
|
[0.2.0]: https://github.com/i2y/konpeito/compare/v0.1.3...v0.2.0
|
|
@@ -403,6 +403,13 @@ module Konpeito
|
|
|
403
403
|
end
|
|
404
404
|
end
|
|
405
405
|
|
|
406
|
+
# Register top-level constants on rb_cObject (e.g., MY_CONST = 42 at top level)
|
|
407
|
+
hir.toplevel_constants.each do |const_name, value_node|
|
|
408
|
+
c_value = hir_literal_to_c_value(value_node)
|
|
409
|
+
next unless c_value
|
|
410
|
+
lines << " rb_const_set(rb_cObject, rb_intern(\"#{const_name}\"), #{c_value});"
|
|
411
|
+
end
|
|
412
|
+
|
|
406
413
|
# Define top-level methods on Object
|
|
407
414
|
hir.functions.each do |func_def|
|
|
408
415
|
next if func_def.owner_class
|
|
@@ -4491,7 +4491,7 @@ module Konpeito
|
|
|
4491
4491
|
# Extract elements for remaining params
|
|
4492
4492
|
remaining_params = target_func.params[splat_index..]
|
|
4493
4493
|
remaining_params.each_with_index do |param, j|
|
|
4494
|
-
next if param.rest || param.keyword_rest
|
|
4494
|
+
next if param.rest || param.keyword_rest || param.block
|
|
4495
4495
|
param_t = widened_param_type(target_func, param, splat_index + j)
|
|
4496
4496
|
# Load array, push index, call get(int)
|
|
4497
4497
|
instructions << load_instruction(splat_temp, :value)
|
|
@@ -4503,8 +4503,9 @@ module Konpeito
|
|
|
4503
4503
|
end
|
|
4504
4504
|
else
|
|
4505
4505
|
# Normal argument loading (no splat)
|
|
4506
|
-
# Load arguments
|
|
4506
|
+
# Load arguments (skip block params — they are handled as KBlock below)
|
|
4507
4507
|
target_func.params.each_with_index do |param, i|
|
|
4508
|
+
next if param.block
|
|
4508
4509
|
if param.rest
|
|
4509
4510
|
# Rest parameter (*args): collect remaining arguments into a KArray
|
|
4510
4511
|
rest_args = args[i..]
|
|
@@ -4547,13 +4548,18 @@ module Konpeito
|
|
|
4547
4548
|
end
|
|
4548
4549
|
end
|
|
4549
4550
|
|
|
4550
|
-
# If target is a yield-containing function, determine descriptor and pass null
|
|
4551
|
+
# If target is a yield-containing function, determine descriptor and pass block (or null)
|
|
4551
4552
|
target_has_yield = @yield_functions.include?(actual_target) || @yield_functions.include?(method_name)
|
|
4552
4553
|
if target_has_yield
|
|
4553
4554
|
kblock_iface = yield_function_kblock_interface(target_func)
|
|
4554
4555
|
desc = method_descriptor_with_block(target_func, kblock_iface)
|
|
4555
|
-
#
|
|
4556
|
-
|
|
4556
|
+
# If caller provides a block, compile it and pass as KBlock; otherwise pass null
|
|
4557
|
+
if inst.block
|
|
4558
|
+
block_insts = compile_block_arg_for_instance_call(inst.block)
|
|
4559
|
+
instructions.concat(block_insts)
|
|
4560
|
+
else
|
|
4561
|
+
instructions << { "op" => "aconst_null" }
|
|
4562
|
+
end
|
|
4557
4563
|
else
|
|
4558
4564
|
desc = method_descriptor(target_func)
|
|
4559
4565
|
end
|
|
@@ -9167,7 +9173,7 @@ module Konpeito
|
|
|
9167
9173
|
|
|
9168
9174
|
# Build method descriptor with KBlock parameter for yield-containing functions
|
|
9169
9175
|
def method_descriptor_with_block(func, kblock_iface)
|
|
9170
|
-
params_desc = func.params.map { |p|
|
|
9176
|
+
params_desc = func.params.reject { |p| p.block }.map { |p|
|
|
9171
9177
|
t = param_type(p)
|
|
9172
9178
|
t = :value if t == :void # Nil/void is not valid as JVM param type
|
|
9173
9179
|
type_to_descriptor(t)
|
|
@@ -9287,6 +9293,7 @@ module Konpeito
|
|
|
9287
9293
|
|
|
9288
9294
|
# Load regular arguments (using the target function's param types)
|
|
9289
9295
|
target_func.params.each_with_index do |param, i|
|
|
9296
|
+
next if param.block # block params handled as KBlock separately
|
|
9290
9297
|
if param.keyword_rest
|
|
9291
9298
|
# Keyword rest parameter (**kwargs): build a KHash from keyword_args
|
|
9292
9299
|
if inst.respond_to?(:keyword_args) && inst.has_keyword_args?
|
|
@@ -9530,7 +9537,7 @@ module Konpeito
|
|
|
9530
9537
|
# because they may receive Regexp (Pattern) arguments that can't be handled inline.
|
|
9531
9538
|
%w[length size upcase downcase include? start_with? end_with? strip
|
|
9532
9539
|
reverse empty? split chars lines bytes
|
|
9533
|
-
replace
|
|
9540
|
+
replace to_i to_f []].include?(name)
|
|
9534
9541
|
end
|
|
9535
9542
|
|
|
9536
9543
|
# Check if a method argument is a Regexp (Pattern) type
|
|
@@ -10223,7 +10230,10 @@ module Konpeito
|
|
|
10223
10230
|
instructions << { "op" => "lcmp" }
|
|
10224
10231
|
instructions << { "op" => "ifne", "target" => found_label }
|
|
10225
10232
|
else
|
|
10226
|
-
|
|
10233
|
+
# Use RubyDispatch.isTruthy to handle null (nil) and Boolean.FALSE
|
|
10234
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
10235
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
10236
|
+
instructions << { "op" => "ifne", "target" => found_label }
|
|
10227
10237
|
end
|
|
10228
10238
|
end
|
|
10229
10239
|
|
|
@@ -10577,7 +10587,10 @@ module Konpeito
|
|
|
10577
10587
|
instructions << { "op" => "lcmp" }
|
|
10578
10588
|
instructions << { "op" => "ifeq", "target" => skip_label }
|
|
10579
10589
|
else
|
|
10580
|
-
|
|
10590
|
+
# Use RubyDispatch.isTruthy to correctly handle null (nil) and Boolean.FALSE
|
|
10591
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
10592
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
10593
|
+
instructions << { "op" => "ifeq", "target" => skip_label }
|
|
10581
10594
|
end
|
|
10582
10595
|
else
|
|
10583
10596
|
instructions << { "op" => "goto", "target" => skip_label }
|
|
@@ -10692,7 +10705,10 @@ module Konpeito
|
|
|
10692
10705
|
instructions << { "op" => "lcmp" }
|
|
10693
10706
|
instructions << { "op" => "ifne", "target" => skip_label }
|
|
10694
10707
|
else
|
|
10695
|
-
|
|
10708
|
+
# Use RubyDispatch.isTruthy to handle null (nil) and Boolean.FALSE
|
|
10709
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
10710
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
10711
|
+
instructions << { "op" => "ifne", "target" => skip_label }
|
|
10696
10712
|
end
|
|
10697
10713
|
end
|
|
10698
10714
|
|
|
@@ -10933,7 +10949,10 @@ module Konpeito
|
|
|
10933
10949
|
instructions << { "op" => "lcmp" }
|
|
10934
10950
|
instructions << { "op" => "ifne", "target" => found_label }
|
|
10935
10951
|
else
|
|
10936
|
-
|
|
10952
|
+
# Use RubyDispatch.isTruthy to handle null (nil) and Boolean.FALSE
|
|
10953
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
10954
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
10955
|
+
instructions << { "op" => "ifne", "target" => found_label }
|
|
10937
10956
|
end
|
|
10938
10957
|
when :all
|
|
10939
10958
|
# all?: if falsy → found (false)
|
|
@@ -10944,7 +10963,10 @@ module Konpeito
|
|
|
10944
10963
|
instructions << { "op" => "lcmp" }
|
|
10945
10964
|
instructions << { "op" => "ifeq", "target" => found_label }
|
|
10946
10965
|
else
|
|
10947
|
-
|
|
10966
|
+
# Use RubyDispatch.isTruthy to handle null (nil) and Boolean.FALSE
|
|
10967
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
10968
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
10969
|
+
instructions << { "op" => "ifeq", "target" => found_label }
|
|
10948
10970
|
end
|
|
10949
10971
|
when :none
|
|
10950
10972
|
# none?: if truthy → found (false)
|
|
@@ -10955,7 +10977,10 @@ module Konpeito
|
|
|
10955
10977
|
instructions << { "op" => "lcmp" }
|
|
10956
10978
|
instructions << { "op" => "ifne", "target" => found_label }
|
|
10957
10979
|
else
|
|
10958
|
-
|
|
10980
|
+
# Use RubyDispatch.isTruthy to handle null (nil) and Boolean.FALSE
|
|
10981
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
10982
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
10983
|
+
instructions << { "op" => "ifne", "target" => found_label }
|
|
10959
10984
|
end
|
|
10960
10985
|
end
|
|
10961
10986
|
end
|
|
@@ -11056,10 +11081,18 @@ module Konpeito
|
|
|
11056
11081
|
if last_result_var
|
|
11057
11082
|
last_type = @variable_types[last_result_var] || :value
|
|
11058
11083
|
instructions << load_instruction(last_result_var, last_type)
|
|
11059
|
-
|
|
11084
|
+
case last_type
|
|
11085
|
+
when :i8
|
|
11086
|
+
instructions << { "op" => "ifeq", "target" => skip_label }
|
|
11087
|
+
when :i64
|
|
11088
|
+
instructions << { "op" => "lconst_0" }
|
|
11089
|
+
instructions << { "op" => "lcmp" }
|
|
11060
11090
|
instructions << { "op" => "ifeq", "target" => skip_label }
|
|
11061
11091
|
else
|
|
11062
|
-
|
|
11092
|
+
# Use RubyDispatch.isTruthy to correctly handle null (nil) and Boolean.FALSE
|
|
11093
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
11094
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
11095
|
+
instructions << { "op" => "ifeq", "target" => skip_label }
|
|
11063
11096
|
end
|
|
11064
11097
|
end
|
|
11065
11098
|
|
|
@@ -11234,7 +11267,7 @@ module Konpeito
|
|
|
11234
11267
|
generate_hash_each_inline(receiver, _block_def, result_var)
|
|
11235
11268
|
end
|
|
11236
11269
|
when "fetch"
|
|
11237
|
-
generate_hash_fetch(receiver, args, result_var)
|
|
11270
|
+
generate_hash_fetch(receiver, args, result_var, _block_def)
|
|
11238
11271
|
when "merge"
|
|
11239
11272
|
generate_hash_merge(receiver, args, result_var)
|
|
11240
11273
|
when "merge!", "update"
|
|
@@ -11431,24 +11464,116 @@ module Konpeito
|
|
|
11431
11464
|
|
|
11432
11465
|
# -- Hash methods --
|
|
11433
11466
|
|
|
11434
|
-
def generate_hash_fetch(receiver, args, result_var)
|
|
11467
|
+
def generate_hash_fetch(receiver, args, result_var, block_def = nil)
|
|
11435
11468
|
instructions = []
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11469
|
+
if block_def && args.size == 1
|
|
11470
|
+
# h.fetch(key) { |k| ... } — call block when key is missing
|
|
11471
|
+
@block_counter = (@block_counter || 0) + 1
|
|
11472
|
+
hash_var = "__fetch_hash_#{@block_counter}"
|
|
11473
|
+
key_var = "__fetch_key_#{@block_counter}"
|
|
11474
|
+
val_var = "__fetch_val_#{@block_counter}"
|
|
11475
|
+
found_label = new_label("fetch_found")
|
|
11476
|
+
end_label = new_label("fetch_end")
|
|
11477
|
+
ensure_slot(hash_var, :value)
|
|
11478
|
+
ensure_slot(key_var, :value)
|
|
11479
|
+
ensure_slot(val_var, :value)
|
|
11480
|
+
|
|
11481
|
+
instructions.concat(load_khash_receiver(receiver))
|
|
11482
|
+
instructions << store_instruction(hash_var, :value)
|
|
11483
|
+
@variable_types[hash_var] = :value
|
|
11484
|
+
|
|
11485
|
+
instructions.concat(load_and_box_for_collection(args[0]))
|
|
11486
|
+
instructions << store_instruction(key_var, :value)
|
|
11487
|
+
@variable_types[key_var] = :value
|
|
11488
|
+
|
|
11489
|
+
# val = hash.get(key)
|
|
11490
|
+
instructions << load_instruction(hash_var, :value)
|
|
11491
|
+
instructions << { "op" => "checkcast", "type" => KHASH_CLASS }
|
|
11492
|
+
instructions << load_instruction(key_var, :value)
|
|
11493
|
+
instructions << { "op" => "invokeinterface", "owner" => "java/util/Map",
|
|
11494
|
+
"name" => "get", "descriptor" => "(Ljava/lang/Object;)Ljava/lang/Object;" }
|
|
11495
|
+
instructions << store_instruction(val_var, :value)
|
|
11496
|
+
@variable_types[val_var] = :value
|
|
11497
|
+
|
|
11498
|
+
# if val != null OR hash.containsKey(key) → found
|
|
11499
|
+
instructions << load_instruction(val_var, :value)
|
|
11500
|
+
instructions << { "op" => "ifnonnull", "target" => found_label }
|
|
11501
|
+
|
|
11502
|
+
# also check containsKey for explicit null values
|
|
11503
|
+
instructions << load_instruction(hash_var, :value)
|
|
11504
|
+
instructions << { "op" => "checkcast", "type" => KHASH_CLASS }
|
|
11505
|
+
instructions << load_instruction(key_var, :value)
|
|
11506
|
+
instructions << { "op" => "invokeinterface", "owner" => "java/util/Map",
|
|
11507
|
+
"name" => "containsKey", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
11508
|
+
instructions << { "op" => "ifne", "target" => found_label }
|
|
11509
|
+
|
|
11510
|
+
# Key not found: execute block with key
|
|
11511
|
+
block_param = block_def.params.first
|
|
11512
|
+
elem_var = block_param ? block_param.name.to_s : "__fetch_blk_k_#{@block_counter}"
|
|
11513
|
+
saved_outer = save_outer_var_for_block_param(elem_var)
|
|
11514
|
+
ensure_slot(elem_var, :value)
|
|
11515
|
+
instructions << load_instruction(key_var, :value)
|
|
11516
|
+
instructions << store_instruction(elem_var, :value)
|
|
11517
|
+
@variable_types[elem_var] = :value
|
|
11518
|
+
|
|
11519
|
+
last_result_var = nil
|
|
11520
|
+
block_def.body.each do |bb|
|
|
11521
|
+
@current_block_label = bb.label.to_s
|
|
11522
|
+
bb.instructions.each do |block_inst|
|
|
11523
|
+
instructions.concat(generate_instruction(block_inst))
|
|
11524
|
+
last_result_var = block_inst.result_var if block_inst.respond_to?(:result_var) && block_inst.result_var
|
|
11525
|
+
end
|
|
11526
|
+
end
|
|
11527
|
+
restore_outer_var_after_block(elem_var, saved_outer)
|
|
11528
|
+
|
|
11529
|
+
if last_result_var
|
|
11530
|
+
last_type = @variable_types[last_result_var] || :value
|
|
11531
|
+
instructions << load_instruction(last_result_var, last_type)
|
|
11532
|
+
case last_type
|
|
11533
|
+
when :i64
|
|
11534
|
+
instructions << { "op" => "invokestatic", "owner" => "java/lang/Long",
|
|
11535
|
+
"name" => "valueOf", "descriptor" => "(J)Ljava/lang/Long;" }
|
|
11536
|
+
when :double
|
|
11537
|
+
instructions << { "op" => "invokestatic", "owner" => "java/lang/Double",
|
|
11538
|
+
"name" => "valueOf", "descriptor" => "(D)Ljava/lang/Double;" }
|
|
11539
|
+
when :i8
|
|
11540
|
+
instructions << { "op" => "invokestatic", "owner" => "java/lang/Boolean",
|
|
11541
|
+
"name" => "valueOf", "descriptor" => "(Z)Ljava/lang/Boolean;" }
|
|
11542
|
+
end
|
|
11543
|
+
else
|
|
11544
|
+
instructions << { "op" => "aconst_null" }
|
|
11545
|
+
end
|
|
11546
|
+
instructions << { "op" => "goto", "target" => end_label }
|
|
11547
|
+
|
|
11548
|
+
# Found: return val
|
|
11549
|
+
instructions << { "op" => "label", "name" => found_label }
|
|
11550
|
+
instructions << load_instruction(val_var, :value)
|
|
11551
|
+
|
|
11552
|
+
instructions << { "op" => "label", "name" => end_label }
|
|
11553
|
+
if result_var
|
|
11554
|
+
ensure_slot(result_var, :value)
|
|
11555
|
+
instructions << store_instruction(result_var, :value)
|
|
11556
|
+
@variable_types[result_var] = :value
|
|
11557
|
+
end
|
|
11558
|
+
instructions
|
|
11440
11559
|
else
|
|
11441
|
-
instructions
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
instructions <<
|
|
11449
|
-
|
|
11560
|
+
instructions.concat(load_khash_receiver(receiver))
|
|
11561
|
+
instructions.concat(load_and_box_for_collection(args[0]))
|
|
11562
|
+
if args.size > 1
|
|
11563
|
+
instructions.concat(load_and_box_for_collection(args[1]))
|
|
11564
|
+
else
|
|
11565
|
+
instructions << { "op" => "aconst_null" }
|
|
11566
|
+
end
|
|
11567
|
+
instructions << { "op" => "invokevirtual", "owner" => KHASH_CLASS,
|
|
11568
|
+
"name" => "fetch",
|
|
11569
|
+
"descriptor" => "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" }
|
|
11570
|
+
if result_var
|
|
11571
|
+
ensure_slot(result_var, :value)
|
|
11572
|
+
instructions << store_instruction(result_var, :value)
|
|
11573
|
+
@variable_types[result_var] = :value
|
|
11574
|
+
end
|
|
11575
|
+
instructions
|
|
11450
11576
|
end
|
|
11451
|
-
instructions
|
|
11452
11577
|
end
|
|
11453
11578
|
|
|
11454
11579
|
def generate_hash_merge(receiver, args, result_var)
|
|
@@ -12307,14 +12432,6 @@ module Konpeito
|
|
|
12307
12432
|
generate_string_bytes(receiver, result_var)
|
|
12308
12433
|
when "replace"
|
|
12309
12434
|
generate_string_replace(receiver, args, result_var)
|
|
12310
|
-
when "freeze"
|
|
12311
|
-
# No-op on JVM (strings are immutable), just return the receiver
|
|
12312
|
-
generate_string_passthrough(receiver, result_var)
|
|
12313
|
-
when "frozen?"
|
|
12314
|
-
# On JVM, String#frozen? defaults to true since Java strings are immutable.
|
|
12315
|
-
# This means "unfrozen" string tests will fail, but "freeze then frozen?" tests will pass.
|
|
12316
|
-
# A proper solution would require wrapping strings in a mutable container.
|
|
12317
|
-
generate_string_always_true(result_var)
|
|
12318
12435
|
when "count"
|
|
12319
12436
|
generate_string_count(receiver, args, result_var)
|
|
12320
12437
|
when "tr"
|
|
@@ -13687,7 +13804,10 @@ module Konpeito
|
|
|
13687
13804
|
instructions << { "op" => "lcmp" }
|
|
13688
13805
|
instructions << { "op" => "ifeq", "target" => skip_label }
|
|
13689
13806
|
else
|
|
13690
|
-
|
|
13807
|
+
# Use RubyDispatch.isTruthy to correctly handle null (nil) and Boolean.FALSE
|
|
13808
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
13809
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
13810
|
+
instructions << { "op" => "ifeq", "target" => skip_label }
|
|
13691
13811
|
end
|
|
13692
13812
|
else
|
|
13693
13813
|
instructions << { "op" => "goto", "target" => skip_label }
|