| The peformance issue is this bit in the evaluator:
def eval_CallMethodExpression(o, scope) |
unless o.functor_expr.is_a? Model::NamedAccessExpression |
fail(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function accessor', :container => o}) |
end |
receiver = unfold([], [o.functor_expr.left_expr], scope) |
name = o.functor_expr.right_expr |
unless name.is_a? Model::QualifiedName |
fail(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function name', :container => o}) |
end |
name = name.value # the string function name |
obj = receiver[0] |
receiver_type = Types::TypeCalculator.infer(obj) |
if receiver_type.is_a?(Types::TypeWithMembers) |
member = receiver_type[name] |
unless member.nil? |
args = unfold([], o.arguments || [], scope) |
return o.lambda.nil? ? member.invoke(obj, scope, args) : member.invoke(obj, scope, args, &proc_from_lambda(o.lambda, scope)) |
end |
end |
call_function_with_block(name, unfold(receiver, o.arguments || [], scope), o, scope) |
end
|
Line 13 in this snippet does a full inference to determine if the object has member attributes. For a very large facts hash, that is a very expensive operation. We need to quickly filter out values that we know cannot possibly have methods, and possibly also find a much faster way to determine if object has members that can be called. A very simple hack is to add:
unless obj.is_a?(Hash) || obj.is_a?(Array)
|
but we probably want to speed this up for all Scalar. Ping Thomas Hallgren - any thoughts on what would be the fastest here? This also brings up a possibility to cache type inference for larger data types... |