Skip to content

Commit

Permalink
Support exception handling on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
RX14 committed Aug 1, 2018
1 parent 8d28cbb commit 0e0e28a
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 149 deletions.
16 changes: 16 additions & 0 deletions spec/compiler/codegen/exception_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1285,4 +1285,20 @@ describe "Code gen: exception" do
end
)).to_string.should eq("foo")
end

it "codegens return from rescue with value" do
run(%(
require "prelude"
def foo
begin
raise "foo"
rescue
return 5
end
end
foo
)).to_i.should eq(5)
end
end
3 changes: 2 additions & 1 deletion spec/std/dir_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ describe "Dir" do
end
end

it "tests empty? on a directory path to a file" do
# TODO: do we even want this?
pending_win32 "tests empty? on a directory path to a file" do
ex = expect_raises(Errno, /Error determining size of/) do
Dir.empty?(datapath("dir", "f1.txt", "/"))
end
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/codegen/call.cr
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ class Crystal::CodeGenVisitor

if raises && (rescue_block = @rescue_block)
invoke_out_block = new_block "invoke_out"
@last = builder.invoke func, call_args, invoke_out_block, rescue_block
@last = invoke func, call_args, invoke_out_block, rescue_block
position_at_end invoke_out_block
else
@last = call func, call_args
Expand Down
23 changes: 21 additions & 2 deletions src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ module Crystal
MALLOC_NAME = "__crystal_malloc64"
MALLOC_ATOMIC_NAME = "__crystal_malloc_atomic64"
REALLOC_NAME = "__crystal_realloc64"
PERSONALITY_NAME = "__crystal_personality"
GET_EXCEPTION_NAME = "__crystal_get_exception"

class Program
Expand Down Expand Up @@ -97,6 +96,7 @@ module Crystal
getter llvm_typer : LLVMTyper
getter alloca_block : LLVM::BasicBlock
getter entry_block : LLVM::BasicBlock
getter personality_name : String
property last : LLVM::Value

class LLVMVar
Expand Down Expand Up @@ -129,6 +129,7 @@ module Crystal
@argv : LLVM::Value
@empty_md_list : LLVM::Value
@rescue_block : LLVM::BasicBlock?
@catch_pad : LLVM::Value?
@malloc_fun : LLVM::Function?
@malloc_atomic_fun : LLVM::Function?
@c_malloc_fun : LLVM::Function?
Expand Down Expand Up @@ -156,6 +157,15 @@ module Crystal
ret_type = @llvm_typer.llvm_return_type(@main_ret_type)
@main = @llvm_mod.functions.add(MAIN_NAME, [llvm_context.int32, llvm_context.void_pointer.pointer], ret_type)

if @program.has_flag? "windows"
@personality_name = "__CxxFrameHandler3"

personality_function = @llvm_mod.functions.add(@personality_name, [] of LLVM::Type, llvm_context.int32, true)
@main.personality_function = personality_function
else
@personality_name = "__crystal_personality"
end

emit_main_def_debug_metadata(@main, "??") unless @debug.none?

@context = Context.new @main, @program
Expand Down Expand Up @@ -282,7 +292,7 @@ module Crystal

def visit(node : FunDef)
case node.name
when MALLOC_NAME, MALLOC_ATOMIC_NAME, REALLOC_NAME, RAISE_NAME, PERSONALITY_NAME, GET_EXCEPTION_NAME
when MALLOC_NAME, MALLOC_ATOMIC_NAME, REALLOC_NAME, RAISE_NAME, @codegen.personality_name, GET_EXCEPTION_NAME
@codegen.accept node
end
false
Expand Down Expand Up @@ -613,6 +623,12 @@ module Crystal

if return_phi = context.return_phi
return_phi.add @last, node_type
elsif catch_pad = @catch_pad
ret_block = new_block "catchret_ret"
builder.build_catch_ret catch_pad, ret_block

position_at_end ret_block
codegen_return node_type
else
codegen_return node_type
end
Expand Down Expand Up @@ -1518,6 +1534,7 @@ module Crystal
old_fun = context.fun
old_ensure_exception_handlers = @ensure_exception_handlers
old_rescue_block = @rescue_block
old_catch_pad = @catch_pad
old_entry_block = @entry_block
old_alloca_block = @alloca_block
old_needs_value = @needs_value
Expand All @@ -1528,6 +1545,7 @@ module Crystal

@ensure_exception_handlers = nil
@rescue_block = nil
@catch_pad = nil

block_value = yield

Expand All @@ -1539,6 +1557,7 @@ module Crystal
@llvm_typer = old_llvm_typer
@ensure_exception_handlers = old_ensure_exception_handlers
@rescue_block = old_rescue_block
@catch_pad = old_catch_pad
@entry_block = old_entry_block
@alloca_block = old_alloca_block
@needs_value = old_needs_value
Expand Down
14 changes: 12 additions & 2 deletions src/compiler/crystal/codegen/crystal_llvm_builder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,14 @@ module Crystal
value
end

def printf(format, args = [] of LLVM::Value)
call @printf, [global_string_pointer(format)] + args
def printf(format, args = [] of LLVM::Value, catch_pad = nil)
if catch_pad
funclet = build_operand_bundle_def("funclet", [catch_pad])
else
funclet = LLVM::OperandBundleDef.null
end

call @printf, [global_string_pointer(format)] + args, bundle: funclet
end

def position_at_end(block)
Expand All @@ -54,6 +60,10 @@ module Crystal
@builder.insert_block
end

def build_operand_bundle_def(name, values : Array(LLVM::Value))
@builder.build_operand_bundle_def(name, values)
end

def to_unsafe
@builder.to_unsafe
end
Expand Down
Loading

0 comments on commit 0e0e28a

Please sign in to comment.