From 33ffcf1d881acf9edf2d652468189e95368de58d Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sun, 8 Apr 2018 18:55:17 +0300 Subject: [PATCH] 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 --- lib/mom/instruction/instruction.rb | 1 + lib/mom/instruction/message_setup.rb | 10 +-- lib/mom/instruction/resolve_method.rb | 67 +++++++++++++++++++ lib/risc/boot.rb | 2 +- lib/vool/statements/send_statement.rb | 13 +--- test/parfait/test_space.rb | 2 +- test/risc/interpreter/test_dynamic_call.rb | 11 ++- .../to_mom/send/test_send_cached_simple.rb | 6 +- 8 files changed, 84 insertions(+), 28 deletions(-) create mode 100644 lib/mom/instruction/resolve_method.rb diff --git a/lib/mom/instruction/instruction.rb b/lib/mom/instruction/instruction.rb index f230aa80..6e7bcba0 100644 --- a/lib/mom/instruction/instruction.rb +++ b/lib/mom/instruction/instruction.rb @@ -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" diff --git a/lib/mom/instruction/message_setup.rb b/lib/mom/instruction/message_setup.rb index 742cd64b..0c09e0c7 100644 --- a/lib/mom/instruction/message_setup.rb +++ b/lib/mom/instruction/message_setup.rb @@ -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 diff --git a/lib/mom/instruction/resolve_method.rb b/lib/mom/instruction/resolve_method.rb new file mode 100644 index 00000000..a91f51af --- /dev/null +++ b/lib/mom/instruction/resolve_method.rb @@ -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 diff --git a/lib/risc/boot.rb b/lib/risc/boot.rb index ff487d9b..21c74969 100644 --- a/lib/risc/boot.rb +++ b/lib/risc/boot.rb @@ -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 diff --git a/lib/vool/statements/send_statement.rb b/lib/vool/statements/send_statement.rb index 7b21f5bb..ce1c5a7a 100644 --- a/lib/vool/statements/send_statement.rb +++ b/lib/vool/statements/send_statement.rb @@ -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 diff --git a/test/parfait/test_space.rb b/test/parfait/test_space.rb index 989059d5..c325188a 100644 --- a/test/parfait/test_space.rb +++ b/test/parfait/test_space.rb @@ -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 diff --git a/test/risc/interpreter/test_dynamic_call.rb b/test/risc/interpreter/test_dynamic_call.rb index 5bec4ce8..1f4837b4 100644 --- a/test/risc/interpreter/test_dynamic_call.rb +++ b/test/risc/interpreter/test_dynamic_call.rb @@ -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 diff --git a/test/vool/to_mom/send/test_send_cached_simple.rb b/test/vool/to_mom/send/test_send_cached_simple.rb index a9c0a2a5..8a33dbea 100644 --- a/test/vool/to_mom/send/test_send_cached_simple.rb +++ b/test/vool/to_mom/send/test_send_cached_simple.rb @@ -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