Use CallSite to resolve and type some implicit services.
Subsequent phases will like them!
Currenlty: all the AFor and ARange services are converted and tools updated.
TODO: Array and SuperString
Pull-Request: #370
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
# Return a new native string initialized with `txt`
fun native_string_instance(txt: String): Instance
do
- var val = new Buffer.from(txt)
+ var val = new FlatBuffer.from(txt)
val.add('\0')
var ic = self.mainmodule.get_primitive_class("NativeString")
return new PrimitiveInstance[Buffer](ic.mclass_type, val)
# Return a stack stace. One line per function
fun stack_trace: String
do
- var b = new Buffer
+ var b = new FlatBuffer
b.append(",---- Stack trace -- - - -\n")
for f in frames do
b.append("| {f.mpropdef} ({f.current_node.location})\n")
return null
else if pname == "copy_to" then
# sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
- var destval = args[1].val.as(Buffer)
+ var destval = args[1].val.as(FlatBuffer)
var lenval = args[2].to_i
var fromval = args[3].to_i
var toval = args[4].to_i
if toval + lenval >= destval.length then
debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
end
- recvval.copy(fromval, lenval, destval, toval)
+ recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
return null
else if pname == "atoi" then
return v.int_instance(recvval.to_i)
var recvval = args.first.val
if pname == "io_write" then
var a1 = args[1].val.as(Buffer)
- recvval.as(OStream).write(a1.substring(0, args[2].to_i))
+ recvval.as(OStream).write(a1.substring(0, args[2].to_i).to_s)
return args[2]
else if pname == "io_read" then
var str = recvval.as(IStream).read(args[2].to_i)
var a1 = args[1].val.as(Buffer)
- new Buffer.from(str).copy(0, str.length, a1, 0)
+ new FlatBuffer.from(str).copy(0, str.length, a1.as(FlatBuffer), 0)
return v.int_instance(str.length)
else if pname == "io_close" then
recvval.as(IOS).close
if col.mtype isa MNullType then fatal(v, "Receiver is null")
#self.debug("col {col}")
- var iter = v.send(v.force_get_primitive_method("iterator", col.mtype), [col]).as(not null)
+ var iter = v.callsite(method_iterator, [col]).as(not null)
#self.debug("iter {iter}")
loop
- var isok = v.send(v.force_get_primitive_method("is_ok", iter.mtype), [iter]).as(not null)
+ var isok = v.callsite(method_is_ok, [iter]).as(not null)
if not isok.is_true then return
if self.variables.length == 1 then
- var item = v.send(v.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
+ var item = v.callsite(method_item, [iter]).as(not null)
#self.debug("item {item}")
v.frame.map[self.variables.first] = item
else if self.variables.length == 2 then
- var key = v.send(v.force_get_primitive_method("key", iter.mtype), [iter]).as(not null)
+ var key = v.callsite(method_key, [iter]).as(not null)
v.frame.map[self.variables[0]] = key
- var item = v.send(v.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
+ var item = v.callsite(method_item, [iter]).as(not null)
v.frame.map[self.variables[1]] = item
else
abort
if v.is_break(self.escapemark) then return
v.is_continue(self.escapemark) # Clear the break
if v.is_escaping then return
- v.send(v.force_get_primitive_method("next", iter.mtype), [iter])
+ v.callsite(method_next, [iter])
end
end
end
var mtype = v.unanchor_type(self.mtype.as(not null))
var res = new MutableInstance(mtype)
v.init_instance(res)
- v.send(v.force_get_primitive_method("init", mtype), [res, e1, e2])
+ v.callsite(init_callsite, [res, e1, e2])
return res
end
end
var mtype = v.unanchor_type(self.mtype.as(not null))
var res = new MutableInstance(mtype)
v.init_instance(res)
- v.send(v.force_get_primitive_method("without_last", mtype), [res, e1, e2])
+ v.callsite(init_callsite, [res, e1, e2])
return res
end
end
import csv # for live_types_to_csv
import ordered_tree # for live_methods_to_tree
+private import more_collections
+
redef class ModelBuilder
fun do_rapid_type_analysis(mainmodule: MModule): RapidTypeAnalysis
do
# Live methods.
var live_methods = new HashSet[MMethod]
+ # Live callsites.
+ var live_callsites = new HashSet[CallSite]
+
+ private var live_targets_cache = new HashMap2[MType, MProperty, Set[MMethodDef]]
+
+ # The live targets of a specific callsite.
+ fun live_targets(callsite: CallSite): Set[MMethodDef]
+ do
+ var mtype = callsite.recv
+ var anchor = callsite.anchor
+ if anchor != null then mtype = mtype.anchor_to(callsite.mmodule, anchor)
+ if mtype isa MNullableType then mtype = mtype.mtype
+ assert mtype isa MClassType
+ mtype = mtype.mclass.intro.bound_mtype
+ var mproperty = callsite.mproperty
+ var res = live_targets_cache[mtype, mproperty]
+ if res != null then return res
+ res = new ArraySet[MMethodDef]
+ live_targets_cache[mtype, mproperty] = res
+
+ for c in live_classes do
+ var tc = c.intro.bound_mtype
+ if not tc.is_subtype(mainmodule, null, mtype) then continue
+ var d = mproperty.lookup_first_definition(mainmodule, tc)
+ res.add d
+ end
+
+ return res
+ end
+
# Live call-to-super.
var live_super_sends = new HashSet[MMethodDef]
fun add_cast_type(mtype: MType) do analysis.add_cast(mtype)
- fun add_callsite(callsite: nullable CallSite) do if callsite != null then analysis.add_send(callsite.recv, callsite.mproperty)
+ fun add_callsite(callsite: nullable CallSite) do if callsite != null then
+ analysis.add_send(callsite.recv, callsite.mproperty)
+ analysis.live_callsites.add(callsite)
+ end
end
###
do
var mtype = self.mtype.as(MClassType)
v.add_type(mtype)
- var prop = v.get_method(mtype, "init")
- v.add_monomorphic_send(mtype, prop)
+ v.add_callsite(init_callsite)
end
end
do
var mtype = self.mtype.as(MClassType)
v.add_type(mtype)
- var prop = v.get_method(mtype, "without_last")
- v.add_monomorphic_send(mtype, prop)
+ v.add_callsite(init_callsite)
end
end
redef class AForExpr
redef fun accept_rapid_type_visitor(v)
do
- var recvtype = self.n_expr.mtype.as(not null)
- var colltype = self.coltype.as(not null)
- var itmeth = v.get_method(colltype, "iterator")
- v.add_send(recvtype, itmeth)
- var iteratortype = itmeth.intro.msignature.return_mtype.as(MClassType).mclass.intro.bound_mtype
- var objtype = v.get_class("Object").mclass_type
- v.add_send(objtype, v.get_method(iteratortype, "is_ok"))
+ v.add_callsite(self.method_iterator)
+ v.add_callsite(self.method_is_ok)
if self.variables.length == 1 then
- v.add_send(objtype, v.get_method(iteratortype, "item"))
+ v.add_callsite(self.method_item)
else if self.variables.length == 2 then
- v.add_send(objtype, v.get_method(iteratortype, "key"))
- v.add_send(objtype, v.get_method(iteratortype, "item"))
+ v.add_callsite(self.method_key)
+ v.add_callsite(self.method_item)
else
abort
end
- v.add_send(objtype, v.get_method(iteratortype, "next"))
+ v.add_callsite(self.method_next)
end
end
end
assert mproperty isa MMethod
- if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility then
- self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self. {mproperty.intro_mclassdef.mmodule.visibility_for(self.mmodule)}")
+ if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility and not modelbuilder.toolcontext.opt_ignore_visibility.value then
+ self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self.")
return null
end
end
end
- var callsite = new CallSite(node, recvtype, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+ var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
return callsite
end
# The assiciated node for location
var node: ANode
- # The statis type of the receiver
+ # The static type of the receiver (possibly unresolved)
var recv: MType
+ # The module where the callsite is present
+ var mmodule: MModule
+
+ # The anchor to use with `recv` or `msignature`
+ var anchor: nullable MClassType
+
# Is the receiver self?
# If "for_self", virtual types of the signature are keeped
# If "not_for_self", virtual type are erased
redef class AForExpr
var coltype: nullable MClassType
- var method_iterator: nullable MMethod
- var method_is_ok: nullable MMethod
- var method_item: nullable MMethod
- var method_next: nullable MMethod
- var method_key: nullable MMethod
+ var method_iterator: nullable CallSite
+ var method_is_ok: nullable CallSite
+ var method_item: nullable CallSite
+ var method_next: nullable CallSite
+ var method_key: nullable CallSite
private fun do_type_iterator(v: TypeVisitor, mtype: MType)
do
if objcla == null then return
# check iterator method
- var unsafe_type = v.anchor_to(mtype)
- if v.try_get_mproperty_by_name2(self, unsafe_type, "iterator") == null then
- if v.try_get_mproperty_by_name2(self, unsafe_type, "iterate") == null then
- v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
- else
- v.modelbuilder.error(self, "NOT YET IMPLEMENTED: Do 'for' on {mtype}")
- end
- return
- end
-
var itdef = v.get_method(self, mtype, "iterator", true)
if itdef == null then
v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
return
end
- self.method_iterator = itdef.mproperty
+ self.method_iterator = itdef
# check that iterator return something
var ittype = itdef.msignature.return_mtype
v.error(self, "Type Error: 'for' expects a method 'is_ok' in 'Iterator' type {ittype}.")
return
end
- self.method_is_ok = ikdef.mproperty
+ self.method_is_ok = ikdef
var itemdef = v.get_method(self, ittype, "item", false)
if itemdef == null then
v.error(self, "Type Error: 'for' expects a method 'item' in 'Iterator' type {ittype}.")
return
end
- self.method_item = itemdef.mproperty
+ self.method_item = itemdef
var nextdef = v.get_method(self, ittype, "next", false)
if nextdef == null then
v.error(self, "Type Error: 'for' expects a method 'next' in 'Iterator' type {ittype}.")
return
end
- self.method_next = nextdef.mproperty
+ self.method_next = nextdef
if is_map then
var keydef = v.get_method(self, ittype, "key", false)
v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
return
end
- self.method_key = keydef.mproperty
+ self.method_key = keydef
end
end
end
redef class ARangeExpr
+ var init_callsite: nullable CallSite
+
redef fun accept_typing(v)
do
var discrete_class = v.get_mclass(self, "Discrete")
if t1 == null or t2 == null then return
var mclass = v.get_mclass(self, "Range")
if mclass == null then return # Forward error
+ var mtype
if v.is_subtype(t1, t2) then
- self.mtype = mclass.get_mtype([t2])
+ mtype = mclass.get_mtype([t2])
else if v.is_subtype(t2, t1) then
- self.mtype = mclass.get_mtype([t1])
+ mtype = mclass.get_mtype([t1])
else
v.error(self, "Type Error: Cannot create range: {t1} vs {t2}")
+ return
+ end
+
+ self.mtype = mtype
+
+ # get the constructor
+ var callsite
+ if self isa ACrangeExpr then
+ callsite = v.get_method(self, mtype, "init", false)
+ else if self isa AOrangeExpr then
+ callsite = v.get_method(self, mtype, "without_last", false)
+ else
+ abort
end
+ init_callsite = callsite
end
end
end
var msignature = v.resolve_signature_for(superprop, recvtype, true)
- var callsite = new CallSite(self, recvtype, true, superprop.mproperty, superprop, msignature, false)
+ var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
self.callsite = callsite
var args = self.n_args.to_a