is to call another function. Like a class wrapper or decorator, a thunk is used to computer things (conversions, log, etc) before or after a function call. It's an intermediary between the caller and the callee.
The most basic use of a thunk is to unbox its argument before invoking the real callee. Virtual functions are a use case of thunk function:
redef class Object
fun toto(x: Int): Int do return 1 + x
end
redef class Int
redef fun toto(x) do return x + self
end
long Object__toto(val self, long x) { return 1 + x } long Inttoto(long self, long x) { return x + self } long THUNK_Inttoto(val self, long x) {
long self2 = (long)(self)>>2 // Unboxing from Object to Int
return Int_toto(self2, x)
}
A thunk has its OWN SIGNATURE and is considered like any other AbstractRuntimeFunction
.
Thus, one might need to be careful when overriding parent's method. Since most usage of
thunks in Nit is to unbox and box things between a caller and a callee, the default
implementation is doing just that. In other words, a thunk takes a signature and a method
and tries to cast its signature to the underlying method's signature.
A virtual function has the same signature as its mmethoddef
field, except for
its receiver is of type Object
.
In the same vibe, a call reference has all of its argument boxed as Object
.
nitc :: ThunkFunction :: _polymorph_call_flag
Determines if the callsite should be polymorphic or static.nitc :: ThunkFunction :: defaultinit
nitc :: ThunkFunction :: polymorph_call_flag
Determines if the callsite should be polymorphic or static.nitc :: ThunkFunction :: polymorph_call_flag=
Determines if the callsite should be polymorphic or static.nitc :: ThunkFunction :: target_recv
The type expected by the callee. Used to resolvemmethoddef
's formal
nitc $ ThunkFunction :: SELF
Type of this instance, automatically specialized in every classnitc $ ThunkFunction :: body_to_c
Generate the code for the body without return statement at the end andnitc :: AbstractRuntimeFunction :: _mmethoddef
The associated Nit methodnitc :: ThunkFunction :: _polymorph_call_flag
Determines if the callsite should be polymorphic or static.nitc :: AbstractRuntimeFunction :: body_to_c
Generate the code for the body without return statement at the end andnitc :: AbstractRuntimeFunction :: build_c_name
Non cached version ofc_name
nitc :: AbstractRuntimeFunction :: build_frame
Builds the static frame for current runtime methodnitc :: AbstractRuntimeFunction :: c_name
The mangled c name of the runtime_functionnitc :: AbstractRuntimeFunction :: c_ref
nitc :: AbstractRuntimeFunction :: call
Implements a call of the runtime_functioncore :: Object :: class_factory
Implementation used byget_class
to create the specific class.
nitc :: AbstractRuntimeFunction :: compile_to_c
Generate the codenitc :: AbstractRuntimeFunction :: declare_signature
How the concrete compiler will declare the method, e.g inside a global header file,nitc :: ThunkFunction :: defaultinit
core :: Object :: defaultinit
nitc :: AbstractRuntimeFunction :: end_compile_to_c
Hook called at the end ofcompile_to_c
function. This function
nitc :: AbstractRuntimeFunction :: fill_parameters
Fills the argument array inside v.frame.arguments, callingresolve_ith_parameter
nitc :: AbstractRuntimeFunction :: has_return
Returnstrue
if the associated mmethoddef
's return type isn't null,
core :: Object :: is_same_instance
Return true ifself
and other
are the same instance (i.e. same identity).
core :: Object :: is_same_serialized
Isself
the same as other
in a serialization context?
core :: Object :: is_same_type
Return true ifself
and other
have the same dynamic type.
nitc :: AbstractRuntimeFunction :: mmethoddef=
The associated Nit methodnitc :: AbstractRuntimeFunction :: msignature
The current msignature to use when compiling :signature_to_c
and body_to_c
.
core :: Object :: native_class_name
The class name of the object in CString format.core :: Object :: output_class_name
Display class name on stdout (debug only).nitc :: ThunkFunction :: polymorph_call_flag
Determines if the callsite should be polymorphic or static.nitc :: ThunkFunction :: polymorph_call_flag=
Determines if the callsite should be polymorphic or static.nitc :: AbstractRuntimeFunction :: recv_mtype
The current receiver type to compile :signature_to_c
and body_to_c
.
nitc :: AbstractRuntimeFunction :: resolve_ith_parameter
Step 4 : CreatesRuntimeVariable
for each method argument.
nitc :: AbstractRuntimeFunction :: resolve_receiver
Prepare theself
runtime variable to be used by the rest of
nitc :: AbstractRuntimeFunction :: resolve_return_mtype
Step 3 : Returns the return type used by the runtime function.nitc :: AbstractRuntimeFunction :: signature_to_c
Generate the code for the signature with an open curly bracenitc :: ThunkFunction :: target_recv
The type expected by the callee. Used to resolvemmethoddef
's formal
nitc :: AbstractRuntimeFunction
A C function associated to a Nit methodnitc :: CustomizedThunkFunction
Thunk implementation for global compiler.
# Base class for all thunk-like function. A thunk is a function whose purpose
# is to call another function. Like a class wrapper or decorator, a thunk is used
# to computer things (conversions, log, etc) before or after a function call. It's
# an intermediary between the caller and the callee.
#
# The most basic use of a thunk is to unbox its argument before invoking the real callee.
# Virtual functions are a use case of thunk function:
#
# ~~~~nitish
# redef class Object
# fun toto(x: Int): Int do return 1 + x
# end
# redef class Int
# redef fun toto(x) do return x + self
# end
#
# ```generated C code
# long Object__toto(val* self, long x) { return 1 + x }
# long Int__toto(long self, long x) { return x + self }
# long THUNK_Int__toto(val* self, long x) {
# long self2 = (long)(self)>>2 // Unboxing from Object to Int
# return Int_toto(self2, x)
# }
#
# ```
# ~~~~
#
# A thunk has its OWN SIGNATURE and is considered like any other `AbstractRuntimeFunction`.
# Thus, one might need to be careful when overriding parent's method. Since most usage of
# thunks in Nit is to unbox and box things between a caller and a callee, the default
# implementation is doing just that. In other words, a thunk takes a signature and a method
# and tries to cast its signature to the underlying method's signature.
#
# A virtual function has the same signature as its `mmethoddef` field, except for
# its receiver is of type `Object`.
# In the same vibe, a call reference has all of its argument boxed as `Object`.
abstract class ThunkFunction
super AbstractRuntimeFunction
# Determines if the callsite should be polymorphic or static.
var polymorph_call_flag = false is writable
# The type expected by the callee. Used to resolve `mmethoddef`'s formal
# parameters and virtual type. This type must NOT need anchor.
fun target_recv: MType is abstract
redef fun body_to_c(v)
do
assert not target_recv.need_anchor
var frame = v.frame
assert frame != null
var selfvar = frame.selfvar
var arguments = frame.arguments
var arguments2 = new Array[RuntimeVariable]
arguments2.push(v.autobox(selfvar, target_recv))
var resolved_sig = msignature.resolve_for(target_recv, target_recv.as(MClassType), v.mmodule, true)
for i in [0..resolved_sig.arity[ do
var param = resolved_sig.mparameters[i]
var mtype = param.mtype
if param.is_vararg then
mtype = v.mmodule.array_type(mtype)
end
var temp = v.autobox(arguments[i+1], mtype)
arguments2.push(temp)
end
v.add("/* {mmethoddef}, {recv_mtype.ctype} */")
var subret: nullable RuntimeVariable = null
if polymorph_call_flag then
subret = v.send(mmethoddef.mproperty, arguments2)
else
subret = v.call(mmethoddef, arguments2[0].mcasttype.as(MClassType), arguments2)
end
if has_return then
assert subret != null
var subret2 = v.autobox(subret, return_mtype.as(not null))
v.assign(frame.returnvar.as(not null), subret2)
end
end
end
src/compiler/abstract_compiler.nit:2267,1--2347,3