# The list of all associated files
# Used to generate .c files
- var files = new List[CodeFile]
+ var files = new Array[CodeFile]
# Initialize a visitor specific for a compiler engine
fun new_visitor: VISITOR is abstract
self.header.add_decl("#include <stdlib.h>")
self.header.add_decl("#include <stdio.h>")
self.header.add_decl("#include <string.h>")
+ # longjmp !
+ self.header.add_decl("#include <setjmp.h>\n")
self.header.add_decl("#include <sys/types.h>\n")
self.header.add_decl("#include <unistd.h>\n")
self.header.add_decl("#include <stdint.h>\n")
compile_header_structs
compile_nitni_structs
+ compile_catch_stack
var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value
if gccd_disable.has("noreturn") or gccd_disable.has("all") then
self.header.add_decl("extern val *glob_sys;")
end
+ # Stack stocking environment for longjumps
+ protected fun compile_catch_stack do
+ self.header.add_decl """
+struct catch_stack_t {
+ int cursor;
+ jmp_buf envs[100];
+};
+extern struct catch_stack_t catchStack;
+"""
+ end
+
# Declaration of structures for live Nit types
protected fun compile_header_structs is abstract
v.add_decl("int glob_argc;")
v.add_decl("char **glob_argv;")
v.add_decl("val *glob_sys;")
+ v.add_decl("struct catch_stack_t catchStack;")
if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then
for tag in count_type_test_tags do
v.add("signal(SIGPIPE, SIG_IGN);")
v.add("glob_argc = argc; glob_argv = argv;")
+ v.add("catchStack.cursor = -1;")
v.add("initialize_gc_option();")
v.add "initialize_nitni_global_refs();"
# Where to store generated lines
class CodeWriter
var file: CodeFile
- var lines: List[String] = new List[String]
- var decl_lines: List[String] = new List[String]
+ var lines = new Array[String]
+ var decl_lines = new Array[String]
# Add a line in the main part of the generated C
fun add(s: String) do self.lines.add(s)
do
mtype = self.anchor(mtype)
var valmtype = value.mcasttype
+
+ # Do nothing if useless autocast
if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
return value
end
+ # Just as_not_null if the target is not nullable.
+ #
+ # eg `nullable PreciseType` adapted to `Object` gives precisetype.
if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
- var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
- return res
- else
- var res = new RuntimeVariable(value.name, valmtype, mtype)
- return res
+ mtype = valmtype.mtype
end
+
+ var res = new RuntimeVariable(value.name, value.mtype, mtype)
+ return res
end
# Generate a super call from a method definition
# Checks
+ # Can value be null? (according to current knowledge)
+ fun maybenull(value: RuntimeVariable): Bool
+ do
+ return value.mcasttype isa MNullableType or value.mcasttype isa MNullType
+ end
+
# Add a check and an abort for a null receiver if needed
fun check_recv_notnull(recv: RuntimeVariable)
do
if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return
- var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
- if maybenull then
+ if maybenull(recv) then
self.add("if (unlikely({recv} == NULL)) \{")
self.add_abort("Receiver is null")
self.add("\}")
# used by aborts, asserts, casts, etc.
fun add_abort(message: String)
do
+ self.add("if(catchStack.cursor >= 0)\{")
+ self.add("longjmp(catchStack.envs[catchStack.cursor], 1);")
+ self.add("\}")
self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");")
add_raw_abort
end
assert arguments.length == 2
var recv = arguments.first
var arg = arguments[1]
- if is_optional then
+ if is_optional and v.maybenull(arg) then
var value = v.new_var(self.mpropdef.static_mtype.as(not null))
v.add("if ({arg} == NULL) \{")
v.assign(value, evaluate_expr(v, recv))
fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
do
- if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
+ if has_value and not is_lazy and not is_optional and not n_expr isa ANullExpr then evaluate_expr(v, recv)
end
# Evaluate, store and return the default value of the attribute
redef class ADoExpr
redef fun stmt(v)
do
- v.stmt(self.n_block)
- v.add_escape_label(break_mark)
+ if self.n_catch != null then
+ v.add("catchStack.cursor += 1;")
+ v.add("if(!setjmp(catchStack.envs[catchStack.cursor]))\{")
+ v.stmt(self.n_block)
+ v.add("catchStack.cursor -= 1;")
+ v.add("\}else \{")
+ v.add("catchStack.cursor -= 1;")
+ v.stmt(self.n_catch)
+ v.add("\}")
+ else
+ v.stmt(self.n_block)
+ end
+ v.add_escape_label(break_mark)
end
end
do
var res = v.new_var(self.mtype.as(not null))
var i1 = v.expr(self.n_expr, null)
+
+ if not v.maybenull(i1) then return i1
+
v.add("if ({i1}!=NULL) \{")
v.assign(res, i1)
v.add("\} else \{")
var i = v.expr(self.n_expr, null)
if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
- if i.mtype.is_c_primitive then return i
+ if not v.maybenull(i) then return i
v.add("if (unlikely({i} == NULL)) \{")
v.add_abort("Cast failed")
return v.native_array_instance(elttype, l)
end
- var recv = v.init_instance_or_extern(mtype)
-
var callsite = self.callsite
- if callsite == null then return recv
+ if callsite == null then return v.init_instance_or_extern(mtype)
if callsite.is_broken then return null
+ var recv
+ # new factories are badly implemented.
+ # They assume a stub temporary receiver exists.
+ # This temporary receiver is required because it
+ # currently holds the method and the formal types.
+ #
+ # However, this object could be reused if the formal types are the same.
+ # Therefore, the following code will `once` it in these case
+ if callsite.mproperty.is_new and not mtype.need_anchor then
+ var name = v.get_name("varoncenew")
+ var guard = v.get_name(name + "_guard")
+ v.add_decl("static {mtype.ctype} {name};")
+ v.add_decl("static int {guard};")
+ recv = v.new_var(mtype)
+ v.add("if (likely({guard})) \{")
+ v.add("{recv} = {name};")
+ v.add("\} else \{")
+ var i = v.init_instance_or_extern(mtype)
+ v.add("{recv} = {i};")
+ v.add("{name} = {recv};")
+ v.add("{guard} = 1;")
+ v.add("\}")
+ else
+ recv = v.init_instance_or_extern(mtype)
+ end
+
var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
var res2 = v.compile_callsite(callsite, args)
if res2 != null then