work on ObjectWriter

Back to the root! but lots of adjusting
ObjectWriter takes machine, machine has space
Virtual constants become Parfait::Objects etc
This commit is contained in:
Torsten Ruger 2015-05-16 12:53:10 +03:00
parent 9d8dc68bf4
commit 9376b8bc16
12 changed files with 65 additions and 50 deletions

View File

@ -6,9 +6,9 @@ require 'elf/string_table_section'
module Elf module Elf
class ObjectWriter class ObjectWriter
def initialize(space , target = Elf::Constants::TARGET_ARM ) def initialize(machine , target = Elf::Constants::TARGET_ARM )
@object = Elf::ObjectFile.new(target) @object = Elf::ObjectFile.new(target)
@object_space = space @object_machine = machine
sym_strtab = Elf::StringTableSection.new(".strtab") sym_strtab = Elf::StringTableSection.new(".strtab")
@object.add_section sym_strtab @object.add_section sym_strtab
@symbol_table = Elf::SymbolTableSection.new(".symtab", sym_strtab) @symbol_table = Elf::SymbolTableSection.new(".symtab", sym_strtab)
@ -17,8 +17,8 @@ module Elf
@text = Elf::TextSection.new(".text") @text = Elf::TextSection.new(".text")
@object.add_section @text @object.add_section @text
@object_space.run_passes @object_machine.run_passes
assembler = Register::Assembler.new(@object_space) assembler = Register::Assembler.new(@object_machine.space)
set_text assembler.assemble set_text assembler.assemble
# for debug add labels to the block positions # for debug add labels to the block positions

View File

@ -25,7 +25,8 @@ module Parfait
class Object class Object
include FakeMem include FakeMem
def self.new_object *args def self.new_object *args
#puts "I am #{self}" # Space.space.get_or_create_class(:Word)
puts "I am #{self}"
object = self.new(*args) object = self.new(*args)
object object
end end

View File

@ -22,5 +22,8 @@
module Parfait module Parfait
class Layout < List class Layout < List
def get_object_class()
return internal_object_get(2)
end
end end
end end

View File

@ -42,6 +42,15 @@ module Parfait
self.length == 0 self.length == 0
end end
def each
index = 0
while index < self.length
item = get(index)
yield item
index = index + 1
end
self
end
def grow_to(len) def grow_to(len)
raise "negative length for grow #{len}" if len < 0 raise "negative length for grow #{len}" if len < 0
return unless len > self.length return unless len > self.length

View File

@ -16,10 +16,16 @@ module Parfait
# In Salama we store the class in the Layout, and so the Layout is the only fixed # In Salama we store the class in the Layout, and so the Layout is the only fixed
# data that every object carries. # data that every object carries.
def get_class() def get_class()
@layout.get_class() l = get_layout()
puts "Layout #{l}"
l.get_object_class()
end end
# class stores the "latest" layout for instances, ir the layout a new object will def get_layout()
return internal_object_get(1)
end
# class stores the "latest" layout for instances, ie the layout a new object will
# be created with. # be created with.
# inside parfait (and for now everywhere) these are constant. # inside parfait (and for now everywhere) these are constant.
@@EMPTY = { :names => [] , :types => []} @@EMPTY = { :names => [] , :types => []}
@ -27,12 +33,8 @@ module Parfait
@@EMPTY @@EMPTY
end end
def get_layout()
@layout
end
def instance_variables def instance_variables
@layout.instance_variables get_layout().instance_variables
end end
def instance_variable_get name def instance_variable_get name
@ -48,7 +50,7 @@ module Parfait
end end
def instance_variable_defined name def instance_variable_defined name
@layout.index_of(name) layout().index_of(name)
end end
# Object # Object

View File

@ -33,7 +33,7 @@ module Parfait
@next_message = @messages.first @next_message = @messages.first
@next_frame = @frames.first @next_frame = @frames.first
end end
attr_reader :init , :main , :classes , :objects , :symbols,:messages, :next_message , :next_frame attr_reader :classes , :objects , :symbols,:messages, :next_message , :next_frame
@@SPACE = { :names => [:classes,:objects,:symbols,:messages, :next_message , :next_frame] , @@SPACE = { :names => [:classes,:objects,:symbols,:messages, :next_message , :next_frame] ,
:types => [Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference]} :types => [Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference]}
@ -50,7 +50,7 @@ module Parfait
end end
end end
# this is the way to instantiate classes (not BootClass.new) # this is the way to instantiate classes (not Parfait::Class.new)
# so we get and keep exactly one per name # so we get and keep exactly one per name
def get_or_create_class name def get_or_create_class name
raise "uups #{name}.#{name.class}" unless name.is_a? Symbol raise "uups #{name}.#{name.class}" unless name.is_a? Symbol

View File

@ -78,12 +78,6 @@ module Parfait
raise "called" raise "called"
class_for(MoveInstruction).new(value , self , :opcode => :mov) class_for(MoveInstruction).new(value , self , :opcode => :mov)
end end
def clazz
Space.space.get_or_create_class(:Word)
end
def layout
Virtual::Object.layout
end
def mem_length def mem_length
padded(1 + string.length) padded(1 + string.length)
end end

View File

@ -34,21 +34,21 @@ module Virtual
def initialize def initialize
@parser = Parser::Salama.new @parser = Parser::Salama.new
the_end = Halt.new #the_end = Halt.new
@passes = [ "Virtual::SendImplementation" ] @passes = [ "Virtual::SendImplementation" ]
@space = Parfait::Space.new @space = Parfait::Space.new
# @message = Message.new(the_end , the_end , :Object) # @message = Message.new(the_end , the_end , :Object)
end end
attr_reader :message , :passes , :space attr_reader :message , :passes , :space , :init , :main
def run_passes def run_passes
@passes.each do |pass_class| @passes.each do |pass_class|
blocks = [@init] + main.blocks blocks = [@init] + @main.blocks
@classes.values.each do |c| @space.classes.values.each do |c|
c.instance_methods.each {|f| blocks += f.blocks } c.instance_methods.each {|f| blocks += f.blocks }
end end
#puts "running #{pass_class}" #puts "running #{pass_class}"
all.each do |block| blocks.each do |block|
pass = eval pass_class pass = eval pass_class
raise "no such pass-class as #{pass_class}" unless pass raise "no such pass-class as #{pass_class}" unless pass
pass.new.run(block) pass.new.run(block)
@ -90,8 +90,9 @@ module Virtual
# CompiledMethods are grabbed from respective modules by sending the method name. This should return the # CompiledMethods are grabbed from respective modules by sending the method name. This should return the
# implementation of the method (ie a method object), not actually try to implement it (as that's impossible in ruby) # implementation of the method (ie a method object), not actually try to implement it (as that's impossible in ruby)
def boot_classes! def boot_classes!
# very fiddly chicken 'n egg problem. Functions need to be in the right order, and in fact we have to define some # very fiddly chicken 'n egg problem. Functions need to be in the right order, and in fact we
# dummies, just for the other to compile # have to define some dummies, just for the other to compile
# TODO: go through the virtual parfait layer and adjust function names to what they really are
obj = @space.get_or_create_class :Object obj = @space.get_or_create_class :Object
[:index_of , :_get_instance_variable , :_set_instance_variable].each do |f| [:index_of , :_get_instance_variable , :_set_instance_variable].each do |f|
obj.add_instance_method Builtin::Object.send(f , nil) obj.add_instance_method Builtin::Object.send(f , nil)

View File

@ -14,13 +14,15 @@ module Virtual
new_codes = [ ] new_codes = [ ]
ref = code.me ref = code.me
raise "only refs implemented #{me.inspect}" unless ( ref.type == Reference) raise "only refs implemented #{me.inspect}" unless ( ref.type == Reference)
# value known at compile time, got do something with it
if(ref.value) if(ref.value)
me = ref.value me = ref.value
if( me.is_a? BootClass ) if( me.is_a? Parfait::Class )
raise "unimplemented #{code}" raise "unimplemented #{code}"
elsif( me.is_a? ObjectConstant ) elsif( me.is_a? Parfait::Object )
# get the function from my class. easy peasy # get the function from my class. easy peasy
method = me.clazz.get_instance_method(code.name) puts "Me is #{me.class}"
method = me.get_class.get_instance_method(code.name)
raise "Method not implemented #{clazz.name}.#{code.name}" unless method raise "Method not implemented #{clazz.name}.#{code.name}" unless method
new_codes << MethodCall.new( method ) new_codes << MethodCall.new( method )
else else
@ -29,9 +31,11 @@ module Virtual
kernel = Virtual::Machine.instance.space.get_or_create_class(:Kernel) kernel = Virtual::Machine.instance.space.get_or_create_class(:Kernel)
method = kernel.get_instance_method(:__send) method = kernel.get_instance_method(:__send)
new_codes << MethodCall.new( method ) new_codes << MethodCall.new( method )
raise "unimplemented #{code}" raise "unimplemented: \n#{code}"
end end
else else
# must defer send to run-time
# So inlining the code from message.send (in the future)
raise "not constant/ known object for send #{ref.inspect}" raise "not constant/ known object for send #{ref.inspect}"
end end
block.replace(code , new_codes ) block.replace(code , new_codes )

View File

@ -13,7 +13,7 @@ require 'parslet/convenience'
module Fragments module Fragments
# need a code generator, for arm # need a code generator, for arm
def setup def setup
@object_space = Boot::Space.new "Arm" @object_machine = Virtual::Machine.new "Arm"
end end
def parse def parse
@ -24,20 +24,20 @@ module Fragments
# and the last is wrapped as a main # and the last is wrapped as a main
parts.each_with_index do |part,index| parts.each_with_index do |part,index|
if part.is_a? Ast::FunctionExpression if part.is_a? Ast::FunctionExpression
expr = part.compile( @object_space.context ) expr = part.compile( @object_machine.context )
else else
puts part.inspect if part.is_a? Hash puts part.inspect if part.is_a? Hash
expr = part.compile( @object_space.context ) expr = part.compile( @object_machine.context )
end end
end end
end end
# helper to write the file # helper to write the file
def write name def write name
writer = Elf::ObjectWriter.new(@object_space , Elf::Constants::TARGET_ARM) writer = Elf::ObjectWriter.new(@object_machine , Elf::Constants::TARGET_ARM)
assembly = writer.text assembly = writer.text
writer.save("#{name}.o") writer.save("#{name}.o")
function = @object_space.classes[@target[0]] function = @object_machine.classes[@target[0]]
assert function , "no class #{@target[0]}" assert function , "no class #{@target[0]}"
function = function.get_function(@target[1]) function = function.get_function(@target[1])
assert function , "no function #{@target[1]} for class #{@target[0]}" assert function , "no function #{@target[1]} for class #{@target[0]}"

View File

@ -35,6 +35,7 @@ class TestRunner < MiniTest::Test
end end
end end
#object writer takes machine
writer = Elf::ObjectWriter.new(program , Elf::Constants::TARGET_ARM) writer = Elf::ObjectWriter.new(program , Elf::Constants::TARGET_ARM)
writer.save(file.gsub(".rb" , ".o")) writer.save(file.gsub(".rb" , ".o"))

View File

@ -7,10 +7,10 @@ class HelloTest < MiniTest::Test
machine = Virtual::Machine.boot machine = Virtual::Machine.boot
expressions = machine.compile_main @string_input expressions = machine.compile_main @string_input
writer = Elf::ObjectWriter.new(Virtual::Space.space) writer = Elf::ObjectWriter.new(machine)
writer.save "hello.o" writer.save "hello.o"
# puts Sof::Writer.write(expressions) # puts Sof::Writer.write(expressions)
puts Sof::Writer.write(Virtual::Space.space) puts Sof::Writer.write(machine.space)
end end
def qtest_simplest_function def qtest_simplest_function