rename typed_method to callable_method

seems to make the essence clearer
also extracted base class
This commit is contained in:
Torsten Ruger 2018-07-07 09:11:09 +03:00
parent acd5cd8f30
commit 9005513368
28 changed files with 146 additions and 142 deletions

View File

@ -69,7 +69,7 @@ module Arm
ArmMachine.mov( :pc , code.register)
end
def translate_DynamicJump(code)
index = Parfait.object_space.get_class_by_name(:TypedMethod).instance_type.variable_index(:binary)
index = Parfait.object_space.get_class_by_name(:CallableMethod).instance_type.variable_index(:binary)
codes = ArmMachine.ldr( code.register , code.register , arm_index(index) )
codes << ArmMachine.mov( :pc , code.register)
codes

View File

@ -35,12 +35,12 @@ module Mom
# but also used directly in __init
def build_with(builder)
case from = method_source
when Parfait::TypedMethod
builder.build { typed_method << from }
when Parfait::CallableMethod
builder.build { callable_method << from }
when Parfait::CacheEntry
builder.build do
cache_entry << from
typed_method << cache_entry[:cached_method]
callable_method << cache_entry[:cached_method]
end
else
raise "unknown source #{method_source}"
@ -64,15 +64,15 @@ module Mom
message[:next_message] << next_message
next_message[:caller] << message
type << typed_method[:arguments_type]
type << callable_method[:arguments_type]
named_list << next_message[:arguments]
named_list[:type] << type
type << typed_method[:frame_type]
type << callable_method[:frame_type]
named_list << next_message[:frame]
named_list[:type] << type
name << typed_method[:name]
name << callable_method[:name]
next_message[:name] << name
#store next.next back into space

View File

@ -41,28 +41,28 @@ module Mom
cache_entry << cache_entry_
type << cache_entry[:cached_type]
typed_method << type[:methods]
callable_method << type[:methods]
add_code while_start_label
space << Parfait.object_space
space << space[:nil_object]
space - typed_method
space - callable_method
if_zero exit_label
name << typed_method[:name]
name << callable_method[:name]
name - word
if_zero ok_label
typed_method << typed_method[:next_method]
callable_method << callable_method[:next]
branch while_start_label
add_code exit_label
Risc::Builtin::Object.emit_syscall( builder , :exit )
add_code ok_label
cache_entry[:cached_method] << typed_method
cache_entry[:cached_method] << callable_method
end
return builder.built
end

View File

@ -10,7 +10,8 @@ require_relative "parfait/class"
require_relative "parfait/list"
require_relative "parfait/word"
require_relative "parfait/binary_code"
require_relative "parfait/typed_method"
require_relative "parfait/callable"
require_relative "parfait/callable_method"
require_relative "parfait/vool_method"
require_relative "parfait/dictionary"
require_relative "parfait/type"

View File

@ -2,7 +2,7 @@
# we resolve the method at runtime, and then cache it. Aaron has shown that over 99%
# of call sites are type stable, so one cache entry at the moment
#
# A cache entry stores the type of the object and the TypedMethod that is to be called
# A cache entry stores the type of the object and the CallableMethod that is to be called
# This is used in DynamicCall, see there
#
module Parfait

View File

@ -8,11 +8,12 @@ module Parfait
# - frame_type: A type object describing the local variables that the method has
# - binary: The binary (jumpable) code that instructions get assembled into
# - blocks: linked list of blocks inside this method/block
# - next: next block/method at same level
#
class Callable < Object
attr_reader :self_type , :arguments_type , :frame_type , :binary , :blocks
attr_reader :self_type , :arguments_type , :frame_type , :binary
attr_reader :blocks, :next
def initialize( self_type , arguments_type , frame_type)
super()
raise "No class #{self}" unless self_type
@ -53,5 +54,10 @@ module Parfait
bin = bin.next
end
end
def set_next( method )
@next = method
end
end
end

View File

@ -0,0 +1,40 @@
# A CallableMethod is static object that primarily holds the executable code.
# It is callable through it's binary code
# Additionally to the base class it has a name
#
# It's relation to the method a ruby programmer knows (called VoolMethod) is many to one,
# meaning one VoolMethod (untyped) has many CallableMethod implementations.
# The VoolMethod only holds vool code, no binary.
module Parfait
class CallableMethod < Callable
attr_reader :name
def initialize( self_type , name , arguments_type , frame_type)
@name = name
super(self_type , arguments_type , frame_type)
end
def ==(other)
return false unless other.is_a?(CallableMethod)
return false if @name != other.name
super
end
def rxf_reference_name
"Method: " + @name.to_s
end
def inspect
"#{@self_type.object_class.name}:#{name}(#{arguments_type.inspect})"
end
def each_method( &block )
block.call( self )
@next.each_method( &block ) if @next
end
end
end

View File

@ -12,7 +12,7 @@
# An Object carries the data for the instance variables it has.
# The Type lists the names of the instance variables
# The Class keeps a list of instance methods, these have a name and (vool) code
# Each type in turn has a list of TypedMethods that hold binary code
# Each type in turn has a list of CallableMethods that hold binary code
module Parfait
class Class < Object

View File

@ -87,12 +87,12 @@ module Parfait
found.init(arguments , frame)
return found
else
add_method TypedMethod.new( self , method_name , arguments , frame )
add_method CallableMethod.new( self , method_name , arguments , frame )
end
end
def add_method( method )
raise "not a method #{method.class} #{method.inspect}" unless method.is_a? TypedMethod
raise "not a method #{method.class} #{method.inspect}" unless method.is_a? CallableMethod
raise "syserr #{method.name.class}" unless method.name.is_a? Symbol
if self.is_a?(Class) and (method.self_type != self)
raise "Adding to wrong class, should be #{method.for_class}"
@ -109,16 +109,16 @@ module Parfait
def remove_method( method_name )
raise "No such method #{method_name} in #{self.name}" unless @methods
if( @methods.name == method_name)
@methods = @methods.next_method
@methods = @methods.next
return true
end
method = @methods
while(method && method.next_method)
if( method.next_method.name == method_name)
method.set_next( method.next_method.next_method )
while(method && method.next)
if( method.next.name == method_name)
method.set_next( method.next.next )
return true
else
method = method.next_method
method = method.next
end
end
raise "No such method #{method_name} in #{self.name}"
@ -144,6 +144,7 @@ module Parfait
return method if method
sup = object_class.super_class
return nil unless sup
return nil if object_class.name == :Object
sup.instance_type.resolve_method(fname)
end

View File

@ -1,53 +0,0 @@
require_relative "callable"
# A TypedMethod is static object that primarily holds the executable code.
# It is called typed, because all arguments and variables it uses are "typed",
# that is to say the names are known and form a type (not that the types of the
# variables are known). The object's type is known too, which means all instances
# variable names are known (not their respective type).
# It's relation to the method a ruby programmer knows (called VoolMethod) is many to one,
# meaning one VoolMethod (untyped) has many TypedMethod implementations.
# The VoolMethod only holds vool code, no binary.
# The Typed method has the following instance variables
# - name : This is the same as the ruby method name it implements
# - binary: The binary (jumpable) code that the instructions get assembled into
# - arguments_type: A type object describing the arguments (name+types) to be passed
# - frame_type: A type object describing the local variables that the method has
# - self_type: The Type the Method is for
module Parfait
class TypedMethod < Callable
attr_reader :name , :next_method
def initialize( self_type , name , arguments_type , frame_type)
@name = name
super(self_type , arguments_type , frame_type)
end
def ==(other)
return false unless other.is_a?(TypedMethod)
return false if @name != other.name
super
end
def rxf_reference_name
"Method: " + @name.to_s
end
def inspect
"#{@self_type.object_class.name}:#{name}(#{arguments_type.inspect})"
end
def each_method( &block )
block.call( self )
next_method.each_method( &block ) if next_method
end
def set_next( method )
@next_method = method
end
end
end

View File

@ -5,7 +5,7 @@ module Parfait
# Type objects are already created for args and locals, but the main attribute
# is the source, which is a Vool::Statement
#
# Classes store VoolMethods, while Types store TypedMethod
# Classes store VoolMethods, while Types store CallableMethod
# A Type referes to a Class , but a Class (interface) is implemented by many types
# as it changes during the course of it's life. Types do not change. Objects have
# type, and so only indirectly a class.
@ -23,14 +23,14 @@ module Parfait
raise "Empty bod" if(source.is_a?(Vool::Statements) and source.empty?)
end
def create_typed_method( type )
def create_callable_method( type )
raise "create_method #{type.inspect} is not a Type" unless type.is_a? Parfait::Type
type.create_method( @name , @args_type , @frame_type)
end
def compiler_for(self_type)
typed_method = create_typed_method(self_type)
compiler = Risc::MethodCompiler.new( typed_method )
callable_method = create_callable_method(self_type)
compiler = Risc::MethodCompiler.new( callable_method )
head = source.to_mom( compiler )
compiler.add_mom(head)
compiler

View File

@ -6,7 +6,7 @@ It is the other side of the parfait coin, part of the runtime.
The functions are organised by their respective classes and get loaded in boot_classes! ,
right at the start. (see register/boot.rb)
These functions return their code, ie a Parfait::TypedMethod with a MethodSource object,
These functions return their code, ie a Parfait::CallableMethod with a MethodSource object,
which can then be called by ruby code as if it were a "normal" function.
A normal ruby function is one that is parsed and transformed to code. But not all

View File

@ -35,11 +35,11 @@ module Risc
return true if objekt.is_a? Fixnum
return true if objekt.is_a?( Risc::Label)
#puts message(objekt , depth)
#puts "ADD #{objekt.inspect}, #{objekt.name}" if objekt.is_a? Parfait::TypedMethod
#puts "ADD #{objekt.inspect}, #{objekt.name}" if objekt.is_a? Parfait::CallableMethod
unless objekt.is_a?( Parfait::Object) or objekt.is_a?( Symbol)
raise "adding non parfait #{objekt.class}:#{objekt}"
end
#raise "Method #{objekt.name}" if objekt.is_a? Parfait::TypedMethod
#raise "Method #{objekt.name}" if objekt.is_a? Parfait::CallableMethod
Position.get_or_create(objekt)
true
end

View File

@ -27,7 +27,7 @@ module Risc
@next = nekst
return unless source
raise "Source must be string or Instruction, not #{source.class}" unless source.is_a?(String) or
source.is_a?(Mom::Instruction) or source.is_a?(Parfait::TypedMethod)
source.is_a?(Mom::Instruction) or source.is_a?(Parfait::CallableMethod)
end
attr_reader :source

View File

@ -115,48 +115,56 @@ module Parfait
# superclasses other than default object
def self.super_class_names
{ Data4: :DataObject , Data8: :DataObject ,Data16: :DataObject ,
{ Data4: :DataObject ,
Data8: :DataObject ,
Data16: :DataObject ,
Data32: :DataObject ,
BinaryCode: :Data16 , Integer: :Data4 , Word: :Data8 ,
Object: :BasicObject, List: :Data16 , ReturnAddress: :Integer}
BinaryCode: :Data16 ,
Integer: :Data4 ,
Word: :Data8 ,
List: :Data16 ,
CallableMethod: :Callable,
ReturnAddress: :Integer}
end
# the function really just returns a constant (just avoiding the constant)
# unfortuantely that constant condenses every detail about the system, class names
# and all instance variable names. Really have to find a better way
def self.type_names
{ Word: {char_length: :Integer , next_word: :Word} ,
{BinaryCode: {next: :BinaryCode} ,
CacheEntry: {cached_type: :Type , cached_method: :CallableMethod } ,
Callable: {binary: :BinaryCode,next: :Callable ,
arguments_type: :Type , self_type: :Type, frame_type: :Type } ,
CallableMethod: {name: :Word, binary: :BinaryCode,
arguments_type: :Type , self_type: :Type, frame_type: :Type ,
next: :CallableMethod} ,
Class: {instance_methods: :List, instance_type: :Type,
name: :Word, super_class_name: :Word },
DataObject: {},
Data4: {},
Data8: {},
Data16: {},
Dictionary: {keys: :List , values: :List } ,
Integer: {next_integer: :Integer},
FalseClass: {},
List: {indexed_length: :Integer , next_list: :List} ,
Message: { next_message: :Message, receiver: :Object, frame: :NamedList ,
return_address: :Integer, return_value: :Object,
caller: :Message , name: :Word , arguments: :NamedList },
Integer: {next_integer: :Integer},
ReturnAddress: {next_integer: :ReturnAddress},
DataObject: {},
Data4: {},
Data8: {},
TrueClass: {},
FalseClass: {},
NamedList: {},
NilClass: {},
Object: {},
BinaryCode: {next: :BinaryCode} ,
ReturnAddress: {next_integer: :ReturnAddress},
Space: {classes: :Dictionary , types: :Dictionary ,
next_message: :Message , messages: :Message ,
next_integer: :Integer, integers: :Integer ,
next_address: :ReturnAddress ,addresses: :ReturnAddress ,
true_object: :TrueClass, false_object: :FalseClass , nil_object: :NilClass},
NamedList: {},
TrueClass: {},
Type: {names: :List , types: :List ,
object_class: :Class, methods: :TypedMethod } ,
Class: {instance_methods: :List, instance_type: :Type,
name: :Word, super_class_name: :Word },
Dictionary: {keys: :List , values: :List } ,
CacheEntry: {cached_type: :Type , cached_method: :TypedMethod } ,
TypedMethod: {name: :Word, risc_instructions: :Object,
cpu_instructions: :Object, binary: :BinaryCode,
arguments_type: :Type , self_type: :Type, frame_type: :Type ,
next_method: :TypedMethod} ,
object_class: :Class, methods: :CallableMethod } ,
VoolMethod: { name: :Word , args_type: :Type , frame_type: :Type } ,
Word: {char_length: :Integer , next_word: :Word} ,
}
end
end

View File

@ -18,7 +18,7 @@ module Arm
assert_equal :r1 , @codes.left
end
def test_slot_right
assert_equal 16 , @codes.right
assert_equal 8 , @codes.right
end
def test_next_from
assert_equal :r1 , @codes.next.from.symbol

View File

@ -21,7 +21,7 @@ module Risc
end
def test_load_method
method = @produced
assert_load( method, Parfait::TypedMethod ,:r1)
assert_load( method, Parfait::CallableMethod ,:r1)
assert_equal :div4 , method.constant.name
end
def test_load_space
@ -43,7 +43,7 @@ module Risc
def test_get_args_type #from method in r1
sl = @produced.next( 5 )
assert_slot_to_reg( sl , :r1 , 5 , :r4 )
assert_slot_to_reg( sl , :r1 , 3 , :r4 )
end
def test_get_args #from message
sl = @produced.next( 6 )
@ -56,7 +56,7 @@ module Risc
def test_get_frame_type #from method in r1
sl = @produced.next( 8 )
assert_slot_to_reg( sl , :r1 , 7 , :r4 )
assert_slot_to_reg( sl , :r1 , 5 , :r4 )
end
def test_get_frame #from message
sl = @produced.next( 9 )

View File

@ -8,7 +8,7 @@ module Parfait
@obj = Parfait.object_space.get_class_by_name(:Object).instance_type
@args = Parfait::Type.for_hash( @obj.object_class , { bar: :Integer , foo: :Type})
@frame = Parfait::Type.for_hash( @obj.object_class , { local_bar: :Integer , local_foo: :Type})
@method = Parfait::TypedMethod.new( @obj , :meth , @args , @frame)
@method = Parfait::CallableMethod.new( @obj , :meth , @args , @frame)
end
def test_method_name
@ -99,7 +99,7 @@ module Parfait
assert_equal @method , @method
end
def test_not_equal
method = Parfait::TypedMethod.new( @obj , :other , @args , @frame)
method = Parfait::CallableMethod.new( @obj , :other , @args , @frame)
assert @method != method
end
end

View File

@ -4,9 +4,10 @@ module Parfait
class TestSpace < ParfaitTest
def classes
[:Word,:List,:Message,:Integer,:ReturnAddress,:DataObject,:Data4,:Data8,
:TrueClass,:FalseClass,:NilClass,:Object,:BinaryCode,:Space,:NamedList,
:Type,:Class,:Dictionary,:CacheEntry,:TypedMethod,:VoolMethod]
[:BinaryCode,:CacheEntry,:Callable,:CallableMethod,:Class,
:DataObject,:Data4,:Data8,:Data16,:Dictionary,:Integer,:FalseClass,
:List,:Message,:NamedList,:NilClass,:Object,:ReturnAddress,
:Space,:TrueClass,:Type,:VoolMethod,:Word]
end
def test_space_length

View File

@ -22,13 +22,13 @@ module Parfait
end
def test_name
assert_equal "Word_Type" , @types.values.first.name
assert_equal "BinaryCode_Type" , @types.values.first.name
end
def test_to_hash
hash = @first.to_hash
assert_equal hash[:type] , :Type
assert_equal 3 , hash.length
assert_equal 2 , hash.length
end
def test_add_is_different
type = @first.add_instance_variable :random , :Integer

View File

@ -14,7 +14,7 @@ module Parfait
end
def foo_method( for_class = :Try)
args = Parfait::Type.for_hash( @try_class , { bar: :Integer})
::Parfait::TypedMethod.new( @space.get_class_by_name(for_class).instance_type , :foo , args,empty_frame)
::Parfait::CallableMethod.new( @space.get_class_by_name(for_class).instance_type , :foo , args,empty_frame)
end
def add_foo_to( clazz = :Try )
foo = foo_method( clazz )
@ -50,7 +50,7 @@ module Parfait
end
def test_method_get
add_foo_to
assert_equal Parfait::TypedMethod , @try_type.get_method(:foo).class
assert_equal Parfait::CallableMethod , @try_type.get_method(:foo).class
end
def test_method_get_nothere
assert_nil @try_type.get_method(:foo)

View File

@ -45,7 +45,7 @@ module Risc
ret = main_ticks(63)
assert_equal FunctionReturn , ret.class
assert_equal :r1 , ret.register.symbol
assert_equal 21924 , @interpreter.get_register(ret.register)
assert_equal 21476 , @interpreter.get_register(ret.register)
end
def test_sys
sys = main_ticks(68)

View File

@ -92,7 +92,7 @@ module Risc
assert_equal @label , ret.label
end
def test_minus
op = @builder.build {space - typed_method}
op = @builder.build {space - callable_method}
assert_equal OperatorInstruction , op.class
assert_equal :- , op.operator
assert_equal :Space , op.left.type

View File

@ -54,7 +54,7 @@ module Risc
end
def test_pc1
@interpreter.tick
assert_equal 21432 , @interpreter.pc
assert_equal 21048 , @interpreter.pc
end
def test_tick2
@interpreter.tick
@ -68,7 +68,7 @@ module Risc
def test_pc2
@interpreter.tick
@interpreter.tick
assert_equal 21436 , @interpreter.pc
assert_equal 21052 , @interpreter.pc
end
def test_tick_14_jump
14.times {@interpreter.tick}

View File

@ -25,7 +25,7 @@ module Risc
assert_equal 0 , Position.get(@linker.cpu_init).at
end
def test_cpu_at
assert_equal "0x626c" , Position.get(@linker.cpu_init.first).to_s
assert_equal "0x60ec" , Position.get(@linker.cpu_init.first).to_s
end
def test_cpu_label
assert_equal Position , Position.get(@linker.cpu_init.first).class

View File

@ -59,14 +59,14 @@ module Risc
assert_equal Parfait::Class , vool.body.first.clazz.class
end
def test_typed_method_instance_type
def test_callable_method_instance_type
in_test_vool("def meth; @ivar = 5; @ibar = 4;end")
test = Parfait.object_space.get_class_by_name(:Test)
method = test.instance_type.get_method(:meth)
assert_equal 1, method.self_type.variable_index(:ivar)
assert_equal 2, method.self_type.variable_index(:ibar)
end
def test_typed_method_has_one_local
def test_callable_method_has_one_local
in_test_vool("def meth; local = 5 ; a = 6;end")
test = Parfait.object_space.get_class_by_name(:Test)
method = test.get_method(:meth)

View File

@ -35,7 +35,7 @@ module Vool
assert_equal Mom::SimpleCall, @ins.next(2).class
end
def test_call_has_method
assert_equal Parfait::TypedMethod, @ins.next(2).method.class
assert_equal Parfait::CallableMethod, @ins.next(2).method.class
end
def test_array
check_array [Mom::MessageSetup,Mom::ArgumentTransfer,Mom::SimpleCall] , @ins

View File

@ -18,7 +18,7 @@ module Vool
assert_equal SimpleCall, @ins.next(2).class
end
def test_call_has_method
assert_equal Parfait::TypedMethod, @ins.next(2).method.class
assert_equal Parfait::CallableMethod, @ins.next(2).method.class
end
def test_call_has_right_method
assert_equal :get_internal_word, @ins.next(2).method.name