konpeito 0.2.2 → 0.2.3
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 +18 -0
- data/lib/konpeito/codegen/builtin_methods.rb +4 -2
- data/lib/konpeito/codegen/cruby_backend.rb +122 -10
- data/lib/konpeito/codegen/inliner.rb +9 -3
- data/lib/konpeito/codegen/jvm_generator.rb +3986 -919
- data/lib/konpeito/codegen/llvm_generator.rb +334 -45
- data/lib/konpeito/codegen/monomorphizer.rb +14 -2
- data/lib/konpeito/hir/builder.rb +150 -20
- data/lib/konpeito/hir/nodes.rb +16 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +100 -41
- data/lib/konpeito/type_checker/types.rb +6 -6
- data/lib/konpeito/type_checker/unification.rb +8 -1
- data/lib/konpeito/version.rb +1 -1
- data/tools/konpeito-asm/build.sh +1 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFiber.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMatchData.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/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +17 -1
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +97 -4
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +20 -25
- data/tools/konpeito-asm/src/konpeito/runtime/KFiber.java +112 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +67 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMatchData.java +55 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRubyException.java +79 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +5 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +285 -19
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 968753a2cfabd2d2b237dd5125d6ae0818848a3f7243e7fdbb408a50dc802f48
|
|
4
|
+
data.tar.gz: 724dcd3309cb7e42fbd2cf7e3ffa0b6b1eac07840a8ba46affcad3c0bab6a21a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e23cbc46176d84f51b1706e1125eae4f02a1ff31f6e9f64bc49856c79c8061a1aae6441cac1ee638c1a7eb8b0884cb235a40d11c509783e8e82b502d0b77e477
|
|
7
|
+
data.tar.gz: 3ead6d2c4b880aae4f687cfabf4f2c75c07f3b1939ed610a20ca0b1af301ff27153acfc25007720aaad772ae2581cb55c11558d7c6e9d9a16876012911081394
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ 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.3] - 2026-02-24
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Conformance test suite expansion: 77 spec files with 1,095+ assertions
|
|
12
|
+
- JVM runtime: Fiber support, ConditionVariable deadlock fix, Math module (PI, E, sqrt)
|
|
13
|
+
- `&blk` block argument support at call sites (e.g., `arr.map(&blk)`)
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Native backend: BUS error in `defined?(:method)` at top-level
|
|
17
|
+
- Native backend: inliner no longer inlines functions with `&blk` block params
|
|
18
|
+
- JVM backend: ConditionVariable deadlock — rewritten to release mutex during wait
|
|
19
|
+
- JVM backend: Math::PI, Math::E constants and Math.sqrt dispatch
|
|
20
|
+
- JVM backend: nested rescue, pattern matching, SizedQueue#empty?
|
|
21
|
+
- JVM backend: Integer()/Float() kernel methods, String#split limit, sleep, Symbol#frozen?
|
|
22
|
+
- JVM backend: hash iteration, KArray methods, splat args, user-defined ==, super(args)
|
|
23
|
+
- JVM backend: VerifyError for widened instance method parameters
|
|
24
|
+
- JVM backend: Fiber resume/yield, thread_mutex, runtime class identity
|
|
25
|
+
|
|
8
26
|
## [0.2.2] - 2026-02-21
|
|
9
27
|
|
|
10
28
|
### Added
|
|
@@ -69,8 +69,10 @@ module Konpeito
|
|
|
69
69
|
:+ => { c_func: "rb_ary_plus", arity: 1, return_type: :Array, conv: :simple },
|
|
70
70
|
concat: { c_func: "rb_ary_concat", arity: 1, return_type: :Array, conv: :simple },
|
|
71
71
|
|
|
72
|
-
# Array transformation
|
|
73
|
-
|
|
72
|
+
# Array transformation
|
|
73
|
+
# Note: rb_ary_reverse is in-place mutation, so we use rb_funcallv fallback
|
|
74
|
+
# to get Ruby's Array#reverse behavior (returns new array without modifying original)
|
|
75
|
+
# reverse: removed from builtin_methods - falls back to rb_funcallv
|
|
74
76
|
sort: { c_func: "rb_ary_sort", arity: 0, return_type: :Array, conv: :simple },
|
|
75
77
|
|
|
76
78
|
# Array query with args - exported
|
|
@@ -152,6 +152,25 @@ module Konpeito
|
|
|
152
152
|
lines << "extern VALUE #{mangled_name}(#{(['VALUE'] * (arity + 1)).join(', ')});"
|
|
153
153
|
end
|
|
154
154
|
end
|
|
155
|
+
|
|
156
|
+
# Declare extern for alias-renamed functions
|
|
157
|
+
(llvm_generator.alias_renamed_methods || {}).each do |key, renamed|
|
|
158
|
+
class_name, _method_name = key.split("#", 2)
|
|
159
|
+
next unless class_name == class_def.name.to_s
|
|
160
|
+
|
|
161
|
+
owner = class_name.gsub(/[^a-zA-Z0-9_]/, "_")
|
|
162
|
+
sanitized = renamed.gsub(/[^a-zA-Z0-9_]/, "_")
|
|
163
|
+
mangled = "rn_#{owner}_#{sanitized}"
|
|
164
|
+
func = llvm_generator.mod.functions[mangled]
|
|
165
|
+
next unless func
|
|
166
|
+
|
|
167
|
+
if llvm_generator.variadic_functions[mangled]
|
|
168
|
+
lines << "extern VALUE #{mangled}(int argc, VALUE *argv, VALUE self);"
|
|
169
|
+
else
|
|
170
|
+
arity = func.params.size - 1
|
|
171
|
+
lines << "extern VALUE #{mangled}(#{(['VALUE'] * (arity + 1)).join(', ')});"
|
|
172
|
+
end
|
|
173
|
+
end
|
|
155
174
|
end
|
|
156
175
|
|
|
157
176
|
# Declare external functions from LLVM module (modules)
|
|
@@ -264,12 +283,12 @@ module Konpeito
|
|
|
264
283
|
lines << " rb_define_singleton_method(#{module_var}, \"#{method_name}\", #{mangled_name}, #{arity});"
|
|
265
284
|
end
|
|
266
285
|
|
|
267
|
-
# Register module constants
|
|
268
|
-
module_def.constants.each do |const_name,
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
lines << "
|
|
286
|
+
# Register module constants (e.g., VERSION = "2.0")
|
|
287
|
+
module_def.constants.each do |const_name, value_node|
|
|
288
|
+
c_value = hir_literal_to_c_value(value_node)
|
|
289
|
+
next unless c_value
|
|
290
|
+
|
|
291
|
+
lines << " rb_const_set(#{module_var}, rb_intern(\"#{const_name}\"), #{c_value});"
|
|
273
292
|
end
|
|
274
293
|
end
|
|
275
294
|
|
|
@@ -297,17 +316,20 @@ module Konpeito
|
|
|
297
316
|
|
|
298
317
|
# Prepend modules (must come before include to maintain proper method resolution order)
|
|
299
318
|
class_def.prepended_modules.each do |module_name|
|
|
300
|
-
|
|
319
|
+
module_expr = resolve_module_c_expr(module_name)
|
|
320
|
+
lines << " rb_prepend_module(#{class_var}, #{module_expr});"
|
|
301
321
|
end
|
|
302
322
|
|
|
303
323
|
# Include modules
|
|
304
324
|
class_def.included_modules.each do |module_name|
|
|
305
|
-
|
|
325
|
+
module_expr = resolve_module_c_expr(module_name)
|
|
326
|
+
lines << " rb_include_module(#{class_var}, #{module_expr});"
|
|
306
327
|
end
|
|
307
328
|
|
|
308
329
|
# Extend modules (adds module methods as singleton methods on the class)
|
|
309
330
|
class_def.extended_modules.each do |module_name|
|
|
310
|
-
|
|
331
|
+
module_expr = resolve_module_c_expr(module_name)
|
|
332
|
+
lines << " rb_extend_object(#{class_var}, #{module_expr});"
|
|
311
333
|
end
|
|
312
334
|
|
|
313
335
|
class_def.method_names.each do |method_name|
|
|
@@ -343,7 +365,41 @@ module Konpeito
|
|
|
343
365
|
|
|
344
366
|
# Register aliases
|
|
345
367
|
class_def.aliases.each do |new_name, old_name|
|
|
346
|
-
|
|
368
|
+
renamed_key = "#{class_def.name}##{old_name}"
|
|
369
|
+
if llvm_generator.alias_renamed_methods&.key?(renamed_key)
|
|
370
|
+
# Method was redefined after alias — point alias to renamed original
|
|
371
|
+
renamed = llvm_generator.alias_renamed_methods[renamed_key]
|
|
372
|
+
owner = class_def.name.to_s.gsub(/[^a-zA-Z0-9_]/, "_")
|
|
373
|
+
sanitized = renamed.gsub(/[^a-zA-Z0-9_]/, "_")
|
|
374
|
+
mangled = "rn_#{owner}_#{sanitized}"
|
|
375
|
+
llvm_func = llvm_generator.mod.functions[mangled]
|
|
376
|
+
if llvm_generator.variadic_functions[mangled]
|
|
377
|
+
arity = -1
|
|
378
|
+
elsif llvm_func
|
|
379
|
+
arity = llvm_func.params.size - 1
|
|
380
|
+
else
|
|
381
|
+
arity = 0
|
|
382
|
+
end
|
|
383
|
+
lines << " rb_define_method(#{class_var}, \"#{new_name}\", #{mangled}, #{arity});"
|
|
384
|
+
else
|
|
385
|
+
lines << " rb_define_alias(#{class_var}, \"#{new_name}\", \"#{old_name}\");"
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# Register class body constants (e.g., PI = 3, VERSION = "1.0")
|
|
390
|
+
class_def.body_constants.each do |const_name, value_node|
|
|
391
|
+
c_value = hir_literal_to_c_value(value_node)
|
|
392
|
+
next unless c_value
|
|
393
|
+
|
|
394
|
+
lines << " rb_const_set(#{class_var}, rb_intern(\"#{const_name}\"), #{c_value});"
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Register class body class variables (e.g., @@count = 0)
|
|
398
|
+
class_def.body_class_vars.each do |cvar_name, value_node|
|
|
399
|
+
c_value = hir_literal_to_c_value(value_node)
|
|
400
|
+
next unless c_value
|
|
401
|
+
|
|
402
|
+
lines << " rb_cvar_set(#{class_var}, rb_intern(\"#{cvar_name}\"), #{c_value});"
|
|
347
403
|
end
|
|
348
404
|
end
|
|
349
405
|
|
|
@@ -1019,6 +1075,25 @@ module Konpeito
|
|
|
1019
1075
|
"Comparable" => "rb_mComparable",
|
|
1020
1076
|
}.freeze
|
|
1021
1077
|
|
|
1078
|
+
# Known Ruby stdlib modules that can be included/extended/prepended
|
|
1079
|
+
KNOWN_MODULE_MAP = {
|
|
1080
|
+
"Comparable" => "rb_mComparable",
|
|
1081
|
+
"Enumerable" => "rb_mEnumerable",
|
|
1082
|
+
"Kernel" => "rb_mKernel",
|
|
1083
|
+
"Math" => "rb_mMath",
|
|
1084
|
+
}.freeze
|
|
1085
|
+
|
|
1086
|
+
# Resolve a module name to its C expression for include/extend/prepend
|
|
1087
|
+
def resolve_module_c_expr(module_name)
|
|
1088
|
+
# Check known stdlib modules first
|
|
1089
|
+
if KNOWN_MODULE_MAP[module_name]
|
|
1090
|
+
return KNOWN_MODULE_MAP[module_name]
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
# User-defined module (defined earlier in Init function as mModuleName)
|
|
1094
|
+
"m#{module_name}"
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1022
1097
|
def resolve_superclass_c_expr(superclass_name, non_native_classes)
|
|
1023
1098
|
return "rb_cObject" unless superclass_name
|
|
1024
1099
|
|
|
@@ -1041,6 +1116,43 @@ module Konpeito
|
|
|
1041
1116
|
"rb_const_get(rb_cObject, rb_intern(\"#{superclass_name}\"))"
|
|
1042
1117
|
end
|
|
1043
1118
|
|
|
1119
|
+
# Convert an HIR literal node to a C VALUE expression for use in Init function.
|
|
1120
|
+
# Returns nil for non-literal nodes that cannot be statically initialized.
|
|
1121
|
+
def hir_literal_to_c_value(node)
|
|
1122
|
+
case node
|
|
1123
|
+
when HIR::IntegerLit
|
|
1124
|
+
"INT2FIX(#{node.value})"
|
|
1125
|
+
when HIR::FloatLit
|
|
1126
|
+
"DBL2NUM(#{node.value})"
|
|
1127
|
+
when HIR::StringLit
|
|
1128
|
+
escaped = node.value.to_s.gsub("\\", "\\\\\\\\").gsub('"', '\\"').gsub("\n", "\\n").gsub("\t", "\\t")
|
|
1129
|
+
"rb_str_new_cstr(\"#{escaped}\")"
|
|
1130
|
+
when HIR::SymbolLit
|
|
1131
|
+
"ID2SYM(rb_intern(\"#{node.value}\"))"
|
|
1132
|
+
when HIR::BoolLit
|
|
1133
|
+
node.value ? "Qtrue" : "Qfalse"
|
|
1134
|
+
when HIR::NilLit
|
|
1135
|
+
"Qnil"
|
|
1136
|
+
when HIR::Literal
|
|
1137
|
+
# Generic literal fallback
|
|
1138
|
+
case node.type
|
|
1139
|
+
when TypeChecker::Types::INTEGER
|
|
1140
|
+
"INT2FIX(#{node.value})"
|
|
1141
|
+
when TypeChecker::Types::FLOAT
|
|
1142
|
+
"DBL2NUM(#{node.value})"
|
|
1143
|
+
when TypeChecker::Types::STRING
|
|
1144
|
+
escaped = node.value.to_s.gsub("\\", "\\\\\\\\").gsub('"', '\\"').gsub("\n", "\\n").gsub("\t", "\\t")
|
|
1145
|
+
"rb_str_new_cstr(\"#{escaped}\")"
|
|
1146
|
+
when TypeChecker::Types::BOOL
|
|
1147
|
+
node.value ? "Qtrue" : "Qfalse"
|
|
1148
|
+
else
|
|
1149
|
+
nil
|
|
1150
|
+
end
|
|
1151
|
+
else
|
|
1152
|
+
nil
|
|
1153
|
+
end
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1044
1156
|
# Generate extern declaration for a @cfunc C function
|
|
1045
1157
|
def generate_cfunc_extern_declaration(cfunc_type)
|
|
1046
1158
|
lines = []
|
|
@@ -74,9 +74,9 @@ module Konpeito
|
|
|
74
74
|
# Skip class methods for now
|
|
75
75
|
return false if func.owner_class
|
|
76
76
|
|
|
77
|
-
# Skip functions with rest params (*args)
|
|
78
|
-
# The inliner doesn't support rest param array aggregation
|
|
79
|
-
return false if func.params.any? { |p| p.rest || p.keyword_rest }
|
|
77
|
+
# Skip functions with rest params (*args), keyword_rest (**kwargs), or block params (&blk)
|
|
78
|
+
# The inliner doesn't support rest param array aggregation or block capture context
|
|
79
|
+
return false if func.params.any? { |p| p.rest || p.keyword_rest || p.block }
|
|
80
80
|
|
|
81
81
|
# Skip functions with multiple blocks (contains if/while/etc.)
|
|
82
82
|
# These have complex control flow that can't be simply inlined
|
|
@@ -91,6 +91,7 @@ module Konpeito
|
|
|
91
91
|
# Skip functions containing block calls (captures need complex transformation)
|
|
92
92
|
# Skip functions containing yield (need KBlock parameter handling)
|
|
93
93
|
# Skip functions containing BeginRescue (exception handling has complex sub-block structure)
|
|
94
|
+
# Skip functions containing ThreadNew/FiberNew (callbacks reference specific allocas)
|
|
94
95
|
func.body.each do |block|
|
|
95
96
|
block.instructions.each do |inst|
|
|
96
97
|
return false if inst.is_a?(HIR::Call) && inst.block
|
|
@@ -98,6 +99,8 @@ module Konpeito
|
|
|
98
99
|
return false if inst.is_a?(HIR::BeginRescue)
|
|
99
100
|
return false if inst.is_a?(HIR::CaseStatement)
|
|
100
101
|
return false if inst.is_a?(HIR::CaseMatchStatement)
|
|
102
|
+
return false if inst.is_a?(HIR::ThreadNew)
|
|
103
|
+
return false if inst.is_a?(HIR::FiberNew)
|
|
101
104
|
end
|
|
102
105
|
end
|
|
103
106
|
|
|
@@ -158,6 +161,9 @@ module Konpeito
|
|
|
158
161
|
def can_inline_call?(inst)
|
|
159
162
|
return false unless self_call?(inst)
|
|
160
163
|
|
|
164
|
+
# Don't inline calls with splat arguments - they need rb_apply
|
|
165
|
+
return false if inst.args.any? { |a| a.is_a?(HIR::SplatArg) }
|
|
166
|
+
|
|
161
167
|
callee_name = inst.method_name.to_s
|
|
162
168
|
@inline_candidates[callee_name] == true
|
|
163
169
|
end
|