renamed info to MethodSource

This commit is contained in:
Torsten Ruger
2015-07-03 20:13:03 +03:00
parent e959c5b0f5
commit b61c73acdd
24 changed files with 103 additions and 103 deletions

View File

@ -21,8 +21,8 @@ also in an similar way that objects have their classes at runtime.
source. Here we add compile functions to ast classes and compile the AST layer into
Virtual::Objects and Parfait::Values
The main objects are Space (lots of objects), BootClass (represents a class),
CompiledMethod (with Blocks and Instruction).
The main objects are Space (lots of objects), Parfait::Class ,
Method and MethodSource (with Blocks and Instruction).
**Virtual** Instructions get further transformed into **register** instructions.
This is done by an abstractly defined Register Machine with basic Intructions.
@ -59,4 +59,4 @@ and also implement very machine dependent functionality which nevertheless is fu
**Parfait** is that part of the runtime that can be coded in ruby.
It is parsed, like any other code and always included in the resulting binary.
**Builtin** is the part of the runtime that can not be coded in ruby (but is still needed).
This is coded by construction CompiledMethods in code and neccesarily machine dependant.
This is coded by construction MethodSource in code and necessarily machine dependant.

View File

@ -2,7 +2,7 @@ module Virtual
module Compiler
# Compiling is the conversion of the AST into 2 things:
# - code (ie sequences of Instructions inside Blocks) carried by CompiledMethods
# - code (ie sequences of Instructions inside Blocks) carried by MethodSource
# - an object graph containing all the Methods, their classes and Constants
#
# Some compile methods just add code, some may add structure (ie Blocks) while

View File

@ -14,24 +14,24 @@ All the headache comes from mixing those two up.*
Similarly, the result of compiling is two-fold: a static and a dynamic part.
- the static part are objects like the constants, but also defined classes and their methods
- the dynamic part is the code, which is stored as streams of instructions in the CompiledMethod
- the dynamic part is the code, which is stored as streams of instructions in the MethodSource
Too make things a little simpler, we create a very high level instruction stream at first and then
run transformation and optimization passes on the stream to improve it.
Each ast class gets a compile method that does the compilation.
#### Compiled Method and Instructions
#### MethodSource and Instructions
The first argument to the compile method is the CompiledMethod.
All code is encoded as a stream of Instructions in the CompiledMethod.
The first argument to the compile method is the MethodSource.
All code is encoded as a stream of Instructions in the MethodSource.
Instructions are stored as a list of Blocks, and Blocks are the smallest unit of code,
which is always linear.
Code is added to the method (using add_code), rather than working with the actual instructions.
This is so each compiling method can just do it's bit and be unaware of the larger structure
that is being created.
The genearal structure of the instructions is a graph
The general structure of the instructions is a graph
(with if's and whiles and breaks and what), but we build it to have one start and *one* end (return).

View File

@ -15,25 +15,25 @@ module Virtual
def self.compile_integer expression , method
int = expression.value
to = Return.new(Integer , int)
method.info.add_code Set.new( int , to )
method.source.add_code Set.new( int , to )
to
end
def self.compile_true expression , method
to = Return.new(Reference , true )
method.info.add_code Set.new( true , to )
method.source.add_code Set.new( true , to )
to
end
def self.compile_false expression , method
to = Return.new(Reference , false)
method.info.add_code Set.new( false , to )
method.source.add_code Set.new( false , to )
to
end
def self.compile_nil expression , method
to = Return.new(Reference , nil)
method.info.add_code Set.new( nil , to )
method.source.add_code Set.new( nil , to )
to
end
@ -47,9 +47,9 @@ module Virtual
if method.has_var(name)
# either an argument, so it's stored in message
if( index = method.has_arg(name))
method.info.add_code MessageGet.new(expression.name , index)
method.source.add_code MessageGet.new(expression.name , index)
else # or a local so it is in the frame
method.info.add_code FrameGet.new(expression.name , index)
method.source.add_code FrameGet.new(expression.name , index)
end
else
call = Ast::CallSiteExpression.new(expression.name , [] ) #receiver self is implicit
@ -62,7 +62,7 @@ module Virtual
clazz = Space.space.get_class_by_name name
raise "uups #{clazz}.#{name}" unless clazz
to = Return.new(Reference , clazz )
method.info.add_code Set.new( clazz , to )
method.source.add_code Set.new( clazz , to )
to
end
@ -71,8 +71,8 @@ module Virtual
# Clearly a TODO here to implement strings rather than reusing symbols
value = expression.string.to_sym
to = Return.new(Reference , value)
method.info.constants << value
method.info.add_code Set.new( value , to )
method.source.constants << value
method.source.add_code Set.new( value , to )
to
end
@ -85,16 +85,16 @@ module Virtual
raise "oh noo, nil from where #{expression.right.inspect}" unless r
index = method.has_arg(expression.left.name.to_sym)
if index
method.info.add_code Set.new(MessageSlot.new(index , r,type , r ) , Return.new)
method.source.add_code Set.new(MessageSlot.new(index , r,type , r ) , Return.new)
else
index = method.ensure_local(expression.left.name.to_sym)
method.info.add_code Set.new(FrameSlot.new(index , r.type , r ) , Return.new)
method.source.add_code Set.new(FrameSlot.new(index , r.type , r ) , Return.new)
end
r
end
def self.compile_variable expression, method
method.info.add_code InstanceGet.new(expression.name)
method.source.add_code InstanceGet.new(expression.name)
Return.new( Unknown )
end
end

View File

@ -6,9 +6,9 @@ module Virtual
def self.compile_callsite expession , method
me = Compiler.compile( expession.receiver , method )
method.info.add_code NewMessage.new
method.info.add_code Set.new( me , NewSelf.new(me.type))
method.info.add_code Set.new( expession.name.to_sym , NewMessageName.new())
method.source.add_code NewMessage.new
method.source.add_code Set.new( me , NewSelf.new(me.type))
method.source.add_code Set.new( expession.name.to_sym , NewMessageName.new())
compiled_args = []
expession.args.each_with_index do |arg , i|
#compile in the running method, ie before passing control
@ -18,13 +18,13 @@ module Virtual
# so the next free is +1
to = NewArgSlot.new(i + 1 ,val.type , val)
# (doing this immediately, not after the loop, so if it's a return it won't get overwritten)
method.info.add_code Set.new( val , to )
method.source.add_code Set.new( val , to )
compiled_args << to
end
method.info.add_code MessageSend.new(expession.name , me , compiled_args) #and pass control
method.source.add_code MessageSend.new(expession.name , me , compiled_args) #and pass control
# the effect of the method is that the NewMessage Return slot will be filled, return it
# (this is what is moved _inside_ above loop for such expressions that are calls (or constants))
Return.new( method.info.return_type )
Return.new( method.source.return_type )
end
end
end

View File

@ -18,8 +18,8 @@ module Virtual
r = Self.new()
class_name = method.for_class.name
end
new_method = CompiledMethodInfo.create_method(class_name, expression.name , args )
new_method.info.receiver = r
new_method = MethodSource.create_method(class_name, expression.name , args )
new_method.source.receiver = r
new_method.for_class.add_instance_method new_method
#frame = frame.new_frame
@ -28,7 +28,7 @@ module Virtual
return_type = Compiler.compile(ex,new_method )
raise return_type.inspect if return_type.is_a? Instruction
end
new_method.info.return_type = return_type
new_method.source.return_type = return_type
new_method
end
def scratch

View File

@ -6,18 +6,18 @@ module Virtual
# to execute the logic as the if states it, the blocks are the other way around
# so we can the jump over the else if true ,
# and the else joins unconditionally after the true_block
merge_block = method.info.new_block "if_merge" # last one, created first
true_block = method.info.new_block "if_true" # second, linked in after current, before merge
false_block = method.info.new_block "if_false" # directly next in order, ie if we don't jump we land here
merge_block = method.source.new_block "if_merge" # last one, created first
true_block = method.source.new_block "if_true" # second, linked in after current, before merge
false_block = method.source.new_block "if_false" # directly next in order, ie if we don't jump we land here
is = Compiler.compile(expression.cond, method )
# TODO should/will use different branches for different conditions.
# just a scetch : cond_val = cond_val.is_true?(method) unless cond_val.is_a? BranchCondition
method.info.add_code IsTrueBranch.new( true_block )
method.source.add_code IsTrueBranch.new( true_block )
# compile the true block (as we think of it first, even it is second in sequential order)
method.info.current true_block
method.source.current true_block
last = is
expression.if_true.each do |part|
last = Compiler.compile(part,method )
@ -25,16 +25,16 @@ module Virtual
end
# compile the false block
method.info.current false_block
method.source.current false_block
expression.if_false.each do |part|
#puts "compiling in if false #{part}"
last = Compiler.compile(part,method )
raise part.inspect if last.nil?
end
method.info.add_code UnconditionalBranch.new( merge_block )
method.source.add_code UnconditionalBranch.new( merge_block )
#puts "compiled if: end"
method.info.current merge_block
method.source.current merge_block
#TODO should return the union of the true and false types
last

View File

@ -53,7 +53,7 @@ module Virtual
@blocks = [@init]
@space.classes.values.each do |c|
c.instance_methods.each do |f|
nb = f.info.blocks
nb = f.source.blocks
@blocks += nb
end
end

View File

@ -4,7 +4,7 @@ module Virtual
# the static info of a method (with its compiled code, argument names etc ) is part of the
# runtime, ie found in Parfait::Method
# the info we create here is injected int the method and used only at compile-time
# the source we create here is injected into the method and used only at compile-time
# receiver
# return arg (usually mystery, but for coded ones can be more specific)
@ -27,11 +27,11 @@ module Virtual
# These (eg if/while) blocks may themselves have linear blocks ,but the last of these
# MUST have an uncoditional branch. And remember, all roads lead to return.
class CompiledMethodInfo
class MethodSource
# create method does two things
# first it creates the parfait method, for the given class, with given argument names
# second, it creates CompiledMethodInfo and attaches it to the method
# second, it creates MethodSource and attaches it to the method
#
# compile code then works with the method, but adds code tot the info
def self.create_method( class_name , method_name , args)
@ -40,7 +40,7 @@ module Virtual
clazz = Virtual.machine.space.get_class_by_name class_name
raise "No such class #{class_name}" unless clazz
method = clazz.create_instance_method( method_name , Virtual.new_list(args))
method.info = CompiledMethodInfo.new(method)
method.source = MethodSource.new(method)
method
end
# just passing the method object in for Instructions to make decisions (later)

View File

@ -157,7 +157,7 @@ module Parfait
end
class Method
attr_accessor :info
attr_accessor :source
end
class Word

View File

@ -15,7 +15,7 @@ module Virtual
object.init_layout
end
if( object.is_a? Parfait::Method)
object.info.constants.each{|c| keep(c) }
object.source.constants.each{|c| keep(c) }
end
layout = object.get_layout
keep layout

View File

@ -24,7 +24,7 @@ module Virtual
end
#puts "stayer #{function.name}"
@gonners.delete function
function.info.blocks.each do |block|
function.source.blocks.each do |block|
block.codes.each do |code|
if code.is_a? Virtual::MessageSend
@gonners.each do |stay|