move resolve_method code from word to mom
rather make resolve an instruction. Since it was coded in risc anyway, we not only save the setup and call But also makes the mom instruction flow clearer The method really came from not wanting to code it in risc, but with the Builder, that is now surprisingly painless
This commit is contained in:
parent
8c322329fb
commit
33ffcf1d88
@ -32,6 +32,7 @@ require_relative "check"
|
||||
require_relative "basic_values"
|
||||
require_relative "simple_call"
|
||||
require_relative "dynamic_call"
|
||||
require_relative "resolve_method"
|
||||
require_relative "truth_check"
|
||||
require_relative "not_same_check"
|
||||
require_relative "jump"
|
||||
|
@ -27,17 +27,17 @@ module Mom
|
||||
# Move method name, frame and arguemnt types from the method to the next_message
|
||||
# Get the message from Space and link it.
|
||||
def to_risc(compiler)
|
||||
build_with(compiler.builder)
|
||||
build_with(compiler.builder(false))
|
||||
end
|
||||
|
||||
# directly called by to_risc
|
||||
# but also used directly in __init
|
||||
def build_with(builder)
|
||||
from = method_source
|
||||
risc = builder.build_and_return { typed_method << from }
|
||||
risc << build_message_data(builder)
|
||||
builder.build { typed_method << from }
|
||||
build_message_data(builder)
|
||||
builder.compiler.reset_regs
|
||||
return risc
|
||||
return builder.built
|
||||
end
|
||||
|
||||
private
|
||||
@ -49,7 +49,7 @@ module Mom
|
||||
# also put it into next_message of current message (and reverse)
|
||||
# set name and type data in the message, from the method loaded
|
||||
def build_message_data( builder )
|
||||
builder.build_and_return do
|
||||
builder.build do
|
||||
space << Parfait.object_space
|
||||
next_message << space[:first_message]
|
||||
message[:next_message] << next_message
|
||||
|
67
lib/mom/instruction/resolve_method.rb
Normal file
67
lib/mom/instruction/resolve_method.rb
Normal file
@ -0,0 +1,67 @@
|
||||
module Mom
|
||||
|
||||
# Dynamic method resolution is at the heart of a dynamic language, and here
|
||||
# is the Mom level instruction to do it.
|
||||
#
|
||||
# When the static type can not be determined a CacheEntry is used to store
|
||||
# type and method of the resolved method. The CacheEntry is shared with
|
||||
# DynamicCall instruction who is responsible for calling the method in the entry.
|
||||
#
|
||||
# This instruction resolves the method, in case the types don't match (and
|
||||
# at least on first encouter)
|
||||
#
|
||||
# This used to be a method, but we don't really need the method setup etc
|
||||
#
|
||||
class ResolveMethod < Instruction
|
||||
attr :cache_entry , :name
|
||||
|
||||
def initialize(name , cache_entry)
|
||||
@name = name
|
||||
@cache_entry = cache_entry
|
||||
end
|
||||
|
||||
# resolve the method name of self, on the given object
|
||||
# may seem wrong way around at first sight, but we know the type of string. And
|
||||
# thus resolving this method happens at compile time, whereas any method on an
|
||||
# unknown self (the object given) needs resolving and that is just what we are doing
|
||||
# ( ie the snake bites it's tail)
|
||||
# This method is just a placeholder until boot is over and the real method is
|
||||
# parsed.
|
||||
def to_risc( compiler )
|
||||
name = @name
|
||||
cache_entry = @cache_entry
|
||||
return Risc.label("hi" , "there")
|
||||
builder = compiler.builder(false)
|
||||
builder.build do
|
||||
word << name
|
||||
|
||||
type << cache_entry
|
||||
type << type[:cached_type]
|
||||
typed_method << type[:methods]
|
||||
|
||||
add while_start_label
|
||||
space << Parfait.object_space
|
||||
space << space[:nil_object]
|
||||
|
||||
space - typed_method
|
||||
if_zero exit_label
|
||||
|
||||
name << typed_method[:name]
|
||||
name - word
|
||||
|
||||
if_not_zero false_label
|
||||
message[:return_value] << typed_method
|
||||
add Mom::ReturnSequence.new.to_risc(compiler)
|
||||
|
||||
add false_label
|
||||
typed_method << typed_method[:next_method]
|
||||
branch while_start_label
|
||||
|
||||
add exit_label
|
||||
end
|
||||
Risc::Builtin::Object.emit_syscall( builder , :exit )
|
||||
return builder.built
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -176,7 +176,7 @@ module Risc
|
||||
end
|
||||
|
||||
obj = space.get_class_by_name(:Word)
|
||||
[:putstring , :get_internal_byte , :set_internal_byte , :resolve_method].each do |f|
|
||||
[:putstring , :get_internal_byte , :set_internal_byte ].each do |f|
|
||||
obj.instance_type.add_method Builtin::Word.send(f , nil)
|
||||
end
|
||||
|
||||
|
@ -94,8 +94,8 @@ module Vool
|
||||
def cache_check(in_method)
|
||||
ok = Mom::Label.new("cache_ok_#{self.object_id}")
|
||||
check = build_condition(ok) # if cached_type != current_type
|
||||
check << build_type_cache_update # cached_type = current_type
|
||||
check << build_method_cache_update(in_method)# cached_method = current_type.resolve_method(method.name)
|
||||
check << Mom::SlotLoad.new([dynamic_call.cache_entry, :cached_type] , [:message , :receiver , :type])
|
||||
check << Mom::ResolveMethod.new( @name , dynamic_call.cache_entry )
|
||||
check << ok
|
||||
end
|
||||
|
||||
@ -111,14 +111,5 @@ module Vool
|
||||
current_type = Mom::SlotDefinition.new(:message , [:receiver , :type])
|
||||
Mom::NotSameCheck.new(cached_type , current_type, ok_label)
|
||||
end
|
||||
def build_type_cache_update
|
||||
Mom::SlotLoad.new([dynamic_call.cache_entry, :cached_type] , [:message , :receiver , :type])
|
||||
end
|
||||
def build_method_cache_update(in_method)
|
||||
receiver = SymbolConstant.new(@name)
|
||||
resolve = SendStatement.new(:resolve_method , receiver , [@receiver])
|
||||
move_method = Mom::SlotLoad.new([dynamic_call.cache_entry, :cached_method] , [:message , :return_value])
|
||||
resolve.to_mom(in_method) << move_method
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -24,7 +24,7 @@ class TestSpace < MiniTest::Test
|
||||
end
|
||||
def test_methods_booted
|
||||
word = @space.get_class_by_name(:Word).instance_type
|
||||
assert_equal 4 , word.method_names.get_length
|
||||
assert_equal 3 , word.method_names.get_length
|
||||
assert word.get_method(:putstring) , "no putstring"
|
||||
end
|
||||
|
||||
|
@ -29,13 +29,10 @@ module Risc
|
||||
IsZero, SlotToReg, OperatorInstruction, IsNotZero, Label,
|
||||
SlotToReg, Branch, Label, LoadConstant, SlotToReg,
|
||||
OperatorInstruction, IsZero, SlotToReg, OperatorInstruction, IsNotZero,
|
||||
Label, SlotToReg, Branch, Label, LoadConstant,
|
||||
SlotToReg, OperatorInstruction, IsZero, SlotToReg, OperatorInstruction,
|
||||
IsNotZero, Label, SlotToReg, Branch, Label,
|
||||
LoadConstant, SlotToReg, OperatorInstruction, IsZero, SlotToReg,
|
||||
OperatorInstruction, IsNotZero, Label, SlotToReg, Branch,
|
||||
Label, LoadConstant, SlotToReg, OperatorInstruction, IsZero,
|
||||
Label, Transfer, Syscall, NilClass]
|
||||
RegToSlot, SlotToReg, SlotToReg, RegToSlot, SlotToReg,
|
||||
SlotToReg, FunctionReturn, SlotToReg, LoadConstant, RegToSlot,
|
||||
Label, LoadConstant, LoadConstant, SlotToReg, RegToSlot,
|
||||
RegToSlot, SlotToReg, SlotToReg]
|
||||
#assert_equal 1 , get_return
|
||||
end
|
||||
|
||||
|
@ -19,15 +19,15 @@ module Vool
|
||||
assert_equal :type , load.right.slots[1] , load
|
||||
end
|
||||
def test_check_resolve_call
|
||||
assert_equal SimpleCall , @ins.next(5).class , @ins
|
||||
assert_equal ResolveMethod , @ins.next(3).class , @ins
|
||||
end
|
||||
def test_dynamic_call_last
|
||||
assert_equal DynamicCall , @ins.last.class , @ins
|
||||
end
|
||||
|
||||
def test_array
|
||||
check_array [SlotLoad, NotSameCheck, SlotLoad, MessageSetup, ArgumentTransfer, SimpleCall ,
|
||||
SlotLoad, Label, MessageSetup, ArgumentTransfer, DynamicCall] , @ins
|
||||
check_array [SlotLoad, NotSameCheck, SlotLoad, ResolveMethod, Label, MessageSetup ,
|
||||
ArgumentTransfer, DynamicCall] , @ins
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user