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:
parent
9d8dc68bf4
commit
9376b8bc16
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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 )
|
||||||
|
@ -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]}"
|
||||||
|
@ -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"))
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user