@@ -7,15 +7,16 @@ require "./llvm_builder_helper"
7
7
require " ./abi/*"
8
8
9
9
module Crystal
10
- MAIN_NAME = " __crystal_main"
11
- RAISE_NAME = " __crystal_raise"
12
- RAISE_OVERFLOW_NAME = " __crystal_raise_overflow"
13
- MALLOC_NAME = " __crystal_malloc64"
14
- MALLOC_ATOMIC_NAME = " __crystal_malloc_atomic64"
15
- REALLOC_NAME = " __crystal_realloc64"
16
- GET_EXCEPTION_NAME = " __crystal_get_exception"
17
- ONCE_INIT = " __crystal_once_init"
18
- ONCE = " __crystal_once"
10
+ MAIN_NAME = " __crystal_main"
11
+ RAISE_NAME = " __crystal_raise"
12
+ RAISE_OVERFLOW_NAME = " __crystal_raise_overflow"
13
+ RAISE_CAST_FAILED_NAME = " __crystal_raise_cast_failed"
14
+ MALLOC_NAME = " __crystal_malloc64"
15
+ MALLOC_ATOMIC_NAME = " __crystal_malloc_atomic64"
16
+ REALLOC_NAME = " __crystal_realloc64"
17
+ GET_EXCEPTION_NAME = " __crystal_get_exception"
18
+ ONCE_INIT = " __crystal_once_init"
19
+ ONCE = " __crystal_once"
19
20
20
21
class Program
21
22
def run (code, filename : String ? = nil , debug = Debug ::Default )
@@ -265,6 +266,7 @@ module Crystal
265
266
@malloc_atomic_fun : LLVMTypedFunction ?
266
267
@realloc_fun : LLVMTypedFunction ?
267
268
@raise_overflow_fun : LLVMTypedFunction ?
269
+ @raise_cast_failed_fun : LLVMTypedFunction ?
268
270
@c_malloc_fun : LLVMTypedFunction ?
269
271
@c_realloc_fun : LLVMTypedFunction ?
270
272
@@ -470,7 +472,7 @@ module Crystal
470
472
case node.name
471
473
when MALLOC_NAME , MALLOC_ATOMIC_NAME , REALLOC_NAME , RAISE_NAME ,
472
474
@codegen .personality_name, GET_EXCEPTION_NAME , RAISE_OVERFLOW_NAME ,
473
- ONCE_INIT , ONCE
475
+ RAISE_CAST_FAILED_NAME , ONCE_INIT , ONCE
474
476
@codegen .accept node
475
477
end
476
478
@@ -1488,11 +1490,7 @@ module Crystal
1488
1490
cond cmp, matches_block, doesnt_match_block
1489
1491
1490
1492
position_at_end doesnt_match_block
1491
-
1492
- temp_var_name = @program .new_temp_var_name
1493
- context.vars[temp_var_name] = LLVMVar .new(last_value, obj_type, already_loaded: true )
1494
- accept type_cast_exception_call(obj_type, to_type, node, temp_var_name)
1495
- context.vars.delete temp_var_name
1493
+ codegen_raise_cast_failed(type_id, to_type, node)
1496
1494
1497
1495
position_at_end matches_block
1498
1496
@last = downcast last_value, resulting_type, obj_type, true
@@ -1548,28 +1546,6 @@ module Crystal
1548
1546
false
1549
1547
end
1550
1548
1551
- def type_cast_exception_call (from_type, to_type, node, var_name)
1552
- pieces = [
1553
- StringLiteral .new(" Cast from " ).at(node),
1554
- Call .new(Var .new(var_name).at(node), " class" ).at(node),
1555
- StringLiteral .new(" to #{ to_type } failed" ).at(node),
1556
- ] of ASTNode
1557
-
1558
- if location = node.location
1559
- pieces << StringLiteral .new(" , at #{ location.expanded_location } :#{ location.line_number } " ).at(node)
1560
- end
1561
-
1562
- ex = Call .new(Path .global(" TypeCastError" ).at(node), " new" , StringInterpolation .new(pieces).at(node)).at(node)
1563
- call = Call .global(" raise" , ex).at(node)
1564
- call = @program .normalize(call)
1565
-
1566
- meta_vars = MetaVars .new
1567
- meta_vars[var_name] = MetaVar .new(var_name, type: from_type)
1568
- visitor = MainVisitor .new(@program , meta_vars)
1569
- @program .visit_main call, visitor: visitor
1570
- call
1571
- end
1572
-
1573
1549
def cant_pass_closure_to_c_exception_call
1574
1550
@cant_pass_closure_to_c_exception_call ||= begin
1575
1551
call = Call .global(" raise" , StringLiteral .new(" passing a closure to C is not allowed" )).at(UNKNOWN_LOCATION )
@@ -1579,6 +1555,63 @@ module Crystal
1579
1555
end
1580
1556
end
1581
1557
1558
+ def codegen_raise_cast_failed (type_id, to_type, node)
1559
+ location = node.location
1560
+ set_current_debug_location(location) if location && @debug .line_numbers?
1561
+
1562
+ func = crystal_raise_cast_failed_fun
1563
+ call_args = [
1564
+ cast_to_void_pointer(type_id_to_class_name(type_id)),
1565
+ cast_to_void_pointer(build_string_constant(to_type.to_s)),
1566
+ location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1567
+ ] of LLVM ::Value
1568
+
1569
+ if (rescue_block = @rescue_block )
1570
+ invoke_out_block = new_block " invoke_out"
1571
+ invoke func, call_args, invoke_out_block, rescue_block
1572
+ position_at_end invoke_out_block
1573
+ else
1574
+ call func, call_args
1575
+ end
1576
+
1577
+ unreachable
1578
+ end
1579
+
1580
+ def type_id_to_class_name (type_id )
1581
+ fun_name = " ~type_id_to_class_name"
1582
+ func = typed_fun?(@main_mod , fun_name) || create_type_id_to_class_name_fun(fun_name)
1583
+ func = check_main_fun fun_name, func
1584
+ call func, type_id
1585
+ end
1586
+
1587
+ # See also: `#create_metaclass_fun`
1588
+ def create_type_id_to_class_name_fun (name )
1589
+ in_main do
1590
+ define_main_function(name, [llvm_context.int32], llvm_type(@program .string)) do |func |
1591
+ set_internal_fun_debug_location(func, name)
1592
+
1593
+ arg = func.params.first
1594
+
1595
+ current_block = insert_block
1596
+
1597
+ cases = {} of LLVM ::Value => LLVM ::BasicBlock
1598
+ @program .llvm_id.@ids .each do |type , (_ , type_id )|
1599
+ block = new_block " type_#{ type_id } "
1600
+ cases[int32(type_id)] = block
1601
+ position_at_end block
1602
+ ret build_string_constant(type .to_s)
1603
+ end
1604
+
1605
+ otherwise = new_block " otherwise"
1606
+ position_at_end otherwise
1607
+ unreachable
1608
+
1609
+ position_at_end current_block
1610
+ @builder .switch arg, otherwise, cases
1611
+ end
1612
+ end
1613
+ end
1614
+
1582
1615
def visit (node : IsA )
1583
1616
codegen_type_filter node, & .filter_by(node.const.type)
1584
1617
end
@@ -2315,6 +2348,15 @@ module Crystal
2315
2348
end
2316
2349
end
2317
2350
2351
+ def crystal_raise_cast_failed_fun
2352
+ @raise_cast_failed_fun ||= typed_fun?(@main_mod , RAISE_CAST_FAILED_NAME )
2353
+ if raise_cast_failed_fun = @raise_cast_failed_fun
2354
+ check_main_fun RAISE_CAST_FAILED_NAME , raise_cast_failed_fun
2355
+ else
2356
+ raise Error .new(" Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it" )
2357
+ end
2358
+ end
2359
+
2318
2360
# Fallbacks to libc malloc and realloc when the expected __crystal_*
2319
2361
# functions aren't defined (e.g. empty prelude). We only use them in tests
2320
2362
# that don't require the prelude, so they don't require the GC.
0 commit comments