1.1 --- a/micropython/__init__.py Tue Nov 01 01:16:09 2011 +0100
1.2 +++ b/micropython/__init__.py Thu Nov 17 01:49:57 2011 +0100
1.3 @@ -40,6 +40,7 @@
1.4 from micropython.common import *
1.5 from micropython.data import *
1.6 import micropython.ast
1.7 +import micropython.native
1.8 import micropython.opt
1.9 import micropython.inspect
1.10 import micropython.table
1.11 @@ -68,6 +69,7 @@
1.12
1.13 self.importer = importer
1.14 self.optimisations = optimisations or set()
1.15 + self.native = micropython.native.NativeLibrary(self)
1.16
1.17 # Remember the tables once generated.
1.18
1.19 @@ -122,6 +124,8 @@
1.20 for const in self.importer.constants():
1.21 self.code.append(const)
1.22
1.23 + # Generate each module.
1.24 +
1.25 last_module = self.importer.modules_ordered[-1]
1.26
1.27 for module in self.importer.modules_ordered:
1.28 @@ -203,6 +207,10 @@
1.29 code = trans.get_module_code()
1.30 self.code += code
1.31
1.32 + # Generate the native library once we know how much of it is used.
1.33 +
1.34 + self.code += self.native.get_native_code()
1.35 +
1.36 return self.code
1.37
1.38 def get_raw_image(self, architecture=None, with_builtins=0):
2.1 --- a/micropython/ast.py Tue Nov 01 01:16:09 2011 +0100
2.2 +++ b/micropython/ast.py Thu Nov 17 01:49:57 2011 +0100
2.3 @@ -53,13 +53,13 @@
2.4 """
2.5
2.6 ASTVisitor.__init__(self)
2.7 - Assembler.__init__(self, program.optimisations)
2.8 + Assembler.__init__(self, program)
2.9 self.visitor = self
2.10 self.module = module
2.11
2.12 # Global program dependencies.
2.13
2.14 - self.program = program
2.15 + self.native = program.native
2.16 self.objtable = self.program.get_object_table()
2.17 self.paramtable = self.program.get_parameter_table()
2.18 self.importer = self.program.get_importer()
3.1 --- a/micropython/code.py Tue Nov 01 01:16:09 2011 +0100
3.2 +++ b/micropython/code.py Thu Nov 17 01:49:57 2011 +0100
3.3 @@ -29,13 +29,18 @@
3.4
3.5 "Support for generating low-level code."
3.6
3.7 - def __init__(self, optimisations):
3.8 + def __init__(self, program):
3.9
3.10 - "Initialise the assembler with an optimiser and status attributes."
3.11 + """
3.12 + Initialise the assembler with a program, optimiser and status
3.13 + attributes.
3.14 + """
3.15 +
3.16 + self.program = program
3.17
3.18 # Optimisation.
3.19
3.20 - self.optimiser = Optimiser(self, optimisations)
3.21 + self.optimiser = Optimiser(self, program.optimisations)
3.22
3.23 # The current unit being translated.
3.24
3.25 @@ -425,4 +430,62 @@
3.26 except IndexError:
3.27 return None
3.28
3.29 + # Allocation-related methods.
3.30 +
3.31 + def make_instance(self, cls, n):
3.32 +
3.33 + """
3.34 + Request a new instance using the given class 'cls' and with 'n'
3.35 + attributes.
3.36 + """
3.37 +
3.38 + # Load the class in order to locate the instance template.
3.39 +
3.40 + self.new_op(LoadConst(cls))
3.41 +
3.42 + # NOTE: Instance headers are one location.
3.43 +
3.44 + self.new_op(MakeInstance(n + 1))
3.45 +
3.46 + def make_exception(self, name):
3.47 +
3.48 + "Make an exception of the given 'name' using 'node'."
3.49 +
3.50 + # NOTE: Reserving an attribute.
3.51 +
3.52 + self.make_instance(self.get_builtin_class(name), 1)
3.53 +
3.54 + # Name-related methods.
3.55 +
3.56 + def get_scope(self, name):
3.57 +
3.58 + "Return the scope for the given 'name'."
3.59 +
3.60 + attr, scope, from_name = self.unit._get_with_scope(name)
3.61 + return scope
3.62 +
3.63 + def load_builtin(self, name, node):
3.64 +
3.65 + "Generate an instruction loading 'name' for the given 'node'."
3.66 +
3.67 + self.new_op(LoadAddress(self.get_builtin(name)))
3.68 +
3.69 + def get_builtin_class(self, name):
3.70 +
3.71 + "Return the built-in class with the given 'name'."
3.72 +
3.73 + return self.get_builtin(name).get_value()
3.74 +
3.75 + def get_builtin(self, name):
3.76 +
3.77 + "Return the built-in module definition for the given 'name'."
3.78 +
3.79 + if self.builtins is not None:
3.80 + try:
3.81 + return self.builtins[name]
3.82 + except KeyError:
3.83 + raise TranslateError("No __builtins__ definition is available for name %r." % name)
3.84 + else:
3.85 + raise TranslateError("No __builtins__ module is available for name %r." % name)
3.86 +
3.87 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/micropython/common.py Tue Nov 01 01:16:09 2011 +0100
4.2 +++ b/micropython/common.py Thu Nov 17 01:49:57 2011 +0100
4.3 @@ -356,6 +356,9 @@
4.4 self.astnode = None
4.5
4.6 def get_lineno(self, node):
4.7 + if node is None:
4.8 + return None
4.9 +
4.10 lineno = node.lineno
4.11 if lineno is not None:
4.12 return lineno
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/micropython/native.py Thu Nov 17 01:49:57 2011 +0100
5.3 @@ -0,0 +1,156 @@
5.4 +#!/usr/bin/env python
5.5 +
5.6 +"""
5.7 +Native library generation.
5.8 +
5.9 +Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
5.10 +
5.11 +This program is free software; you can redistribute it and/or modify it under
5.12 +the terms of the GNU General Public License as published by the Free Software
5.13 +Foundation; either version 3 of the License, or (at your option) any later
5.14 +version.
5.15 +
5.16 +This program is distributed in the hope that it will be useful, but WITHOUT
5.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
5.19 +details.
5.20 +
5.21 +You should have received a copy of the GNU General Public License along with
5.22 +this program. If not, see <http://www.gnu.org/licenses/>.
5.23 +"""
5.24 +
5.25 +from micropython.code import Assembler
5.26 +from micropython.rsvp import *
5.27 +
5.28 +class NativeLibrary(Assembler):
5.29 +
5.30 + "A native library generator providing common routines."
5.31 +
5.32 + def __init__(self, program):
5.33 +
5.34 + """
5.35 + Initialise a native library for the given 'program'.
5.36 + """
5.37 +
5.38 + Assembler.__init__(self, program)
5.39 +
5.40 + self.importer = self.program.get_importer()
5.41 + self.builtins = None
5.42 +
5.43 + self.unknown_target_block = None
5.44 + self.unknown_target_testable_self_block = None
5.45 + self.known_target_testable_self_block = None
5.46 +
5.47 + # Reset the assembler.
5.48 +
5.49 + self.reset()
5.50 +
5.51 + def get_native_code(self):
5.52 + self.builtins = self.importer.modules.get("__builtins__")
5.53 +
5.54 + if self.unknown_target_block is not None:
5.55 + self._generateCallFuncUnknownTarget()
5.56 +
5.57 + if self.unknown_target_testable_self_block is not None:
5.58 + self._generateCallFuncUnknownTargetTestableSelf()
5.59 +
5.60 + if self.known_target_testable_self_block is not None:
5.61 + self._generateCallFuncKnownTargetTestableSelf()
5.62 +
5.63 + return self.blocks
5.64 +
5.65 + def _commonCallFunc(self, adjust_block, continue_block):
5.66 + self.new_op(CheckContext(working="source", target="status"))
5.67 + self.new_op(JumpIfFalse(adjust_block, working="status"))
5.68 +
5.69 + # Skip adjustment and tests if the context is not a class.
5.70 + # Classes themselves employ a placeholder context so that
5.71 + # instantiators can be callable with a context which will be
5.72 + # overwritten in the frame.
5.73 +
5.74 + # Here, the source value should still refer to the context.
5.75 +
5.76 + self.new_op(CheckClass(working="source", target="status"))
5.77 + self.new_op(JumpIfFalse(continue_block, working="status"))
5.78 +
5.79 + def _commonTestContext(self, success_block):
5.80 + self.new_op(CheckInstance(source="source", target="status"))
5.81 + self.new_op(JumpIfTrue(success_block, working="status"))
5.82 +
5.83 + # Where the context is inappropriate, drop the incomplete frame and
5.84 + # raise an exception.
5.85 +
5.86 + self.new_op(DropFrame())
5.87 +
5.88 + self.make_exception("TypeError")
5.89 + self.set_target("exception")
5.90 + self.new_op(RaiseException())
5.91 +
5.92 + def _commonAdjustFrame(self, adjust_block, continue_block):
5.93 + self.set_block(adjust_block)
5.94 + self.new_op(AdjustFrame(1))
5.95 + self.set_block(continue_block)
5.96 +
5.97 + def getCallFuncUnknownTarget(self):
5.98 + if self.unknown_target_block is None:
5.99 + self.unknown_target_block = self.new_block()
5.100 +
5.101 + return self.unknown_target_block
5.102 +
5.103 + def _generateCallFuncUnknownTarget(self):
5.104 +
5.105 + """
5.106 + Some preliminary tests where the target of an invocation is not known.
5.107 + Requires the context in the working value register.
5.108 + """
5.109 +
5.110 + adjust_block = self.new_block()
5.111 + continue_block = self.new_block()
5.112 +
5.113 + self.set_block(self.unknown_target_block)
5.114 + self._commonCallFunc(adjust_block, continue_block)
5.115 + self._commonAdjustFrame(adjust_block, continue_block)
5.116 + self.new_op(Return())
5.117 +
5.118 + def getCallFuncUnknownTargetTestableSelf(self):
5.119 + if self.unknown_target_testable_self_block is None:
5.120 + self.unknown_target_testable_self_block = self.new_block()
5.121 +
5.122 + return self.unknown_target_testable_self_block
5.123 +
5.124 + def _generateCallFuncUnknownTargetTestableSelf(self):
5.125 +
5.126 + """
5.127 + Test any explicit first argument against the context.
5.128 + """
5.129 +
5.130 + adjust_block = self.new_block()
5.131 + continue_block = self.new_block()
5.132 +
5.133 + self.set_block(self.unknown_target_testable_self_block)
5.134 + self._commonCallFunc(adjust_block, continue_block)
5.135 + self._commonTestContext(adjust_block)
5.136 + self._commonAdjustFrame(adjust_block, continue_block)
5.137 + self.new_op(Return())
5.138 +
5.139 + def getCallFuncKnownTargetTestableSelf(self):
5.140 + if self.known_target_testable_self_block is None:
5.141 + self.known_target_testable_self_block = self.new_block()
5.142 +
5.143 + return self.known_target_testable_self_block
5.144 +
5.145 + def _generateCallFuncKnownTargetTestableSelf(self):
5.146 +
5.147 + """
5.148 + Test any explicit first argument against the context.
5.149 + """
5.150 +
5.151 + adjust_block = self.new_block()
5.152 + continue_block = self.new_block()
5.153 +
5.154 + self.set_block(self.known_target_testable_self_block)
5.155 + self._commonTestContext(continue_block)
5.156 + self._commonAdjustFrame(adjust_block, continue_block)
5.157 + self.new_op(Return())
5.158 +
5.159 +# vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/micropython/rsvp.py Tue Nov 01 01:16:09 2011 +0100
6.2 +++ b/micropython/rsvp.py Thu Nov 17 01:49:57 2011 +0100
6.3 @@ -317,11 +317,13 @@
6.4 return self.__class__(self.attr, self.working, self.target, self.source)
6.5
6.6 def __repr__(self):
6.7 - return "%s(%s%s%s%s)" % (self.__class__.__name__,
6.8 - self.format_operand(),
6.9 - self.format_working(),
6.10 - self.format_source(),
6.11 - self.format_target())
6.12 + return "%s(%s)" % (self.__class__.__name__,
6.13 + ", ".join(
6.14 + self.format_operand() +
6.15 + self.format_working() +
6.16 + self.format_source() +
6.17 + self.format_target()
6.18 + ))
6.19
6.20 def __hash__(self):
6.21 return hash(self.get_details())
6.22 @@ -334,16 +336,16 @@
6.23
6.24 def format_operand(self):
6.25 operand = self.get_operand()
6.26 - return operand is not None and repr(operand) or ""
6.27 + return operand is not None and [repr(operand)] or []
6.28
6.29 def format_working(self):
6.30 - return self.working != self.default_working and (", working=%r" % self.working) or ""
6.31 + return self.working != self.default_working and ["working=%r" % self.working] or []
6.32
6.33 def format_source(self):
6.34 - return self.source != self.default_source and (", source=%r" % self.source) or ""
6.35 + return self.source != self.default_source and ["source=%r" % self.source] or []
6.36
6.37 def format_target(self):
6.38 - return self.target != self.default_target and (", target=%r" % self.target) or ""
6.39 + return self.target != self.default_target and ["target=%r" % self.target] or []
6.40
6.41 def get_operand(self):
6.42 return None
6.43 @@ -362,7 +364,7 @@
6.44 "An instruction accessing an object's attribute."
6.45
6.46 def format_operand(self):
6.47 - return "%s, name=%r" % (Instruction.format_operand(self), name(self.attr))
6.48 + return Instruction.format_operand(self) + ["name=%r" % name(self.attr)]
6.49
6.50 def get_operand(self):
6.51 return self.attr.position
6.52 @@ -376,12 +378,12 @@
6.53 def format_operand(self):
6.54 location, position, result = self.get_operands()
6.55 if location is not None:
6.56 - return "%s, location=%s, position=%s, name=%s" % (
6.57 - result, location, position, name(self.attr))
6.58 + return ["%s" % result, "location=%s" % location, "position=%s" % position,
6.59 + "name=%s" % name(self.attr)]
6.60 elif result is not None:
6.61 - return "%s, name=%s" % (result, name(self.attr))
6.62 + return ["%s" % result, "name=%s" % name(self.attr)]
6.63 else:
6.64 - return "name=%s" % name(self.attr)
6.65 + return ["name=%s" % name(self.attr)]
6.66
6.67 def get_operands(self):
6.68 if isinstance(self.attr, Attr):
6.69 @@ -410,7 +412,7 @@
6.70 "An instruction loading the address of an invocation target."
6.71
6.72 def format_operand(self):
6.73 - return "%s, name=%r" % (Instruction.format_operand(self), name(self.attr))
6.74 + return Instruction.format_operand(self) + ["name=%r" % name(self.attr)]
6.75
6.76 def get_operand(self):
6.77 return self.attr.code_body_location
6.78 @@ -627,6 +629,11 @@
6.79 cost = 2
6.80 default_target = None
6.81
6.82 +class JumpInFrameDirect(Address):
6.83 + "Jump, using the current locals, to the specified address."
6.84 + cost = 2
6.85 + default_target = None
6.86 +
6.87 class JumpWithFrame(Instruction):
6.88 "Jump, adopting the invocation frame, to the current callable."
6.89 cost = 3
6.90 @@ -708,7 +715,10 @@
6.91 """
6.92
6.93 return instruction.target == register or isinstance(instruction, (
6.94 - JumpWithFrame, JumpWithFrameDirect, JumpIfTrue, JumpIfFalse, Jump
6.95 + JumpInFrame, JumpInFrameDirect,
6.96 + JumpWithFrame, JumpWithFrameDirect,
6.97 + JumpIfTrue, JumpIfFalse,
6.98 + Jump
6.99 ))
6.100
6.101 # vim: tabstop=4 expandtab shiftwidth=4
7.1 --- a/micropython/trans.py Tue Nov 01 01:16:09 2011 +0100
7.2 +++ b/micropython/trans.py Thu Nov 17 01:49:57 2011 +0100
7.3 @@ -28,64 +28,6 @@
7.4
7.5 "Internal helper methods for AST visitors."
7.6
7.7 - # Allocation-related methods.
7.8 -
7.9 - def make_instance(self, cls, n):
7.10 -
7.11 - """
7.12 - Request a new instance using the given class 'cls' and with 'n'
7.13 - attributes.
7.14 - """
7.15 -
7.16 - # Load the class in order to locate the instance template.
7.17 -
7.18 - self.new_op(LoadConst(cls))
7.19 -
7.20 - # NOTE: Instance headers are one location.
7.21 -
7.22 - self.new_op(MakeInstance(n + 1))
7.23 -
7.24 - def make_exception(self, name):
7.25 -
7.26 - "Make an exception of the given 'name' using 'node'."
7.27 -
7.28 - # NOTE: Reserving an attribute.
7.29 -
7.30 - self.make_instance(self.get_builtin_class(name), 1)
7.31 -
7.32 - # Name-related methods.
7.33 -
7.34 - def get_scope(self, name):
7.35 -
7.36 - "Return the scope for the given 'name'."
7.37 -
7.38 - attr, scope, from_name = self.unit._get_with_scope(name)
7.39 - return scope
7.40 -
7.41 - def load_builtin(self, name, node):
7.42 -
7.43 - "Generate an instruction loading 'name' for the given 'node'."
7.44 -
7.45 - self.new_op(LoadAddress(self.get_builtin(name)))
7.46 -
7.47 - def get_builtin_class(self, name):
7.48 -
7.49 - "Return the built-in class with the given 'name'."
7.50 -
7.51 - return self.get_builtin(name).get_value()
7.52 -
7.53 - def get_builtin(self, name):
7.54 -
7.55 - "Return the built-in module definition for the given 'name'."
7.56 -
7.57 - if self.builtins is not None:
7.58 - try:
7.59 - return self.builtins[name]
7.60 - except KeyError:
7.61 - raise TranslateError("No __builtins__ definition is available for name %r." % name)
7.62 - else:
7.63 - raise TranslateError("No __builtins__ module is available for name %r." % name)
7.64 -
7.65 # Common methods.
7.66
7.67 def _generateGuards(self, node):
7.68 @@ -751,71 +693,37 @@
7.69 """
7.70 Generate code involved in a call to the given 'target' to test the
7.71 context provided by 'temp_context' against 'temp_first_argument', and to
7.72 - signal an exception (using 'node') if the context is incompatible with
7.73 - the first frame argument.
7.74 + signal an exception if the context is incompatible with the first frame
7.75 + argument.
7.76
7.77 In addition, the invocation frame will be shifted if 'temp_context'
7.78 indicates a function or a class.
7.79 -
7.80 - NOTE: This should probably be migrated to a native library.
7.81 """
7.82
7.83 - adjust_block = self.new_block()
7.84 - continue_block = self.new_block()
7.85 + # Need to store the explicit first argument in the working register for
7.86 + # the eventual test.
7.87 +
7.88 + if temp_first_argument is not None:
7.89 + self.new_op(temp_first_argument)
7.90 +
7.91 + # Put the context in the source register.
7.92 +
7.93 + if target is None or temp_first_argument is not None:
7.94 + if self.new_op(temp_context.copy()):
7.95 + self.last_op().target = "source"
7.96 + else:
7.97 + self.new_op(Transfer(source="working", target="source"))
7.98
7.99 # Add some preliminary tests where the target is not known.
7.100
7.101 if target is None:
7.102 -
7.103 - # Adjust the frame if a replaceable context is provided.
7.104 -
7.105 - self.new_op(temp_context)
7.106 - self.new_op(CheckContext(target="status"))
7.107 - self.new_op(JumpIfFalse(adjust_block, working="status"))
7.108 -
7.109 - # Skip adjustment and tests if the context is not a class.
7.110 - # Classes themselves employ a placeholder context so that
7.111 - # instantiators can be callable with a context which will be
7.112 - # overwritten in the frame.
7.113 -
7.114 - # Here, the working value should still refer to the context.
7.115 -
7.116 - self.new_op(CheckClass(target="status"))
7.117 - self.new_op(JumpIfFalse(continue_block, working="status"))
7.118 -
7.119 - # Test any explicit first argument against the context.
7.120 -
7.121 - if temp_first_argument is not None:
7.122 -
7.123 - # Check the current value (the argument) against the known context
7.124 - # (given as the source).
7.125 + if temp_first_argument is not None:
7.126 + self.new_op(JumpInFrameDirect(self.native.getCallFuncUnknownTargetTestableSelf()))
7.127 + else:
7.128 + self.new_op(JumpInFrameDirect(self.native.getCallFuncUnknownTarget()))
7.129
7.130 - if self.new_op(temp_context.copy()):
7.131 - self.last_op().target = "source"
7.132 - self.update_temp(temp_context, self.last_op())
7.133 -
7.134 - self.new_op(temp_first_argument)
7.135 - self.new_op(CheckInstance(source="source", target="status"))
7.136 -
7.137 - if target is None:
7.138 - self.new_op(JumpIfTrue(adjust_block, working="status"))
7.139 - else:
7.140 - self.new_op(JumpIfTrue(continue_block, working="status"))
7.141 -
7.142 - # Where the context is inappropriate, drop the incomplete frame and
7.143 - # raise an exception.
7.144 -
7.145 - self.new_op(DropFrame())
7.146 -
7.147 - self.make_exception("TypeError")
7.148 - self.set_target("exception")
7.149 - self.new_op(RaiseException())
7.150 -
7.151 - if target is None or temp_first_argument is not None:
7.152 - self.set_block(adjust_block)
7.153 - self.new_op(AdjustFrame(1))
7.154 -
7.155 - self.set_block(continue_block)
7.156 + elif temp_first_argument is not None:
7.157 + self.new_op(JumpInFrameDirect(self.native.getCallFuncKnownTargetTestableSelf()))
7.158
7.159 def _doCallFunc(self, temp_target, target=None):
7.160
8.1 --- a/rsvp.py Tue Nov 01 01:16:09 2011 +0100
8.2 +++ b/rsvp.py Thu Nov 17 01:49:57 2011 +0100
8.3 @@ -220,6 +220,11 @@
8.4 coverage = self.coverage[start:end]
8.5 self.show_memory(memory, coverage, start)
8.6
8.7 + def show_object(self, start):
8.8 + obj = self.memory[start]
8.9 + end = start + obj.size
8.10 + self.show_memory(self.memory[start:end], self.coverage[start:end], start)
8.11 +
8.12 def show_memory(self, memory, coverage, start):
8.13 for i, (c, x) in enumerate(map(None, coverage, memory)):
8.14 location = start + i
8.15 @@ -750,6 +755,9 @@
8.16 codeaddr = self.registers[instruction.working]
8.17 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one
8.18
8.19 + def JumpInFrameDirect(self, addr, instruction):
8.20 + return self.jump(addr, self.pc + 1) # return to the instruction after this one
8.21 +
8.22 def JumpWithFrame(self, operand, instruction):
8.23 codeaddr = self.registers[instruction.working]
8.24 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
9.1 --- a/test.py Tue Nov 01 01:16:09 2011 +0100
9.2 +++ b/test.py Thu Nov 17 01:49:57 2011 +0100
9.3 @@ -26,6 +26,10 @@
9.4 for name, attr in obj.items():
9.5 print name, attr
9.6
9.7 +def reset():
9.8 + global rm
9.9 + rm = rsvp.machine(p)
9.10 +
9.11 # Main program.
9.12
9.13 if __name__ == "__main__":