[pypy-svn] r60619 - in pypy/branch/avm/pypy/translator/avm: . test
magcius at codespeak.net
magcius at codespeak.net
Fri Dec 19 20:01:17 CET 2008
Author: magcius
Date: Fri Dec 19 20:01:17 2008
New Revision: 60619
Added:
pypy/branch/avm/pypy/translator/avm/
pypy/branch/avm/pypy/translator/avm/__init__.py
pypy/branch/avm/pypy/translator/avm/avm.py
pypy/branch/avm/pypy/translator/avm/avm1.py
pypy/branch/avm/pypy/translator/avm/avm1gen.py
pypy/branch/avm/pypy/translator/avm/avm1types.py
pypy/branch/avm/pypy/translator/avm/bootstrap.py
pypy/branch/avm/pypy/translator/avm/database.py
pypy/branch/avm/pypy/translator/avm/function.py
pypy/branch/avm/pypy/translator/avm/log.py
pypy/branch/avm/pypy/translator/avm/metavm.py
pypy/branch/avm/pypy/translator/avm/records.py
pypy/branch/avm/pypy/translator/avm/support.py
pypy/branch/avm/pypy/translator/avm/swf.py
pypy/branch/avm/pypy/translator/avm/tags.py
pypy/branch/avm/pypy/translator/avm/test/
pypy/branch/avm/pypy/translator/avm/test/browsertest.py
pypy/branch/avm/pypy/translator/avm/test/runtest.py
pypy/branch/avm/pypy/translator/avm/util.py
Log:
Aaaand the experimental non-functioning (yet) AVM1 backend.
Added: pypy/branch/avm/pypy/translator/avm/__init__.py
==============================================================================
Added: pypy/branch/avm/pypy/translator/avm/avm.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/avm.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,66 @@
+
+import py, os
+
+from pypy.rpython.rmodel import inputconst
+from pypy.rpython.typesystem import getfunctionptr
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.ootypesystem import ootype
+from pypy.tool.udir import udir
+from pypy.translator.avm.log import log
+from pypy.translator.avm.asmgen import AsmGen
+from pypy.translator.avm.avm1types import AVM1TypeSystem
+#from pypy.translator.js.opcodes import opcodes
+from pypy.translator.avm.function import Function
+from pypy.translator.avm.database import LowLevelDatabase
+from pypy.translator.avm import bootstrap
+
+from pypy.translator.oosupport.genoo import GenOO
+from heapq import heappush, heappop
+
+
+class AVM1(GenOO):
+ TypeSystem = AVMTypeSystem
+ Function = Function
+ Database = LowLevelDatabase
+
+ def __init__(self, translator, function=[], stackless=False, compress=False, \
+ logging=False, use_debug=False):
+ if not isinstance(function, list):
+ functions = [functions]
+ GenOO.__init__(self, udir, translator, None)
+
+ pending_graphs = [ translator.annotator.bookeeeper.getdesc(f).cachedgraph(None) for f in functions ]
+ for graph in pending_graphs:
+ self.db.pending_function(graph)
+
+ self.db.translator = translator
+ self.use_debug = use_debug
+ self.assembly_name = self.translator.graphs[0].name
+ self.tmpfile = udir.join(self.assembly_name + '.swf')
+
+ def stack_optimization(self):
+ pass
+
+ def gen_pendings(self):
+ while self.db._pending_nodes:
+ node = self.db.pending_nodes.pop()
+ to_render = []
+ nparent = node
+ while nparent-order != 0:
+ nparent = nparent.parent
+ to_render.append(nparent)
+ to_render.reverse()
+ for i in to_render:
+ i.render(self.ilasm)
+
+ def create_assembler(self):
+ return bootstrap.create_assembler(self.assembly_name)
+
+ def generate_swf(self):
+ self.ilasm = self.create_assembler()
+ self.fix_names()
+ self.gen_entrypoint()
+ while self.db._pending_nodes:
+ self.gen_pendings()
+ self.db.gen_constants(self.ilasm, self.db._pending_nodes)
+ # self.ilasm.close()
Added: pypy/branch/avm/pypy/translator/avm/avm1.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/avm1.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,625 @@
+
+# AVM1 = ActionScript Virtual Machine 1
+# Used for ActionScript 1 and 2
+
+from pypy.translator.avm.util import BitStream
+import struct
+
+class DataTypes(object):
+
+ def __init__(self, id, name, size):
+ self.id = id
+ self.name = name
+ self.size = size
+
+ def __str__(self):
+ return self.name
+
+ def __call__(self, *a, **b):
+ pass
+
+ __unicode__ = __str__
+
+DataTypes.STRING = DataTypes(0, "string", "Z")
+DataTypes.FLOAT = DataTypes(1, "float", "f")
+DataTypes.NULL = DataTypes(2, "null", "!")
+DataTypes.UNDEFINED = DataTypes(3, "undefined", "!")
+DataTypes.REGISTER = DataTypes(4, "register", "B")
+DataTypes.BOOLEAN = DataTypes(5, "boolean", "B")
+DataTypes.DOUBLE = DataTypes(6, "double", "d")
+DataTypes.INTEGER = DataTypes(7, "integer", "l")
+DataTypes.CONSTANT8 = DataTypes(8, "constant 8", "B")
+DataTypes.CONSTANT16 = DataTypes(9, "constant 16", "H")
+
+class Index(object):
+ def __init__(self, index):
+ self.index = index
+
+class Value(object):
+ def __init__(self, value):
+ self.value = value
+
+Null = object()
+Null.type = DataTypes.Null
+
+Undefined = object()
+Undefined.type = DataTypes.UNDEFINED
+
+class Constant(Index):
+ def __getattr__(self, name):
+ if name == "type":
+ if self.index < 256:
+ return DataTypes.CONSTANT8
+ return DataTypes.CONSTANT16
+ return Index.__getattr__(self, name)
+
+class RegisterByIndex(Index):
+ type = DataTypes.REGISTER
+
+class RegisterByValue(Value):
+ type = DataTypes.REGISTER
+
+class Action(object):
+
+ ACTION_NAME = "NotImplemented"
+ ACTION_ID = 0x00
+
+ def __init__(self):
+ self.offset = 0
+ self.label_name = ""
+
+ def serialize(self):
+ inner_data = self.gen_data()
+ outer_data = self.gen_outer_data()
+ header = struct.pack("BH", self.ACTION_ID, len(inner_data))
+ return bytes + inner_data + outer_data
+
+ def __len__(self):
+ return 6 + len(self.gen_data()) + len(self.gen_outer_data())
+
+ def gen_data(self):
+ raise NotImplementedError, "Action::gen_data is not implemented in the abstract class"
+
+ def gen_outer_data(self):
+ raise NotImplementedError, "Action::gen_outer_data is not implemented in the abstract class"
+
+ def get_block_props_early(self, block):
+ raise NotImplementedError, "Action::get_block_props_early is not implemented in the abstract class"
+
+ def get_block_props_late(self, block):
+ raise NotImplementedError, "Action::get_block_props_late is not implemented in the abstract class"
+
+class RegisterError(IndexError):
+ pass
+
+global_registers = []
+
+class Block(object):
+
+ AUTO_LABEL_TEMPLATE = "label%d"
+ MAX_REGISTERS = 4
+ FUNCTION_TYPE = 0
+
+ def __init__(self, insert_end=False):
+ self.code = ""
+ self.__sealed = False
+ self.insert_end = insert_end
+
+ self.labels = {}
+ self.branch_blocks = {}
+ self.constants = ActionConstantPool()
+ self.actions = [self.constants]
+
+ self.current_offset = 0
+ self.label_count = 0
+ self.registers = global_registers
+
+ def get_free_register(self):
+ if None in self.registers:
+ return self.registers.index(None)
+ elif len(self.registers) < self.MAX_REGISTERS:
+ return len(self.registers)
+ else:
+ raise RegisterError, "maximum number of registers in use"
+
+ def store_register(self, value, index=-1):
+ if value in self.registers:
+ return self.registers.index(value)
+ if index < 1:
+ index = self.get_free_register()
+ self.registers[index] = value
+ return index
+
+ def find_register(self, value):
+ if value in self.registers:
+ return self.registers.index(value)
+ return -1
+
+ def free_register(self, index):
+ self.registers[index] = None
+
+ def __len__(self):
+ return self.current_offset + (2 if self.insert_end else 0)
+
+ def seal(self):
+ self.__sealed = True
+ return len(self)
+
+ def is_sealed(self):
+ return self.__sealed
+
+ def add_action(self, action):
+ if self.__sealed:
+ raise Exception, "Block is sealed. Cannot add new actions"
+ self.code = "" # Dirty the code.
+ action.offset = self.current_offset
+ action.get_block_props_early(self)
+
+ # Do some early optimizations. Combine two pushes into one.
+ if isinstance(action, ActionPush) and isinstance(self.actions[-1], ActionPush):
+ old_action = self.actions[-1]
+ old_len = len(old_action)
+ self.actions[-1].values.extend(action.values)
+ self.current_offset += len(old_action) - old_len
+ return None
+
+ # Two nots negate. Take them out.
+ if isinstance(action, ActionNot) and isinstance(self.actions[-1], ActionNot):
+ self.actions.pop()
+ self.current_offset -= 1 # len(ShortAction) is 1
+ return None
+
+ if not isinstance(action, Block): # Don't add block length until we've finalized.
+ self.current_offset += len(action)
+
+ self.actions.append(action)
+ return action
+
+ def serialize(self):
+ if len(self.code) > 0:
+ return self.code
+ bytes = []
+ for action in self.actions:
+ action.get_block_props_late(self)
+ bytes += action.serialize()
+ if self.insert_end:
+ bytes += "\0\0"
+ self.code = "".join(bytes)
+ return self.code
+
+ def new_label(self):
+ self.label_count += 1
+ name = Block.AUTO_LABEL_TEMPLATE % self.label_count
+ self.labels[name] = -1
+ return name
+
+ def set_label_here(self, name):
+ self.labels[name] = self.current_offset
+
+ def new_label_here(self):
+ name = self.new_label()
+ self.labels[name] = self.current_offset
+ return name
+
+class ActionCall(Action):
+ ACTION_NAME = "ActionCall"
+ ACTION_ID = 0x9e
+
+class ActionConstantPool(Action):
+ ACTION_NAME = "ActionConstantPool"
+ ACTION_ID = 0x88
+
+ def __init__(self, *args):
+ self.pool = []
+ for string in args:
+ if not string in self.pool:
+ self.pool.append(args)
+
+ def add_constant(self, string):
+ if not string in self.pool:
+ self.pool.append(string)
+ return len(self.pool)-1
+ return self.pool.index(string)
+
+ def gen_data(self):
+ return struct.pack("H", len(self.pool)) + "".join([item + "\0" for item in self.pool])
+
+class ActionDefineFunction(Block, Action):
+ ACTION_NAME = "ActionDefineFunction"
+ ACTION_ID = 0x9b
+ FUNCTION_TYPE = 1
+
+ def __init__(self, name, parameters):
+ Block.__init__(self, False)
+ self.function_name = name
+ self.params = params
+
+ def gen_data(self):
+ self.block_data = Block.serialize(self)
+ bytes = [self.function_name, "\0", struct.pack("H", len(self.params))]
+ bytes += [p + "\0" for p in self.params]
+ bytes += struct.pack("H", len(self.block_data))
+ return "".join(bytes)
+
+ def gen_outer_data(self):
+ return self.block_data
+
+class ActionDefineFunction2(Block, Action):
+ ACTION_NAME = "ActionDefineFunction2"
+ ACTION_ID = 0x8e
+ MAX_REGISTERS = 256
+ FUNCTION_TYPE = 2
+
+ def __init__(self, name, parameters, flags=0):
+ Block.__init__(self, False)
+ self.function_name = name
+ self.params = params
+ self.flags = flags & 0xFF01
+ self.eval_flags()
+
+ def find_register(self):
+ if value in self.registers:
+ return self.registers.index(value)+1
+ return -1
+
+ def eval_flags(self): # WARNING! eval_flags will clear registers!
+ bits = BitStream()
+ bits.write_bit_value(self.flags, 16)
+ bits.rewind()
+ preload_parent = bits.read_bit()
+ preload_root = bits.read_bit()
+ suppress_super = bits.read_bit()
+ preload_super = bits.read_bit()
+ suppress_args = bits.read_bit()
+ preload_args = bits.read_bit()
+ suppress_this = bits.read_bit()
+ preload_this = bits.read_bit()
+ bits.cursor += 7 # skip over 7 Reserved bits
+ preload_global = bits.read_bit()
+
+ # According to the docs, this is the order of register allocation.
+ if preload_this: self.registers.append("this")
+ if preload_args: self.registers.append("arguments")
+ if preload_super: self.registers.append("super")
+ if preload_root: self.registers.append("_root")
+ if preload_parent: self.registers.append("_parent")
+ if preload_global: self.registers.append("_global")
+
+ for name in self.params:
+ self.registers.append(name)
+
+ def gen_data(self):
+ self.block_data = Block.serialize(self)
+ params = [p for p in self.params if isinstance(p, RegisterParam)]
+ bytes = [self.function_name, "\0", struct.pack("HBH", len(params), len(self.registers)-1, self.flags)]
+ for name in self.params:
+ bytes += [chr(self.registers.index(name)+1), name, "\0"]
+
+ bytes += [struct.pack("H", len(self.block_data))]
+ return "".join(bytes)
+
+ def gen_outer_data(self):
+ return self.block_data
+
+class ActionGetURL(Action):
+ ACTION_NAME = "ActionGetURL"
+ ACTION_ID = 0x83
+
+ def __init__(self, url, target=""):
+ self.url = url
+ self.target = target
+
+ def gen_data(self):
+ return "%s\0%s\0" % (self.url, self.target)
+
+class ActionGetURL2(Action):
+ ACTION_NAME = "ActionGetURL2"
+ ACTION_ID = 0x9a
+
+ METHOD_NONE = 0
+ METHOD_GET = 1
+ METHOD_POST = 2
+
+ def __init__(self, method, load_target=False, load_variables=False):
+ self.method = max(method, 2)
+ self.load_target = load_target
+ self.load_variables = load_varibles
+
+ def gen_data(self):
+ bits = BitStream()
+ bits.write_bit_value(self.method, 2)
+ bits.zero_fill(4)
+ bits.write_boolean(load_target)
+ bits.write_boolean(load_variables)
+ return bits.serialize()
+
+class ActionGotoFrame(Action):
+ ACTION_NAME = "ActionGotoFrame"
+ ACTION_ID = 0x81
+
+ def __init__(self, index):
+ self.index = index
+
+ def gen_data(self):
+ return struct.pack("H", self.index)
+
+class ActionGotoFrame2(Action):
+ ACTION_NAME = "ActionGotoFrame2"
+ ACTION_ID = 0x9f
+
+ def __init__(self, play=False, scene_bias=0):
+ self.play = play
+ self.scene_bias = scene_bias
+
+ def gen_data(self):
+ bits = BitStream()
+ bits.zero_fill(6)
+ bits.write_boolean(self.scene_bias > 0)
+ bits.write_boolean(self.play)
+
+ if self.scene_bias > 0:
+ return bits.serialize() + struct.pack("H", sceneBias)
+
+ return bits.serialize()
+
+class ActionGotoLabel(Action):
+ ACTION_NAME = "ActionGotoLabel"
+ ACTION_ID = 0x81
+
+ def __init__(self, label_name):
+ self.label_name = label_name
+
+ def serialize(self):
+ return self.label_name + "\0"
+
+class BranchingActionBase(Action):
+
+ def __init__(self, branch):
+ if isinstance(branch, str):
+ self.branch_label = branch
+ self.branch_offset = 0
+ elif isinstance(branch, int):
+ self.branch_label = None
+ self.branch_offset = branch
+
+ def get_block_props_late(self, block):
+ if len(self.branch_label) > 0:
+ self.branch_offset = block.labels[self.branch_label] - self.offset
+
+ def gen_data(self):
+ return struct.pack("H", self.branch_offset)
+
+class ActionJump(BranchingActionBase):
+ ACTION_NAME = "ActionJump"
+ ACTION_ID = 0x99
+
+class ActionIf(BranchingActionBase):
+ ACTION_NAME = "ActionIf"
+ ACTION_ID = 0x9d
+
+class ActionPush(Action):
+ ACTION_NAME = "ActionPush"
+ ACTION_ID = 0x96
+
+ def __init__(self, *args):
+ self.values = []
+ self.add_element(args)
+
+ def add_element(self, element):
+ if isinstance(element, (list, tuple)):
+ for el in element:
+ self.add_element(el)
+ elif hasattr(element, "type"):
+ self.values.append((0, type))
+ elif isinstance(element, str):
+ self.values.append((element, DataTypes.STRING))
+ elif isinstance(element, bool):
+ self.values.append((element, DataTypes.BOOLEAN))
+ elif isinstance(element, int):
+ self.values.append((element, DataTypes.INTEGER))
+ elif isinstance(element, float):
+ if element > 0xFFFFFFFF:
+ self.values.append((element, DataTypes.DOUBLE))
+ else:
+ self.values.append((element, DataTypes.FLOAT))
+ elif isinstance(element, Index):
+ self.values.append((element.index, element.type))
+ elif isinstance(element, RegisterByValue):
+ self.values.append((element.value, RegisterByValue))
+
+ def get_block_props_early(self, block):
+ for index, (value, type) in enumerate(self.values):
+ if type == DataTypes.STRING:
+ constant_index = block.constants.add_constant(value)
+ self.values[index] = (constant_index, DataTypes.CONSTANT8 if constant_index < 256 else DataTypes.CONSTANT16)
+ elif type == RegisterByValue:
+ register_index = block.store_register(value)
+ self.values[index] = (register_index, DataTypes.REGISTER)
+
+ def gen_data(self):
+ bytes = []
+ for value, type in self.values:
+ bytes += chr(type.id)
+ if type.size == "Z":
+ bytes += [value, "\0"]
+ elif type.size != "!":
+ bytes += struct.pack(type.size, value)[0]
+ return "".join(bytes)
+
+class ActionSetTarget(object):
+ ACTION_NAME = "ActionSetTarget"
+ ACTION_ID = 0x8b
+
+ def __init__(self, target):
+ self.target = target
+
+ def gen_data(self):
+ return self.target + "\0"
+
+class ActionStoreRegister(object):
+ ACTION_NAME = "ActionStoreRegister"
+ ACTION_ID = 0x87
+
+ def __init__(self, index):
+ self.index = index
+
+ def gen_data(self):
+ return chr(index)
+
+class ActionTry(object):
+ ACTION_NAME = "ActionTry"
+ ACTION_ID = 0x8f
+
+ def __init__(self, catch_object, try_block=None, catch_block=None, finally_block=None):
+
+ self.catch_object = catch_object
+
+ self.try_block = try_block or Block()
+ self.catch_block = catch_block or Block()
+ self.finally_block = finally_block or Block()
+
+ def gen_data(self):
+ has_catch_block = len(self.catch_block.actions) > 0
+ bits = BitStream()
+ bits.zero_fill(5)
+ bits.write_boolean(isinstance(self.catch_object, Register))
+ bits.write_boolean(len(self.finally_block.actions) > 0)
+ bits.write_boolean(has_catch_block)
+ bytes = [bits.serialize()]
+ bytes += [struct.pack("HHH", len(self.try_block) + 5 if has_catch_block else 0, len(self.catch_block), len(finallyBlock))]
+ bytes += self.catch_object.index if isinstance(self.catch_object, Register) else (self.catch_object + "\0")
+ return "".join(bytes)
+
+ def gen_outer_data(self):
+ bytes = [self.try_block.serialize()]
+ if len(self.catch_block.actions) > 0:
+ bytes += ActionJump(len(self.catch_block)).serialize()
+ bytes += catchBlock.serialize()
+ bytes += self.finally_block.serialize()
+
+class ActionWaitForFrame(Action):
+ ACTION_NAME = "ActionWaitForFrame"
+ ACTION_ID = 0x8a
+
+ def __init__(self, index, skip_count=0):
+ self.index = index
+ self.skip_count = skip_count
+
+ def gen_data(self):
+ return struct.pack("HB", self.index, self.skip_count)
+
+class ActionWaitForFrame2(Action):
+ ACTION_NAME = "ActionWaitForFrame2"
+ ACTION_ID = 0x8d
+
+ def __init__(self, skip_count=0):
+ self.skip_count = skip_count
+
+ def gen_data(self):
+ return chr(self.skip_count)
+
+class ActionWith(Action):
+ ACTION_NAME = "ActionWith"
+ ACTION_ID = 0x94
+
+ def __init__(self, with_block):
+ self.block = with_block or Block()
+
+ def gen_data(self):
+ return struct.pack("H", len(block)) + block.serialize()
+
+class ShortAction(Action):
+
+ def __call__(self, *args, **kwargs):
+ return self
+
+ def __init__(self, id, name):
+ self.ACTION_ID = id
+ self.ACTION_NAME = name
+ Action.__init__(self)
+
+ def __len__(self):
+ return 1 # 1 (Action ID)
+
+ def serialize(self)
+ return chr(self.ACTION_ID)
+
+ActionNextFrame = ShortAction(0x04, "ActionNextFrame")
+ActionPreviousFrame = ShortAction(0x05, "ActionPreviousFrame")
+ActionPlay = ShortAction(0x06, "ActionPlay")
+ActionStop = ShortAction(0x07, "ActionStop")
+ActionToggleQuality = ShortAction(0x08, "ActionToggleQuality")
+ActionStopSounds = ShortAction(0x09, "ActionStopSounds")
+ActionAdd = ShortAction(0x0a, "ActionAdd")
+ActionSubtract = ShortAction(0x0b, "ActionSubtract")
+ActionMultiply = ShortAction(0x0c, "ActionMultiply")
+ActionDivide = ShortAction(0x0d, "ActionDivide")
+ActionEquals = ShortAction(0x0e, "ActionEquals")
+ActionLess = ShortAction(0x0f, "ActionLess")
+ActionAnd = ShortAction(0x10, "ActionAnd")
+ActionOr = ShortAction(0x11, "ActionOr")
+ActionNot = ShortAction(0x12, "ActionNot")
+ActionStringEquals = ShortAction(0x13, "ActionStringEquals")
+ActionStringLength = ShortAction(0x14, "ActionStringLength")
+ActionStringExtract = ShortAction(0x15, "ActionStringExtract")
+ActionPop = ShortAction(0x17, "ActionPop")
+ActionToInteger = ShortAction(0x18, "ActionToInteger")
+ActionGetVariable = ShortAction(0x1c, "ActionGetVariable")
+ActionSetVariable = ShortAction(0x1d, "ActionSetVariable")
+ActionSetTarget2 = ShortAction(0x20, "ActionSetTarget2")
+ActionStringAdd = ShortAction(0x21, "ActionStringAdd")
+ActionGetProperty = ShortAction(0x22, "ActionGetProperty")
+ActionSetProperty = ShortAction(0x23, "ActionSetProperty")
+ActionCloneSprite = ShortAction(0x24, "ActionCloneSprite")
+ActionRemoveSprite = ShortAction(0x25, "ActionRemoveSprite")
+ActionTrace = ShortAction(0x26, "ActionTrace")
+ActionStartDrag = ShortAction(0x27, "ActionStartDrag")
+ActionEndDrag = ShortAction(0x28, "ActionEndDrag")
+ActionStringLess = ShortAction(0x29, "ActionStringLess")
+ActionThrow = ShortAction(0x2a, "ActionThrow")
+ActionCastOp = ShortAction(0x2b, "ActionCastOp")
+ActionImplementsOp = ShortAction(0x2c, "ActionImplementsOp")
+ActionRandomNumber = ShortAction(0x30, "ActionRandomNumber")
+ActionMBStringLength = ShortAction(0x31, "ActionMBStringLength")
+ActionCharToAscii = ShortAction(0x32, "ActionCharToAscii")
+ActionAsciiToChar = ShortAction(0x33, "ActionAsciiToChar")
+ActionGetTime = ShortAction(0x34, "ActionGetTime")
+ActionMBStringExtract = ShortAction(0x35, "ActionMBStringExtract")
+ActionMBCharToAscii = ShortAction(0x36, "ActionMBCharToAscii")
+ActionMBAsciiToChar = ShortAction(0x37, "ActionMBAsciiToChar")
+ActionDelVar = ShortAction(0x3a, "ActionDelVar")
+ActionDelThreadVars = ShortAction(0x3b, "ActionDelThreadVars")
+ActionDefineLocalVal = ShortAction(0x3c, "ActionDefineLocalVal")
+ActionCallFunction = ShortAction(0x3d, "ActionCallFunction")
+ActionReturn = ShortAction(0x3e, "ActionReturn")
+ActionModulo = ShortAction(0x3f, "ActionModulo")
+ActionNewObject = ShortAction(0x40, "ActionNewObject")
+ActionDefineLocal = ShortAction(0x41, "ActionDefineLocal")
+ActionInitArray = ShortAction(0x42, "ActionInitArray")
+ActionInitObject = ShortAction(0x43, "ActionInitObject")
+ActionTypeof = ShortAction(0x44, "ActionTypeof")
+ActionGetTargetPath = ShortAction(0x45, "ActionGetTargetPath")
+ActionEnumerate = ShortAction(0x46, "ActionEnumerate")
+ActionTypedAdd = ShortAction(0x47, "ActionTypedAdd")
+ActionTypedLessThan = ShortAction(0x48, "ActionTypedLessThan")
+ActionTypedEquals = ShortAction(0x49, "ActionTypedEquals")
+ActionConvertToNumber = ShortAction(0x4a, "ActionConvertToNumber")
+ActionConvertToString = ShortAction(0x4b, "ActionConvertToString")
+ActionDuplicate = ShortAction(0x4c, "ActionDuplicate")
+ActionSwap = ShortAction(0x4d, "ActionSwap")
+ActionGetMember = ShortAction(0x4e, "ActionGetMember")
+ActionSetMember = ShortAction(0x4f, "ActionSetMember")
+ActionIncrement = ShortAction(0x50, "ActionIncrement")
+ActionDecrement = ShortAction(0x51, "ActionDecrement")
+ActionCallMethod = ShortAction(0x52, "ActionCallMethod")
+ActionCallNewMethod = ShortAction(0x53, "ActionCallNewMethod")
+ActionBitAnd = ShortAction(0x60, "ActionBitAnd")
+ActionBitOr = ShortAction(0x61, "ActionBitOr")
+ActionBitXor = ShortAction(0x62, "ActionBitXor")
+ActionShiftLeft = ShortAction(0x63, "ActionShiftLeft")
+ActionShiftRight = ShortAction(0x64, "ActionShiftRight")
+ActionShiftUnsigned = ShortAction(0x65, "ActionShiftUnsigned")
+ActionStrictEquals = ShortAction(0x66, "ActionStrictEquals")
+ActionGreater = ShortAction(0x67, "ActionGreater")
+ActionStringGreater = ShortAction(0x68, "ActionStringGreater")
+ActionExtends = ShortAction(0x69, "ActionExtends")
Added: pypy/branch/avm/pypy/translator/avm/avm1gen.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/avm1gen.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,216 @@
+
+""" backend generator routines
+"""
+
+from pypy.translator.avm import avm1
+
+
+class AsmGen(object):
+ """ AVM1 'assembler' generator routines """
+ def __init__(self, name, block=None):
+ self.name = name
+ self.block = block or Block(True)
+ self.scope = (self.block, None, None) # (Code object, Parent scope, Exit callback)
+
+ def new_label(self):
+ return self.scope[0].new_label()
+
+ def store_register(self, *args, **kwargs):
+ return self.scope[0].store_register(*args, **kwargs)
+
+ def find_register(self, value):
+ return self.scope[0].find_register(value)
+
+ def action(self, action):
+ return self.scope[0].add_action(action)
+
+ def enter_scope(self, new_code_obj, exit_callback):
+ self.scope = (new_code_obj, self.scope, exit_callback)
+
+ def in_function(self):
+ return self.block.FUNCTION_TYPE
+
+ def exit_scope(self):
+ block_len = self.finalize_block(self, self.scope[0])
+ exit_callback = self.scope[2]
+
+ # Go up to the parent scope.
+ self.scope = self.scope[1]
+
+ self.scope[0].current_offset += len(block_len)
+ if exit_callback is not None:
+ exit_callback(self)
+
+ def finalize_block(self, block):
+ for label, branch_block in block.branch_blocks.iteritems():
+ if not branch_block.is_sealed():
+ raise Exception, "Branch block hasn't been finalized"
+ # Set the label.
+ block.labels[label] = block.current_offset
+ # Add the actions, which updates current_offset
+ for act in branch_block.actions:
+ block.add_action(act)
+ return block.seal()
+
+
+ def begin_function(self, name, arglist):
+ self.enter_scope(self.action(avm1.ActionDefineFunction2(name, arglist)))
+
+ def begin_prototype_method(self, function_name, _class, arglist):
+ self.action(avm1.ActionPush(function_name, "prototype", _class))
+ self.action(avm1.ActionGetVariable())
+ self.action(avm1.ActionGetMember())
+ self.enter_scope(self.action(avm1.ActionDefineFunction2("", arglist, 0)), lambda s: self.action(avm1.ActionSetMember()))
+
+ def set_variable(self):
+ self.action(avm1.ActionSetVariable())
+
+ def set_member(self):
+ self.action(avm1.ActionSetMember())
+
+ def get_member(self):
+ self.action(avm1.ActionGetMember())
+
+ def push_arg(self, v):
+ if self.in_function() == 0:
+ raise Exception, "avm1::push_arg called while not in function scope."
+ elif self.in_function() == 1:
+ self.push_local(v.name)
+ else:
+ self.action(avm1.ActionPush(RegisterByValue(v.name)))
+
+# def push_value(self, v):
+# self.action(avm1.ActionPush(v.name))
+
+ def push_this(self, v):
+ k = self.find_register("this")
+ if k > 0:
+ self.action(avm1.ActionPush(RegisterByIndex(k)))
+ else:
+ self.action(avm1.ActionPush("this"))
+ self.action(avm1.ActionGetVariable())
+
+ def push_local(self, v):
+ k = self.find_register(v.name)
+ if k > 0:
+ self.action(avm1.ActionPush(RegisterByIndex(k)))
+ else:
+ self.action(avm1.ActionPush(v.name))
+ self.action(avm1.ActionGetVariable())
+
+ def push_const(self, v):
+ self.action(avm1.ActionPush(v))
+
+ def push_undefined(self):
+ self.action(avm1.ActionPush(avm1.Undefined))
+
+ def push_null(self):
+ self.action(avm1.ActionPush(avm1.Null))
+
+ def return_stmt(self):
+ self.action(avm1.ActionReturn())
+
+ def is_equal(self, value=None):
+ if value is not None:
+ self.action(avm1.ActionPush(value))
+ self.action(avm1.ActionEquals())
+
+ def is_not_equal(self, value=None):
+ self.is_equal(value)
+ self.action(avm1.ActionNot())
+
+ def init_object(self, dict=None):
+ if dict is not None:
+ self.action(avm1.ActionPush([(b,a) for (a,b) in dict.iteritems()], len(dict)))
+ self.action(avm1.ActionInitObject())
+
+ def init_array(self, list=None):
+ if list is not None:
+ self.action(avm1.ActionPush(list, len(list)))
+ self.action(avm1.ActionInitArray())
+
+ def call_function(self, func_name): # Assumes the args and number of args are on the stack.
+ self.action(avm1.ActionPush(func_name))
+ self.action(avm1.ActionCallFunction())
+
+ def call_function_constargs(self, func_name, *args):
+ self.action(avm1.ActionPush(args, len(args), func_name))
+ self.action(avm1.ActionCallFunction())
+
+ def call_method(self, func_name): # Assumes the args and number of args and ScriptObject are on the stack, in that order.
+ self.action(avm1.ActionPush(func_name))
+ self.action(avm1.ActionCallMethod())
+
+ def call_method_constvar(self, _class, func_name): # Assumes vars and number of args are on the stack.
+ self.action(avm1.ActionPush(_class))
+ self.action(avm1.ActionGetVariable())
+ self.action(avm1.ActionPush(func_name))
+ self.action(avm1.ActionCallMethod())
+
+ def branch_if_true(self, label=""): # Boolean value should be on stack when this is called
+ if len(label) < 0:
+ label = self.new_label()
+ self.scope[0].branch_blocks[label] = Block(False)
+ self.action(avm1.ActionIf(label))
+ return (label, self.scope[0].branch_blocks[label])
+
+ def set_proto_field(self, _class, member_name): # Assumes the value is on the stack.
+ self.action(avm1.ActionPush(member_name, "prototype", _class))
+ self.action(avm1.ActionGetVariable())
+ self.action(avm1.ActionGetMember())
+ self.action(avm1.ActionSwap())
+ self.action(avm1.ActionSetMember())
+
+ def set_static_field(self, _class, member_name): # Assumes the value is on the stack.
+ self.action(avm1.ActionPush(member_name, _class))
+ self.action(avm1.ActionGetVariable())
+ self.action(avm1.ActionSwap())
+ self.action(avm1.ActionSetMember())
+
+ def newobject_constthis(self, obj, *args): # If no args are passed then it is assumed that the args and number of args are on the stack.
+ if len(args) > 0:
+ self.action(avm1.ActionPush(args, len(args), obj))
+ else:
+ self.action(avm1.ActionPush(obj))
+ self.action(avm1.ActionNewObject())
+
+ def newobject(self):
+ self.action(avm1.ActionNewObject())
+
+# def store_void(self):
+# if not len(self.right_hand):
+# return
+# v = self.right_hand.pop()
+# if v is not None and v.find('('):
+# self.codegenerator.writeline(v+";")
+
+ # FIXME: will refactor later
+ #load_str = load_const
+
+ def begin_switch_varname(self, varname):
+ self.action(avm1.ActionPush(varname))
+ self.action(avm1.ActionGetVariable())
+ self.switch_register = self.store_register(varname)
+ self.action(avm1.ActionStoreRegister(self.switch_register))
+
+ def write_case(self, testee):
+ self.action(avm1.ActionPush(avm1.RegisterByIndex(self.switch_register), testee))
+ self.action(avm1.ActionStrictEquals())
+ if len(self.case_label) < 1:
+ self.case_label, self.case_block = self.branch_if_true()
+ else:
+ self.branch_if_true(self.case_label)
+
+ def write_break(self):
+ self.exit_scope()
+ self.case_flag = False
+ self.case_block = None
+
+ def enter_case_branch(self):
+ self.enter_scope(self.case_block)
+
+# def inherits(self, subclass_name, parent_name):
+# self.codegenerator.writeline("inherits(%s,%s);"%(subclass_name, parent_name))
+
+ def throw(self): # Assumes the value to be thrown is on the stack.
+ self.action(avm1.ActionThrow())
Added: pypy/branch/avm/pypy/translator/avm/avm1types.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/avm1types.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,151 @@
+""" JavaScript type system
+"""
+
+from pypy.rpython.ootypesystem import ootype
+from pypy.rpython.lltypesystem import lltype
+from pypy.translator.cli import oopspec
+
+from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float
+from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong, Primitive
+from pypy.rpython.lltypesystem.lltype import Char, UniChar
+from pypy.rpython.ootypesystem.ootype import String, _string, List, StaticMethod
+from pypy.rlib.objectmodel import Symbolic
+
+from pypy.translator.avm.log import log
+
+from types import FunctionType
+from pypy.rpython.extfunc import is_external
+
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+class AVM1TypeSystem(object):
+ """ Class implementing JavaScript type system
+ calls with mapping similiar to cts
+ """
+ def __init__(self, db):
+ self.db = db
+
+ #def __class(self, name):
+ # return name.replace(".", "_")
+
+ def escape_name(self, name):
+ return name.replace('.', '_')
+
+ def llvar_to_cts(self, var):
+ return 'var ', var.name
+
+ def lltype_to_cts(self, t):
+ if isinstance(t, ootype.Instance):
+ self.db.pending_class(t)
+ return self.escape_name(t._name)
+ elif isinstance(t, ootype.List):
+ return 'Array'
+ elif isinstance(t, ootype.Array):
+ return 'Array'
+ #elif isinstance(t, lltype.Primitive):
+ # return 'var'
+ elif isinstance(t, ootype.Record):
+ return 'Array'
+ elif isinstance(t, ootype.String.__class__):
+ return 'String'
+ elif isinstance(t, ootype.Dict):
+ return 'Object'
+ elif isinstance(t, ootype.DictItemsIterator):
+ return 'Object'
+ elif t is ootype.StringBuilder:
+ return 'StringBuilder'
+ #return "var"
+ raise NotImplementedError("Type %r" % (t,))
+
+ def graph_to_signature(self, graph, is_method = False, func_name = None):
+ func_name = func_name or self.db.get_uniquename(graph,graph.name)
+
+ args = [arg for arg in graph.getargs() if
+ arg.concretetype is not ootype.Void]
+ if is_method:
+ args = args[1:]
+
+ return func_name,args
+
+ def method_signature(self, obj, name):
+ # TODO: use callvirt only when strictly necessary
+ if isinstance(obj, ootype.Instance):
+ owner, meth = obj._lookup(name)
+ METH = meth._TYPE
+ return obj._name, METH.ARGS
+ elif isinstance(obj, ootype.BuiltinType):
+ meth = oopspec.get_method(obj, name)
+ class_name = self.lltype_to_cts(obj)
+ return class_name,meth.ARGS
+ else:
+ assert False
+
+ def obj_name(self, obj):
+ return self.lltype_to_cts(obj)
+
+ def primitive_repr(self, _type, v):
+ if _type is Bool:
+ if v == False:
+ val = 'false'
+ else:
+ val = 'true'
+ elif _type is Void:
+ val = 'undefined'
+ elif isinstance(_type,String.__class__):
+ val = repr(v._str)
+ elif isinstance(_type,List):
+ # FIXME: It's not ok to use always empty list
+ val = repr(v._list)
+ elif isinstance(_type,StaticMethod):
+ if hasattr(v, 'graph') and not is_external(v):
+ self.db.pending_function(v.graph)
+ else:
+ self.db.pending_abstract_function(v)
+ val = v._name
+ val = val.replace('.', '_')
+ if val == '?':
+ val = 'undefined'
+ elif _type is UniChar or _type is Char:
+ #log("Constant %r"%v)
+ s = repr(v)
+ if s.startswith('u'):
+ s = s[1:]
+ if s != "'\''":
+ s.replace("'", '"')
+ val = s
+ elif isinstance(v, Symbolic):
+ val = v.expr
+ elif isinstance(_type, Primitive):
+ #log("Type: %r"%_type)
+ val = str(v)
+ else:
+ assert False, "Unknown constant %r"%_type
+ val = str(v)
+ return val
+
+ #def lltype_to_cts(self, t, include_class=True):
+ # return 'var'
+## if isinstance(t, ootype.Instance):
+## self.db.pending_class(t)
+## return self.__class(t._name, include_class)
+## elif isinstance(t, ootype.Record):
+## name = self.db.pending_record(t)
+## return self.__class(name, include_class)
+## elif isinstance(t, ootype.StaticMethod):
+## return 'void' # TODO: is it correct to ignore StaticMethod?
+## elif isinstance(t, ootype.List):
+## item_type = self.lltype_to_cts(t.ITEM)
+## return self.__class(PYPY_LIST % item_type, include_class)
+## elif isinstance(t, ootype.Dict):
+## key_type = self.lltype_to_cts(t._KEYTYPE)
+## value_type = self.lltype_to_cts(t._VALUETYPE)
+## return self.__class(PYPY_DICT % (key_type, value_type), include_class)
+## elif isinstance(t, ootype.DictItemsIterator):
+## key_type = self.lltype_to_cts(t._KEYTYPE)
+## value_type = self.lltype_to_cts(t._VALUETYPE)
+## return self.__class(PYPY_DICT_ITEMS_ITERATOR % (key_type, value_type), include_class)
+##
+## return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t)
Added: pypy/branch/avm/pypy/translator/avm/bootstrap.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/bootstrap.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,13 @@
+
+
+from pypy.translator.avm.swf import SwfData
+from pypy.translator.avm.tags import DoAction, SetBackgroundColor
+
+def create_assembler(name):
+ return AsmGen(name, DoAction())
+
+def bootstrap_avm1(asmgen):
+ data = SwfData()
+ data.add_tag(SetBackgroundColor(0x333333))
+ data.add_tag(asmgen)
+ return data.serialize()
Added: pypy/branch/avm/pypy/translator/avm/database.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/database.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,472 @@
+
+""" genjs constant database module
+"""
+
+import py
+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.avm import avm1
+#from pypy.translator.js.opcodes import opcodes
+from pypy.translator.avm.function import Function
+from pypy.translator.avm.log import log
+#from pypy.translator.js._class import Class
+from pypy.translator.avm.support import AVM1NameManager
+
+from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float
+from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong, typeOf
+from pypy.rpython.lltypesystem.lltype import Char, UniChar
+from pypy.rpython.ootypesystem import ootype
+from pypy.rpython.ootypesystem import bltregistry
+
+from pypy.objspace.flow.model import Variable, Constant
+
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+class LowLevelDatabase(object):
+ def __init__(self, genoo):
+ self._pending_nodes = set()
+ self.genoo = genoo
+ self._rendered_nodes = set()
+ self.classes = {} # classdef --> class_name
+ self.functions = {} # graph --> function_name
+ self.function_names = {} # graph --> real_name
+ self.methods = {} # graph --> method_name
+ self.consts = {} # value --> const_name
+ self.reverse_consts = {}
+ self.const_names = set()
+ self.rendered = set()
+ self.const_var = Variable("__consts")
+ self.name_manager = AVM1NameManager(self)
+ self.pending_consts = []
+ self.cts = self.genoo.TypeSystem(self)
+# self.proxies = []
+
+ def is_primitive(self, type_):
+ if type_ in (Void, Bool, Float, Signed, Unsigned, SignedLongLong, UnsignedLongLong, Char, UniChar, ootype.StringBuilder) or \
+ isinstance(type_,ootype.StaticMethod):
+ return True
+ return False
+
+ def pending_function(self, graph):
+ self.pending_node(self.genoo.Function(self, graph))
+
+ def pending_abstract_function(self, name):
+ pass
+ # XXX we want to implement it at some point (maybe...)
+
+ def pending_class(self, classdef):
+ self.pending_node(classdef)
+ return c
+
+ def pending_record(self, record):
+ r = Record(self, record) # I can't find Record anywhere, and it's not in the imports.
+ self.pending_node(r)
+ return r.get_name()
+
+ def pending_node(self, node):
+ if node in self._pending_nodes or node in self._rendered_nodes:
+ return
+ self._pending_nodes.add(node)
+
+ def record_function(self, graph, name):
+ self.functions[graph] = name
+
+ def get_uniquename(self, graph, name):
+ try:
+ return self.function_names[graph]
+ except KeyError:
+ real_name = self.name_manager.uniquename(name, lenmax=1111111)
+ self.function_names[graph] = real_name
+ return real_name
+
+ def record_class(self, classdef, name):
+ self.classes[classdef] = name
+
+# def register_comm_proxy(self, proxy_const, *args):
+# """ Register external object which should be rendered as
+# method call
+# """
+# self.proxies.append(XmlHttp(proxy_const, *args))
+
+ def graph_name(self, graph):
+ return self.functions.get(graph, None)
+
+ def class_name(self, classdef):
+ return self.classes.get(classdef, None)
+
+ def record_const(self, value, type_ = None, retval='name'):
+ if type_ is None:
+ type_ = typeOf(value)
+ if self.is_primitive(type_):
+ return None
+ const = AbstractConst.make(self, value)
+ if not const:
+ return None
+ try:
+ if retval == 'name':
+ return self.consts[const]
+ else:
+ self.consts[const]
+ return self.reverse_consts[self.consts[const]]
+ except KeyError:
+ if self.genoo.config.translation.verbose:
+ log("New const:%r"%value)
+ if isinstance(value, ootype._string):
+ log(value._str)
+ else:
+ log.dot()
+ name = const.get_name()
+ if name in self.const_names:
+ name += '__%d' % len(self.consts)
+ self.consts[const] = name
+ self.reverse_consts[name] = const
+ self.const_names.add(name)
+ self.pending_consts.append((const,name))
+ if retval == 'name':
+ return name
+ else:
+ return const
+
+ def gen_constants(self, ilasm, pending):
+ try:
+ while True:
+ const,name = self.pending_consts.pop()
+ const.record_fields()
+ except IndexError:
+ pass
+
+ if pending:
+ return
+
+ #if not self.rendered:
+ # begin_consts(self.const_var.name)
+
+ def generate_constants(consts):
+ all_c = [const for const,name in consts.iteritems()]
+ dep_ok = set()
+ while len(all_c) > 0:
+ const = all_c.pop()
+ if const not in self.rendered:
+ to_render = True
+ if hasattr(const, 'depends_on') and const.depends_on:
+ for i in const.depends_on:
+ if i not in self.rendered and i not in dep_ok:
+ assert i.depends is None or const in i.depends
+ to_render = False
+ continue
+
+ if to_render and (not hasattr(const, 'depends')) or (not const.depends) or const in dep_ok:
+ yield const,consts[const]
+ self.rendered.add(const)
+ else:
+ all_c.append(const)
+ for i in const.depends:
+ all_c.append(i)
+ dep_ok.add(const)
+
+ # We need to keep track of fields to make sure
+ # our items appear earlier than us
+ for const, name in generate_constants(self.consts):
+ if self.genoo.config.translation.verbose:
+ log("Recording %r %r"%(const,name))
+ else:
+ log.dot()
+
+ ilasm.push_const(name)
+ const.init(ilasm)
+
+ def push_const(self, type_, value, ilasm):
+ if self.is_primitive(type_):
+ ilasm.push_const(self.cts.primitive_repr(type_, value))
+ else:
+ try:
+ return self.consts[BuiltinConst(value)]
+ except KeyError:
+ name = self.record_const(value)
+ ilasm.push_local(self.const_var)
+ ilasm.get_field(name)
+ #assert False, 'Unknown constant %s' % const
+
+
+class AbstractConst(object):
+ def __init__(self, db, const):
+ self.db = db
+ self.const = const
+ self.cts = db.genoo.TypeSystem(db)
+ self.depends = set()
+ self.depends_on = set()
+
+ def __hash__(self):
+ return hash(self.get_key())
+
+ def __eq__(self, other):
+ return (other.__class__ is self.__class__ and
+ other.get_key() == self.get_key())
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def make(db, const):
+ if isinstance(const, ootype._view):
+ static_type = const._TYPE
+ const = const._inst
+ else:
+ static_type = None
+
+ if isinstance(const, ootype._instance):
+ return InstanceConst(db, const, static_type)
+ elif isinstance(const, ootype._list):
+ return ListConst(db, const)
+ elif isinstance(const, ootype._array):
+ return ListConst(db, const)
+ elif isinstance(const, ootype._record):
+ return RecordConst(db, const)
+ elif isinstance(const, ootype._string):
+ return StringConst(db, const)
+ elif isinstance(const, ootype._dict):
+ return DictConst(db, const)
+ elif isinstance(const, bltregistry._external_inst):
+ return ExtObject(db, const)
+ elif isinstance(const, ootype._class):
+ if const._INSTANCE:
+ return ClassConst(db, const)
+ else:
+ return None
+ else:
+ assert False, 'Unknown constant: %s %r' % (const, typeOf(const))
+ make = staticmethod(make)
+
+ def get_name(self):
+ pass
+
+ def get_type(self):
+ pass
+
+ def init(self, ilasm, name):
+ pass
+
+ def record_fields(self):
+ pass
+
+class InstanceConst(AbstractConst):
+ def __init__(self, db, obj, static_type):
+ self.depends = set()
+ self.depends_on = set()
+ self.db = db
+ self.cts = db.genoo.TypeSystem(db)
+ self.obj = obj
+ if static_type is None:
+ self.static_type = obj._TYPE
+ else:
+ self.static_type = static_type
+ self.cts.lltype_to_cts(obj._TYPE) # force scheduling of obj's class
+
+ def get_key(self):
+ return self.obj
+
+ def get_name(self):
+ return self.obj._TYPE._name.replace('.', '_')
+
+ def get_type(self):
+ return self.cts.lltype_to_cts(self.static_type)
+
+ def init(self, ilasm):
+ if not self.obj:
+ ilasm.push_null()
+ return
+
+ classdef = self.obj._TYPE
+ try:
+ classdef._hints['_suggested_external']
+ #ilasm.new(classdef._name.split("."))
+ pass
+ except KeyError:
+ #ilasm.new(classdef._name.replace(".", "_"))
+ pass
+
+ def record_fields(self):
+ if not self.obj:
+ return
+ INSTANCE = self.obj._TYPE
+ #while INSTANCE:
+ for i, (_type, val) in INSTANCE._allfields().items():
+ if _type is not ootype.Void:
+ name = self.db.record_const(getattr(self.obj, i), _type, 'const')
+ if name is not None:
+ self.depends.add(name)
+ name.depends_on.add(self)
+
+# def init_fields(self, ilasm, name):
+# if not self.obj:
+# return
+
+# INSTANCE = self.obj._TYPE
+# #while INSTANCE:
+# for i, (_type, el) in INSTANCE._allfields().items():
+# if _type is not ootype.Void:
+# ilasm.push_local(const_var)
+# self.db.push_const(_type, getattr(self.obj, i), ilasm)
+# ilasm.set_field(None, "%s.%s"%(name, i))
+# ilasm.store_void()
+
+class RecordConst(AbstractConst):
+ def get_name(self):
+ return "const_tuple"
+
+ def init(self, ilasm):
+ if not self.const:
+ ilasm.push_undefined()
+
+ for i in reversed(self.const._items):
+ el = self.const._items[i]
+ self.db.push_const(typeOf(el), el, ilasm)
+ ilasm.init_array()
+
+ def record_fields(self):
+ if not self.const:
+ return
+
+ for i in self.const._items:
+ name = self.db.record_const(self.const._items[i], None, 'const')
+ if name is not None:
+ self.depends.add(name)
+ name.depends_on.add(self)
+
+ def get_key(self):
+ return self.const
+
+class ListConst(AbstractConst):
+
+ def _get_list(self):
+ if isinstance(self.const, ootype._list):
+ return self.const._list
+ else:
+ return self.const._array
+
+
+ def get_name(self):
+ return "const_list"
+
+ def record_fields(self):
+ if not self.const:
+ return
+
+ for i in self._get_list():
+ name = self.db.record_const(i, None, 'const')
+ if name is not None:
+ self.depends.add(name)
+ name.depends_on.add(self)
+
+ def get_key(self):
+ return self.const
+
+ def init(self, ilasm):
+ if not self.const:
+ ilasm.push_undefined()
+
+ lst = self._get_list()
+ for el in lst:
+ self.db.push_const(typeOf(el), el, ilasm)
+ ilasm.push_const(len(lst))
+ ilasm.init_array()
+
+class StringConst(AbstractConst):
+ def get_name(self):
+ return "const_str"
+
+ def get_key(self):
+ return self.const._str
+
+ def init(self, ilasm):
+ if self.const:
+ ilasm.push_const(self.const._str)
+ else:
+ ilasm.push_undefined()
+
+class ClassConst(AbstractConst):
+ def __init__(self, db, const):
+ super(ClassConst, self).__init__(db, const)
+ self.cts.lltype_to_cts(const._INSTANCE) # force scheduling of class
+
+ def get_key(self):
+ return self.get_name()
+
+ def get_name(self):
+ return self.const._INSTANCE._name.replace(".", "_")
+
+ def init(self, ilasm):
+ #ilasm.push_const(self.get_name())
+
+ #def init_fields(self, ilasm, const_var, name):
+ # pass
+
+class BuiltinConst(AbstractConst):
+ def __init__(self, name):
+ self.name = name
+
+ def get_key(self):
+ return self.name
+
+ def get_name(self):
+ return self.name
+
+ def init(self, ilasm):
+ ilasm.push_const(self.name)
+
+class DictConst(RecordConst):
+ def record_const(self, co):
+ name = self.db.record_const(co, None, 'const')
+ if name is not None:
+ self.depends.add(name)
+ name.depends_on.add(self)
+
+ def record_fields(self):
+ if not self.const:
+ return
+
+ for i in self.const._dict:
+ self.record_const(i)
+ self.record_const(self.const._dict[i])
+
+ def init(self, ilasm):
+ if not self.const:
+ return
+
+ for i in self.const._dict:
+ el = self.const._dict[i]
+ self.db.push_const(typeOf(el), el, ilasm)
+ self.db.push_const(typeOf(i), i, ilasm)
+ ilasm.push_const(len(_dict))
+ ilasm.init_object()
+
+# class ExtObject(AbstractConst):
+# def __init__(self, db, const):
+# self.db = db
+# self.const = const
+# self.name = self.get_name()
+# self.depends = set()
+# self.depends_on = set()
+
+# def get_key(self):
+# return self.name
+
+# def get_name(self):
+# return self.const._TYPE._name
+
+# def init(self, ilasm):
+# _class = self.const._TYPE._class_
+# if getattr(_class, '_render_xmlhttp', False):
+# use_xml = getattr(_class, '_use_xml', False)
+# base_url = getattr(_class, '_base_url', "") # XXX: should be
+# method = getattr(_class, '_use_method', 'GET')
+# # on per-method basis
+# self.db.register_comm_proxy(self.const, self.name, use_xml, base_url, method)
+# ilasm.new(self.get_name())
+# else:
+# # Otherwise they just exist, or it's not implemented
+# if not hasattr(self.const.value, '_render_name'):
+# raise ValueError("Prebuilt constant %s has no attribute _render_name,"
+# "don't know how to render" % self.const.value)
+# ilasm.push_str(self.const.value._render_name)
Added: pypy/branch/avm/pypy/translator/avm/function.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/function.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,236 @@
+
+from pypy.objspace.flow import model as flowmodel
+from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float
+from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong
+from pypy.rpython.ootypesystem import ootype1
+from pypy.translator.oosupport.metavm import Generator,InstructionList
+from pypy.translator.oosupport import function
+
+from pypy.translator.avm.log import log
+from types import FunctionType
+
+import re
+
+class BaseGenerator(object):
+ def push(self, v):
+ if isinstance(v, flowmodel.Variable):
+ if v.name in self.argset:
+ selftype, selfname = self.args[0]
+ if self.is_method and v.name == selfname:
+ self.ilasm.push_this()
+ else:
+ self.ilasm.push_arg(v)
+ else:
+ self.ilasm.push_local(v)
+ elif isinstance(v, flowmodel.Constant):
+ self.db.push_const(v.concretetype, v.value, self.ilasm)
+ elif isinstance(v, str):
+ self.ilasm.push_const(v)
+ else:
+ assert False
+
+ def store(self, v):
+ assert isinstance(v, flowmodel.Variable)
+ if v.concretetype is not Void:
+ self.ilasm.(v)
+ else:
+ self.ilasm.push_null()
+
+# def change_name(self, name, to_name):
+# self.ilasm.change_name(name, to_name)
+
+# def add_comment(self, text):
+# pass
+
+ def function_signature(self, graph):
+ return self.cts.graph_to_signature(graph, False)
+
+ def class_name(self, ooinstance):
+ return ooinstance._name
+
+ def emit(self, instr, *args):
+ self.ilasm.emit(instr, *args)
+
+ def call_graph(self, graph):
+ self.db.pending_function(graph)
+ func_sig = self.function_signature(graph)
+ self.ilasm.call(func_sig)
+
+ def call_external(self, name, args):
+ self.ilasm.call((name, args))
+
+ #def call_signature(self, signature):
+ # self.ilasm.call(signature)
+
+ def cast_to(self, lltype):
+ cts_type = self.cts.lltype_to_cts(lltype, False)
+ self.ilasm.castclass(cts_type)
+
+ def new(self, obj):
+ self.ilasm.new(self.cts.obj_name(obj))
+
+ def oonewarray(self, obj, length):
+ self.ilasm.oonewarray(self.cts.obj_name(obj), length)
+
+ def set_field(self, obj, name):
+ self.ilasm.set_member()
+ #self.ilasm.set_field(self.field_name(obj,name))
+
+ def get_field(self, useless_stuff, name):
+ self.ilasm.get_field(name)
+
+ def call_method(self, obj, name):
+ func_name, signature = self.cts.method_signature(obj, name)
+ self.ilasm.call_method(obj, name, signature)
+
+ def call_external_method(self, name, arg_len):
+ self.ilasm.call_method(None, name, [0]*arg_len)
+
+ def instantiate(self):
+ self.ilasm.runtimenew()
+
+ def downcast(self, TYPE):
+ pass
+
+ def load_special(self, v):
+ # special case for loading value
+ # when setting builtin field we need to load function instead of None
+ # FIXME: we cheat here
+ if isinstance(v, flowmodel.Constant) and v.concretetype is ootype.Void and isinstance(v.value, FunctionType):
+ graph = self.db.translator.annotator.bookkeeper.getdesc(v.value).cachedgraph(None)
+ self.db.pending_function(graph)
+ name = graph.name
+ self.ilasm.load_str(name)
+ else:
+ self.load(v)
+
+ def cast_function(self, name, num):
+ self.ilasm.cast_function(name, num)
+
+ def prefix_op(self, st):
+ self.ilasm.prefix_op(st)
+
+ def push_const(self, s):
+ self.ilasm.push_const(s)
+
+ def push_undefined(self):
+ self.ilasm.push_undefined()
+
+ def push_primitive_constant(self, TYPE, value):
+ self.db.load_const(TYPE, value, self.ilasm)
+
+ def branch_unconditionally(self, target_label):
+ self.ilasm.jump_block(self.block_map[target_label])
+
+ def branch_conditionally(self, exitcase, target_label):
+ self.ilasm.branch_if(exitcase)
+ self.ilasm.jump_block(self.block_map[target_label])
+ self.ilasm.close_branch()
+
+class Function(function.Function, BaseGenerator):
+ def __init__(self, db, graph, name=None, is_method=False,
+ is_entrypoint=False, _class=None):
+ self._class = _class
+ super(Function, self).__init__(db, graph, name, is_method, is_entrypoint)
+ self._set_args()
+ self._set_locals()
+ self.order = 0
+ self.name = name or self.db.get_uniquename(self.graph, self.graph.name)
+
+ def _setup_link(self, link, is_exc_link = False):
+ target = link.target
+ for to_load, to_store in zip(link.args, target.inputargs):
+ if to_load.concretetype is not Void:
+ if is_exc_link and isinstance(to_load, flowmodel.Variable) and re.match("last_exc_value", to_load.name):
+ self.ilasm.load_str("exc")
+ else:
+ self.load(to_load)
+ self.store(to_store)
+
+ def _create_generator(self, ilasm):
+ return self
+
+ def begin_render(self):
+ block_map = {}
+ for blocknum, block in enumerate(self.graph.iterblocks()):
+ block_map[self._get_block_name(block)] = blocknum
+ self.block_map = block_map
+
+ if self.is_method:
+ args = self.args[1:] # self is implicit
+ else:
+ args = self.args
+ if self.is_method:
+ self.ilasm.begin_method(self.name, self._class, [i[1] for i in args])
+ else:
+ self.ilasm.begin_function(self.name, args)
+ self.ilasm.set_locals(",".join([i[1] for i in self.locals]))
+ self.ilasm.begin_for()
+
+ def render_return_block(self, block):
+ return_var = block.inputargs[0]
+ if return_var.concretetype is not Void:
+ self.load(return_var)
+ self.ilasm.ret()
+ else:
+ self.ilasm.load_void()
+ self.ilasm.ret()
+
+ def end_render(self):
+ self.ilasm.end_for()
+ self.ilasm.end_function()
+
+ def render_raise_block(self, block):
+ self.ilasm.throw(block.inputargs[1])
+
+ def end_try(self, target_label, cond):
+ self.ilasm.jump_block(self.block_map[target_label])
+ if cond:
+ self.ilasm.catch()
+ #self.ilasm.close_branch()
+
+ # XXX: soon or later we should use the smarter version in oosupport
+ def render_bool_switch(self, block):
+ for link in block.exits:
+ self._setup_link(link)
+ target_label = self._get_block_name(link.target)
+ if link is block.exits[-1]:
+ self.generator.branch_unconditionally(target_label)
+ else:
+ assert type(link.exitcase) is bool
+ assert block.exitswitch is not None
+ self.generator.load(block.exitswitch)
+ self.generator.branch_conditionally(link.exitcase, target_label)
+
+ def record_ll_meta_exc(self, ll_meta_exc):
+ pass
+
+ def begin_catch(self, llexitcase):
+ real_name = self.cts.lltype_to_cts(llexitcase._INSTANCE)
+ s = "isinstanceof(exc, %s)"%real_name
+ self.ilasm.branch_if_string(s)
+
+ def end_catch(self, target_label):
+ """ Ends the catch block, and branchs to the given target_label as the
+ last item in the catch block """
+ self.ilasm.close_branch()
+
+ def store_exception_and_link(self, link):
+ self._setup_link(link, True)
+ self.ilasm.jump_block(self.block_map[self._get_block_name(link.target)])
+
+ def after_except_block(self):
+ #self.ilasm.close_branch()
+ self.ilasm.throw_real("exc")
+ self.ilasm.close_branch()
+
+ def set_label(self, label):
+ self.ilasm.write_case(self.block_map[label])
+ #self.ilasm.label(label)
+
+ def begin_try(self, cond):
+ if cond:
+ self.ilasm.begin_try()
+
+ def clean_stack(self):
+ self.ilasm.clean_stack()
Added: pypy/branch/avm/pypy/translator/avm/log.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/log.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,4 @@
+import py
+from pypy.tool.ansi_print import ansi_log
+log = py.log.Producer("avm")
+py.log.setconsumer("avm", ansi_log)
Added: pypy/branch/avm/pypy/translator/avm/metavm.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/metavm.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,301 @@
+""" Opcode meaning objects, descendants of MicroInstruction
+"""
+
+#from pypy.translator.js.jsbuiltin import Builtins
+from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult,\
+ InstructionList, New, GetField, MicroInstruction
+
+from pypy.translator.js.log import log
+from pypy.rpython.ootypesystem import ootype
+from types import FunctionType
+from pypy.objspace.flow.model import Constant
+
+class NewBuiltin(MicroInstruction):
+ def __init__(self, arg):
+ self.arg = arg
+
+ def render(self, generator, op):
+ generator.ilasm.new(self.arg)
+
+class _ListSetitem(MicroInstruction):
+ def render(self, generator, op):
+ # op.args = [function_name, list, value, index]
+ generator.push(op.args[1])
+ generator.push(op.args[3])
+ generator.push(op.args[2])
+ generator.ilasm.set_member()
+ListSetitem = _ListSetitem()
+
+class _ListGetitem(MicroInstruction):
+ def render(self, generator, op):
+ # op.args = [function_name, list, index]
+ generator.push(op.args[1])
+ generator.push(op.args[2])
+ generator.ilasm.get_member()
+ListGetitem = _ListGetitem()
+
+class _ListContains(MicroInstruction):
+ def render(self, generator, op):
+ # op.args = [function_name, list, to_find]
+ generator.push(op.args[1])
+ generator.push(op.args[2])
+ generator.ilasm.is_not_equal_const(avm1.Null())
+ListContains = _ListContains()
+
+class _Call(MicroInstruction):
+ def render(self, generator, op):
+ graph = op.args[0].value.graph
+ self._render_function(generator, graph, op.args)
+
+ def _render_builtin(self, generator, builtin, args):
+ for func_arg in args[1:]: # push parameters
+ generator.load(func_arg)
+ generator.call_external(builtin, args[1:])
+
+ def _render_builtin_prepared_args(self, generator, builtin, args):
+ for func_arg in args:
+ generator.load_str(func_arg)
+ generator.call_external(builtin, args)
+
+ def _render_builtin_method(self, generator, builtin, args):
+ for func_arg in args:
+ generator.load_special(func_arg)
+ generator.call_external_method(builtin, len(args)-1)
+
+ def _render_function(self, generator, graph, args):
+ for func_arg in args[1:]: # push parameters
+ if func_arg.concretetype is not ootype.Void:
+ generator.load(func_arg)
+ generator.call_graph(graph)
+
+ def _render_method(self, generator, method_name, args):
+ this = args[0]
+ for arg in args: # push parametes
+ generator.load(arg)
+ generator.call_method(this.concretetype, method_name)
+
+Call = _Call()
+
+class CallBuiltin(_Call):
+ def __init__(self, builtin):
+ self.builtin = builtin
+
+ def render(self, generator, op):
+ self._render_builtin(generator, self.builtin, op.args)
+
+class CallBuiltinMethod(_Call):
+ def __init__(self, builtin, slice=None, additional_args=[]):
+ self.builtin = builtin
+ self.slice = slice
+ self.additional_args = additional_args
+
+ def render(self, generator, op):
+ if self.slice is not None:
+ args = op.args[self.slice]
+ else:
+ args = op.args
+ args += self.additional_args
+ self._render_builtin_method(generator, self.builtin, args)
+
+class _SameAs(MicroInstruction):
+ def render(self, generator, op):
+ generator.change_name(op.result, op.args[0])
+
+class _CastFun(MicroInstruction):
+ def __init__(self, name, num):
+ self.name = name
+ self.num = num
+
+ def render(self, generator, op):
+ log("Args: %r"%op.args)
+ generator.cast_function(self.name, self.num)
+
+class _Prefix(MicroInstruction):
+ def __init__(self, st):
+ self.st = st
+
+ def render(self, generator, op):
+ generator.prefix_op(self.st)
+
+class _NotImplemented(MicroInstruction):
+ def __init__(self, reason):
+ self.reason = reason
+
+ def render(self, generator, op):
+ raise NotImplementedError(self.reason)
+
+class _CastMethod(MicroInstruction):
+ def __init__(self, method_name, num=0):
+ self.method_name = method_name
+ self.num = num
+
+ def render(self, generator, op):
+ generator.call_external_method(self.method_name, self.num)
+
+class _LoadConst(MicroInstruction):
+ def __init__(self, value):
+ self.value = value
+
+ def render(self, generator, op):
+ generator.load(Constant(self.value, ootype.typeOf(self.value)))
+
+class _GetBuiltinField(MicroInstruction):
+ def render(self, generator, op):
+ this = op.args[0]
+ field = op.args[1].value[1:]
+ generator.load(this)
+ generator.get_field(None, field)
+
+class _GetPredefinedField(MicroInstruction):
+ def __init__(self, field, num=1):
+ self.field = field
+ self.num = num
+
+ def render(self, generator, op):
+ if op.result.concretetype is ootype.Void:
+ return
+ this = op.args[self.num]
+ generator.load(this)
+ generator.get_field(None, self.field)
+
+GetBuiltinField = _GetBuiltinField()
+
+class _SetBuiltinField(MicroInstruction):
+ def render(self, generator, op):
+ this = op.args[0]
+ field = op.args[1].value
+ if not field.startswith('o'):
+ generator.load_void()
+ else:
+ value = op.args[2]
+ field_name = field[1:]
+ self.run_it(generator, this, field_name, value)
+
+ def run_it(self, generator, this, field_name, value):
+ generator.load(this)
+ generator.load_special(value)
+ generator.set_field(None, field_name)
+
+class _SetPredefinedField(_SetBuiltinField):
+ def __init__(self, field):
+ self.field = field
+
+ def render(self, generator, op):
+ value = op.args[2]
+ this = op.args[1]
+ self.run_it(generator, this, self.field, value)
+
+class _SetExternalField(_SetBuiltinField):
+ def render(self, generator, op):
+ self.run_it(generator, op.args[0], op.args[1].value, op.args[2])
+
+SetBuiltinField = _SetBuiltinField()
+SetExternalField = _SetExternalField()
+
+class _CallMethod(_Call):
+ def render(self, generator, op):
+ method = op.args[0]
+ self._render_method(generator, method.value, op.args[1:])
+
+class _CallBuiltinObject(_Call):
+ def render(self, generator, op):
+ this = op.args[1].concretetype
+ method = op.args[0]
+ method_name = this._methods[method.value]._name[1:]
+ generator.load(op.args[1])
+ self._render_builtin_method(generator, method_name, op.args[1:])
+
+class _CallExternalObject(_Call):
+ def render(self, generator, op):
+ this = op.args[1].concretetype
+ method = op.args[0]
+ method_name = method.value
+ #generator.load(op.args[1])
+ self._render_builtin_method(generator, method_name, op.args[1:])
+
+CallBuiltinObject = _CallBuiltinObject()
+CallExternalObject = _CallExternalObject()
+
+class _IsInstance(MicroInstruction):
+ def render(self, generator, op):
+ # FIXME: just temporary hack
+ generator.load(op.args[0])
+ generator.ilasm.load_const(op.args[1].value._name.replace('.', '_'))#[-1])
+ generator.cast_function("isinstanceof", 2)
+
+class _IndirectCall(MicroInstruction):
+ def render(self, generator, op):
+ for func_arg in op.args[1:]: # push parameters
+ generator.load(func_arg)
+ generator.call_external(op.args[0].name, op.args[1:])
+
+class _SetTimeout(MicroInstruction):
+ # FIXME: Dirty hack for javascript callback stuff
+ def render(self, generator, op):
+ val = op.args[1].value
+ assert(isinstance(val, ootype._static_meth))
+ #if isinstance(val, ootype.StaticMethod):
+ real_name = val._name
+ generator.db.pending_function(val.graph)
+ #generator.db.pending_function(val.graph)
+ #else:
+ # concrete = val.concretize()
+ # real_name = concrete.value._name
+ # generator.db.pending_function(concrete.value.graph)
+ generator.load_str("'%s()'" % real_name)
+ generator.load(op.args[2])
+ generator.call_external('setTimeout',[0]*2)
+
+class _DiscardStack(MicroInstruction):
+ def render(self, generator, op):
+ generator.clean_stack()
+
+class SetOnEvent(MicroInstruction):
+ def __init__(self, field):
+ self.field = field
+
+ # FIXME: Dirty hack for javascript callback stuff
+ def render(self, generator, op):
+ val = op.args[1].value
+ val = val.concretize().value
+ assert(isinstance(val, ootype._static_meth))
+ real_name = val._name
+ generator.db.pending_function(val.graph)
+ generator.load_str("document")
+ generator.load_str(real_name)
+ generator.set_field(None, self.field)
+
+class _CheckLength(MicroInstruction):
+ def render(self, generator, op):
+ assert not generator.ilasm.right_hand
+
+class _ListRemove(MicroInstruction):
+ def render(self, generator, op):
+ generator.list_getitem(op.args[1], op.args[2])
+ generator.call_external('delete', [0])
+
+ListRemove = _ListRemove()
+CheckLength = _CheckLength()
+SetTimeout = _SetTimeout()
+IndirectCall = _IndirectCall()
+IsInstance = _IsInstance()
+CallMethod = _CallMethod()
+CopyName = [PushAllArgs, _SameAs ()]
+CastString = _CastFun("convertToString", 1)
+SameAs = CopyName
+DiscardStack = _DiscardStack()
+
+def fix_opcodes(opcodes):
+ for key, value in opcodes.iteritems():
+ if type(value) is str:
+ value = InstructionList([PushAllArgs, value, StoreResult, CheckLength])
+ elif value == []:
+ value = InstructionList([CheckLength])
+ elif value is not None:
+ if StoreResult not in value:
+ value.append(StoreResult)
+ if CheckLength not in value:
+ value.append(CheckLength)
+ value = InstructionList(value)
+
+ opcodes[key] = value
Added: pypy/branch/avm/pypy/translator/avm/records.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/records.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,238 @@
+
+from pypy.translator.avm.util import BitStream
+
+class RecordHeader(object):
+
+ def __init__(self, type, length):
+ self.type = type
+ self.length = length
+
+ def serialize(self):
+ bits = BitStream()
+ bits.write_bit_value(type, 6)
+ if length < 0x3F:
+ bits.write_bit_value(self.length, 10)
+ else:
+ bits.write_bit_value(0x3F, 10)
+ bits.write_bit_value(self.length, 32)
+ return bits
+
+ def parse(self, bitstream):
+ self.type = bitstream.read_bit_value(6)
+ self.length = bitstream.read_bit_value(10)
+ if self.length >= 0x3F:
+ self.length = bits.read_bit_value(32)
+
+class Rect(object):
+
+ def __init__(self, XMin=0, XMax=0, YMin=0, YMax=0):
+ self.XMin = XMin
+ self.XMax = XMax
+ self.YMin = YMin
+ self.YMax = YMax
+
+ def union(self, rect):
+ return Rect(min(self.XMin, rect.XMin),
+ max(self.XMax, rect.XMax),
+ min(self.YMin, rect.YMin),
+ max(self.YMax, rect.YMax))
+
+ def serialize(self):
+ if XMin > XMax or YMin > Max:
+ raise ValueError, "Maximum values in a RECT must be larger than the minimum values."
+
+ # Find our values in twips.
+ twpXMin = self.XMin * 20
+ twpXMax = self.XMax * 20
+ twpYMin = self.YMin * 20
+ twpYMax = self.YMax * 20
+
+ # Find the number of bits required to store the longest
+ # value, then add one to account for the sign bit.
+ longest = max(abs(twpXMin), abs(twpXMax), abs(twpYMin), abs(twpYMax))
+ import math
+ NBits = int(math.ceil(math.log(longest, 2))) + 1
+
+ if NBits > 31:
+ raise ValueError, "Number of bits per value field cannot exceede 31."
+
+ # And write out our bits.
+ bits = BitStream()
+ bits.write_bit_value(NBits, 5)
+ bits.write_bit_value(twpXMin, NBits)
+ bits.write_bit_value(twpXMax, NBits)
+ bits.write_bit_value(twpYMin, NBits)
+ bits.write_bit_value(twpYMax, NBits)
+
+ return bits
+
+ def parse(self, bitstream):
+
+ NBits = bits.read_bit_value(5)
+ self.XMin = bits.read_bit_value(NBits)
+ self.XMax = bits.read_bit_value(NBits)
+ self.YMin = bits.read_bit_value(NBits)
+ self.YMax = bits.read_bit_value(NBits)
+
+class XY(object):
+
+ def __init__(self, X=0, Y=0):
+ self.X = 0
+ self.Y = 0
+
+ def serialize(self):
+ # Convert to twips plz.
+ twpX = self.X * 20
+ twpY = self.Y * 20
+
+ # Find the number of bits required to store the longest
+ # value, then add one to account for the sign bit.
+ longest = max(abs(twpX), abas(twpY))
+ import math
+ NBits = int(math.ceil(math.log(longest, 2)))+1
+
+ bits = BitStream()
+ bits.write_bit_value(NBits, 5)
+ bits.write_bit_value(twpX, NBits)
+ bits.write_bit_value(twpY, NBits)
+
+ return bits
+
+ def parse(self, bitstream):
+
+ NBits = bits.read_bit_value(5)
+ self.X = bits.read_bit_value(NBits)
+ self.Y = bits.read_bit_value(NBits)
+
+class RGB(object):
+
+ def __init__(self, color):
+ self.color = color & 0xFFFFFF
+
+ def serialize(self):
+ bits = BitStream()
+ bits.write_bit_value(self.color, 24)
+ return bits
+
+ def parse(self, bitstream):
+ self.color = bitstream.read_bit_value(24)
+
+class RGBA(RGB):
+
+ def __init__(self, color, alpha=1.0):
+ RGB.__init__(self, color)
+ self.alpha = alpha
+
+ def serialize(self):
+ bits = RGB.serialize(self)
+ bits.write_bit_value(int(self.alpha * 0xFF), 8)
+ return bits
+
+ def parse(self, bitstream):
+ RGB.parse(self, bitstream)
+ self.alpha = bitstream.read_bit_value(8) / 0xFF
+
+class Shape(object):
+
+ def __init__(self):
+ self.shapes = []
+
+ self.edge_bounds = Rect()
+ self.shape_bounds = Rect()
+
+ self.has_scaling = False
+ self.has_non_scaling = False
+
+ self.bounds_calculated = False
+
+ def add_shape_record(self, shape):
+ self.shapes.append(shape)
+ self.bounds_calculated = False
+
+ def add_shape(self, shape):
+ self.shapes.expand(shape.shapes)
+ self.bounds_calculated = False
+
+ def serialize(self):
+ if EndShapeRecord not in self.shapes:
+ shapes.append(EndShapeRecord())
+
+ bits = BitArray()
+
+ bits.write_bit_value(0, 8) # NumFillBits and NumLineBits
+ for records in self.shapes:
+ bits += record.serialize()
+
+ return bits
+
+ def calculate_bounds(self):
+
+ if self.bounds_calculated:
+ return
+
+ last_x, last_y = 0, 0
+ for record in shapes:
+ last_x, last_y, has_scale, has_non_scale = record.calculate_bounds(last, self.shape_bounds, self.edge_bounds)
+ if has_scale:
+ self.has_scaling = True
+ if has_non_scale:
+ self.has_non_scaling = True
+
+ self.bounds_calculated = True
+
+def ShapeWithStyle(Shape):
+
+ def __init__(self, fills=[], strokes=[]):
+ Shape.__init__(self)
+ self.fills = fills
+ self.strokes = strokes
+
+ def add_fill_style(self, style):
+ self.fills.append(style)
+
+ def add_line_style(self, style):
+ self.strokes.append(style)
+
+ def add_shape(self, shape):
+ Shape.add_shape(self, shape)
+ try:
+ self.fills += shape.fills
+ self.strokes += shape.strokes
+ except AttributeError:
+ pass
+
+ @static_method
+ def __serialize_style_list(list):
+ bits = BitStream()
+
+ if len(list) <= 0xFF:
+ bits.write_bit_value(len(list), 8)
+ else:
+ bits.write_bit_value(0xFF, 8)
+ bits.write_bit_value(len(list), 16)
+
+ for style in list:
+ bits += style.serialize()
+
+ return bits
+
+ def serialize(self):
+ bits = BitStream()
+ bits += __serialize_style_list(self.fills)
+ bits += __serialize_style_list(self.strokes)
+ import math
+ bits.write_bit_value(math.ceil(math.log(len(self.fills), 2)), 4)
+ bits.write_bit_value(math.ceil(math.log(len(self.strokes), 2)), 4)
+ return bits
+
+class LineStyle(object):
+
+ def __init__(self, width=1, color=0, alpha=1.0):
+ self.width = width
+ self.color = RGBA(color, alpha)
+
+ def serialize(self):
+ bits = BitStream()
+ bits.write_bit_value(self.width * 20, 16)
+ bits += color.serialize()
+ return bits
Added: pypy/branch/avm/pypy/translator/avm/support.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/support.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,50 @@
+from pypy.translator.gensupp import NameManager
+#from pypy.translator.js.optimize import is_optimized_function
+
+class AVM1NameManager(NameManager):
+ def __init__(self, db):
+ NameManager.__init__(self)
+ self.db = db
+ self.reserved = {}
+
+
+ # Source:
+ # http://livedocs.adobe.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001236.html
+ reserved_words = '''add and break case catch class continue default
+ delete do dynamic else eq extends finally for function ge get gt if
+ ifFrameLoaded implements import in instanceof interface intrinsic
+ le lt ne new not on onClipEvent or private public return setw
+ static switch tellTarget this throw try typeof var void while with'''
+
+ for name in reserved_words.split():
+ self.reserved[name] = True
+
+ predefined_classes_and_objects = '''
+ Accessibility Accordion Alert Array Binding Boolean Button Camera
+ CellRenderer CheckBox Collection Color ComboBox ComponentMixins ContextMenu
+ ContextMenuItem CustomActions CustomFormatterCustomValidator DataGrid
+ DataHolder DataProvider DataSet DataType Date DateChooser DateField Delta
+ DeltaItem DeltaPacket DepthManager EndPoint Error FocusManager Form Function
+ Iterator Key Label List Loader LoadVars LocalConnection Log Math Media Menu
+ MenuBar Microphone Mouse MovieClip MovieClipLoader NetConnection NetStream
+ Number NumericStepper Object PendingCall PopUpManager PrintJob ProgressBar
+ RadioButton RDBMSResolver Screen ScrollPane Selection SharedObject Slide SOAPCall
+ Sound Stage String StyleManager System TextArea TextField TextFormat TextInput
+ TextSnapshot TransferObject Tree TreeDataProvider TypedValue UIComponent
+ UIEventDispatcher UIObject Video WebService WebServiceConnector Window XML
+ XMLConnector XUpdateResolver'''
+
+ for name in predefined_classes_and_objects.split():
+ self.reserved[name] = True
+
+ self.make_reserved_names(' '.join(self.reserved))
+
+ self.predefined = set(predefined_classes_and_objects)
+
+ #def uniquename(self, name, lenmax=0):
+ # return NameManager.uniquename(self, , lenmax)
+
+ def ensure_non_reserved(self, name):
+ while name in self.reserved:
+ name += '_'
+ return name
Added: pypy/branch/avm/pypy/translator/avm/swf.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/swf.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,59 @@
+
+
+class SwfData(object):
+
+ def __init__(self, width=600, height=400, fps=24, compress=False, version=10):
+ self.width = width
+ self.height = height
+ self.fps = fps
+ self.compress = compress
+ self.version = version
+ self.frame_count = 1
+
+ self.tags = []
+
+ def __getitem__(self, i):
+ return self.tags.__getitem__(i)
+
+ def __iadd__(self, other):
+ if hasattr(other, "TAG_TYPE"):
+ self.add_tag(other)
+ else:
+ self.add_tags(other)
+
+ def add_tag(self, tag):
+ if self.version > tag.min_version:
+ self.tags.append(tag)
+
+ def add_tags(self, tag_container):
+ if hasattr(tag_container, "tags"):
+ self.tags += tag_container.tags
+ else:
+ self.tags += tag_container
+
+ def serialize(self):
+ final_bytes = []
+
+ header = __gen_header()
+ data = __gen_data_stub()
+ data += [tag.serialize() for tag in self.tags]
+
+ header[3] = len(header) + len("".join(data)) # FileSize
+ if self.compress:
+ import zlib
+ data = zlib.compress(data)
+
+ return "".join(header + data)
+
+ def __gen_header(self):
+ import struct
+ return ("CWS" if self.compress else "FWS") + struct.pack("BL", self.version, 0)
+
+ def __gen_data_stub(self):
+ from util import BitStream
+ from records import Rect
+ data = BitStream()
+ data += Rect(XMax=width, YMax=height).serialize()
+ data.write_bit_value(fps, 16)
+ data.write_bit_value(frame_count, 16)
+ return data.serialize()
Added: pypy/branch/avm/pypy/translator/avm/tags.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/tags.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,46 @@
+
+from pypy.translator.avm.util import BitStream
+from pypy.translator.avm.avm1 import Block
+
+class SwfTag(object):
+
+ TAG_TYPE = -1
+ TAG_MIN_VERSION = -1
+
+ def serialize_data(self):
+ return ""
+
+ def serialize(self):
+ data = self.serialize_data(self)
+ return RecordHeader(self.TAG_TYPE, len(data)).serialize().serialize() + data
+
+class SetBackgroundColor(SwfTag):
+
+ TAG_TYPE = 9
+ TAG_MIN_VERSION = 1
+
+ def __init__(self, color):
+ self.color = color
+
+ def serialize_data(self):
+ import struct
+ return struct.pack("LB", color >> 8 & 0xFFFF, color & 0xFF)
+
+class DoAction(SwfTag, Block):
+
+ TAG_TYPE = 12
+ TAG_MIN_VERSION = 3
+
+ def __init__(self):
+ Block.__init__(self, True)
+
+ def serialize_data(self):
+ return Block.serialize(self)
+
+class End(SwfTag):
+
+ TAG_TYPE = 0
+ TAG_MIN_VERSION = 0
+
+ def serialize(self):
+ return "\0\0"
Added: pypy/branch/avm/pypy/translator/avm/test/browsertest.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/test/browsertest.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,97 @@
+from BaseHTTPServer import HTTPServer as BaseHTTPServer, BaseHTTPRequestHandler
+import py
+from os import system
+from cgi import parse_qs
+from sys import platform
+from time import sleep
+import webbrowser
+from pypy.translator.avm.log import log
+log = log.browsertest
+
+class HTTPServer(BaseHTTPServer):
+ allow_reuse_address = True
+
+class config:
+ http_port = 10001
+
+ html_page = """<html>
+<head>
+<title>PyPy AVM1 Test Case: %s</title>
+</head>
+<body onload="runTest()">
+<object type="application/x-shockwave-flash" data="testcase.swf" width="400" height="300">
+<param name="movie" value="test.swf" />
+</object>
+</body>
+</html>"""
+
+ crossdomain_xml="""<cross-domain-policy>
+<allow-access-from domain="*" secure="false"/>
+</cross-domain-policy>"""
+
+class TestCase(object):
+ def __init__(self, name, swfdata):
+ self.testcasename = name
+ self.swfdata = swfdata
+ self.result = None
+
+class TestHandler(BaseHTTPRequestHandler):
+ """The HTTP handler class that provides the tests and handles results"""
+
+ def do_GET(self):
+ global do_status
+ if self.path == "/test.html":
+ data = config.html_page % testcase.xtestcasename
+ mime = 'text/html'
+ elif self.path == "/test.swf":
+ data = testcase.swfdata
+ mime = 'application/x-shockwave-flash'
+ elif self.path == "/crossdomain.xml":
+ data = config.crossdomain_xml
+ mime = 'text/xml'
+ self.serve_data(mime, data)
+ do_status = 'do_GET'
+
+ def do_POST(self):
+ global do_status
+ if self.path == "/test.result":
+ form = parse_qs(self.rfile.read(int(self.headers['content-length'])))
+ testcase.result = form['result'][0]
+ do_status = 'do_POST'
+
+ def serve_data(self, content_type, data):
+ self.send_response(200)
+ self.send_header("Content-type", content_type)
+ self.send_header("Content-length", len(data))
+ self.end_headers()
+ self.wfile.write(data)
+
+
+class BrowserTest(object):
+ """The browser driver"""
+
+ def start_server(self, port, html_page, is_interactive):
+ server_address = ('', port)
+ self.httpd = HTTPServer(server_address, TestHandler)
+ self.httpd.is_interactive = is_interactive
+ self.httpd.html_page = html_page
+
+ def get_result(self):
+ global do_status
+ do_status = None
+ while do_status != 'do_GET':
+ self.httpd.handle_request()
+ while do_status != 'do_POST':
+ self.httpd.handle_request()
+ return jstest.result
+
+
+def browsertest(testcase, swfdata):
+ global driver, testcase
+ testcase = TestCase(str(testcase), str(swfdata))
+ driver = BrowserTest()
+ driver.start_server(config.http_port, html_page, is_interactive)
+ webbrowser.open('http://localhost:%d/test.html' % config.http_port)
+
+ result = driver.get_result()
+ return result
Added: pypy/branch/avm/pypy/translator/avm/test/runtest.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/test/runtest.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,140 @@
+
+import py, os, re, subprocess
+from pypy.translator.translator import TranslationContext
+from pypy.translator.backendopt.all import backend_optimizations
+from pypy.translator.avm.avm import AVM1
+from pypy.translator.avm.test.browsertest import browsertest, TestCase
+# from pypy.translator.avm import conftest
+from pypy.translator.avm.log import log
+from pypy.conftest import option
+from pypy.rpython.test.tool import BaseRtypingTest, OORtypeMixin
+from pypy.rlib.nonconst import NonConstant
+from pypy.rpython.ootypesystem import ootype
+
+from pypy.rpython.llinterp import LLException
+
+log = log.runtest
+
+class AVM1Exception(object):
+
+class compile_function(object):
+ def __init__(self, function, annotations, stackless=False, view=False, root=None, policy=None):
+
+ t = TranslationContext()
+
+ if policy is None:
+ from pypy.annotation.policy import AnnotatorPolicy
+ policy = AnnotatorPolicy()
+ policy.allow_someobjects = False
+
+ self.root = root
+
+ ann = t.buildannotator(policy=policy)
+ ann.build_types(function, annotations)
+ if view or option.view:
+ t.view()
+
+ t.buildrtyper(type_system="ootype").specialize()
+
+ if view or option.view:
+ t.view()
+
+ self.avm = AVM1(t, function, stackless)
+
+ def _conv(self, v):
+ if isinstance(v, str):
+ return repr(v)
+ return str(v).lower()
+
+ def call(self, entry_function):
+
+ if entry_function is None:
+ entry_function = self.avm.translator.graphs[0].name
+ else:
+ entry_function = self.avm.translator.annotator.bookeeper.getdesc(entry_function).cached_graph(None)
+
+ output = browsertest("Test Name", self.avm.serialize())
+ return self.reinterpret(output)
+
+ @classmethod
+ def reinterpret(cls, s):
+ if s == 'false':
+ return False
+ elif s == 'true':
+ return True
+ elif s == 'undefined' or s == 'null':
+ return None
+ elif s == 'inf':
+ return 1e400
+ elif s == 'NaN':
+ return 1e400 / 1e400
+ elif s.startswith('[') or s.startswith('('):
+ contents = s[1:-1].split(',')
+ return [self.reintepret(i) for i in contents]
+ else:
+ try:
+ res = float(s)
+ if float(int(res)) == float(res):
+ return int(res)
+ return res
+ except ValueError:
+ return str(s)
+
+class AVM1Test(BaseRtypingTest, OORtypeMixin):
+ def _compile(self, _fn, args, policy=None):
+ argnames = _fn.func_code.co_varnames[:_fn.func_code.co_argcount]
+ func_name = _fn.func_name
+ if func_name == '<lambda>':
+ func_name = 'func'
+ source = py.code.Source("""
+ def %s():
+ from pypy.rlib.nonconst import NonConstant
+ res = _fn(%s)
+ if isinstance(res, type(None)):
+ return None
+ else:
+ return str(res)"""
+ % (func_name, ",".join(["%s=NonConstant(%r)" % (name, i) for
+ name, i in zip(argnames, args)])))
+ exec source.compile() in locals()
+ return compile_function(locals()[func_name], [], policy=policy)
+
+ def interpret(self, fn, args, policy=None):
+ f = self.compile(fn, args, policy)
+ res = f(*args)
+ return res
+
+ def interpret_raises(self, exception, fn, args):
+ try:
+ res = self.interpret(fn, args)
+ except AVM1Exception, e:
+ s = e.args[0]
+ assert s.startswith('uncaught exception')
+ assert re.search(exception.__name__, s)
+ else:
+ raise AssertionError("Did not raise, returned %s" % res)
+
+ def string_to_ll(self, s):
+ return s
+
+ def ll_to_string(self, s):
+ return str(s)
+
+ def ll_to_list(self, l):
+ return l
+
+ def ll_unpack_tuple(self, t, length):
+ assert len(t) == length
+ return tuple(t)
+
+ def class_name(self, value):
+ return value[:-8].split('.')[-1]
+
+ def is_of_instance_type(self, val):
+ m = re.match("^<.* object>$", val)
+ return bool(m)
+
+ def read_attr(self, obj, name):
+ py.test.skip('read_attr not supported on genavm tests')
+
+def check_source_contains(compiled_function, pattern):
Added: pypy/branch/avm/pypy/translator/avm/util.py
==============================================================================
--- (empty file)
+++ pypy/branch/avm/pypy/translator/avm/util.py Fri Dec 19 20:01:17 2008
@@ -0,0 +1,196 @@
+
+import struct, os
+
+ALIGN_LEFT = "left"
+ALIGN_RIGHT = "right"
+
+class BitStream(object):
+
+ """ BitStream is a class for taking care of data structures that are bit-packed, like SWF."""
+
+ def __init__(self, bits=[]):
+ """
+ Constructor.
+ """
+ self.bits = bits
+ self.cursor = 0
+
+ def read_bit(self):
+ """Reads a bit from the bit stream and returns it as either True or False. IndexError is thrown if reading past the end of the stream."""
+ self.cursor += 1
+ return self.bits[self.cursor-1]
+
+ def read_bits(self, length):
+ """Reads length bits and return them in their own bit stream."""
+ self.cursor += length
+ return BitStream(self.bits[self.cursor-length:self.cursor])
+
+ def write_bit(self, value):
+ """Writes the boolean value to the bit stream."""
+ if self.cursor < len(self.bits):
+ self.bits[self.cursor] = bool(value)
+ else:
+ self.bits.append(bool(value))
+ self.cursor += 1
+
+ def write_bits(self, bits, offset=0, length=0):
+ """Writes length bits from bits to this bit stream, starting reading at offset. If length
+ is 0, the entire stream is used."""
+ if length < 1: length = len(bits)
+ self.bits[self.cursor:self.cursor+length] = bits[offset:offset+length]
+ self.cursor += length
+
+ def read_bit_value(self, length):
+ """Read length bits and return a number containing those bits with the last bit read being
+ the least significant bit."""
+ n = 0
+ for i in xrange(length-1, -1, -1):
+ n |= self.read_bit() << i
+ return n
+
+ def write_bit_value(self, value, length=-1):
+ """Writes an int to the specified number of bits in the stream, the most significant bit
+ first. If length is not specified or negative, the log base 2 of value is taken."""
+ if int(value) != value:
+ self.write_fixed_value(value, length)
+ return
+
+ if length < 0:
+ import math
+ try:
+ length = int(math.ceil(math.log(value, 2))) # Get the log base 2, or number of bits value will fit in.
+ except ValueError:
+ length = 1
+
+ for i in xrange(length-1, -1, -1):
+ self.write_bit(value & (1 << i))
+
+ def read_fixed_value(self, length, eight_bit_mantissa=False):
+ """Reads a fixed point number of length. If eight_bit_mantissa is True, an
+ 8.8 format is used instead of a 16.16 format."""
+ min_length = 8 if eight_bit_mantissa else 16
+ if length < min_length:
+ raise ValueError, "Length must be greater than or equal to %(m)s, as %(m)s.%(m)s FB requires at \
+ least %(m)s bits to store." % {"m": min_length}
+
+ return self.read_bit_value(length) / 0x100 if eight_bit_mantissa else 0x10000
+
+ def write_fixed_value(self, value, length=-1, eight_bit_mantissa=False):
+ """Writes a fixed point number of length, whole part first. If eight_bit_mantissa is True,
+ an 8.8 format is used instead of a 16.16 format. If length is negative, it will be calculated for."""
+ self.writeBitValue( value * ( 0x100 if eight_bit_mantissa else 0x10000 ), length )
+
+ _EXPN_BIAS = {16: 16, 32: 127, 64: 1023}
+ _N_EXPN_BITS = {16: 5, 32: 8, 64: 52}
+ _N_FRAC_BITS = {16: 10, 32: 23, 64: 52}
+ _FLOAT_NAME = {16: "float16", 32: "float", 64: "double"}
+
+ def read_float_value(self, length=16):
+ """Reads a floating point number of length, which must be 16 (float16), 32 (float),
+ or 64 (double). See: http://en.wikipedia.org/wiki/IEEE_floating-point_standard"""
+ if length not in _FLOAT_NAME:
+ raise ValueError, "Length in read_float_value is not 16, 32 or 64."
+
+ sign = self.read_bit()
+ expn = self.read_bit_value(_N_EXPN_BITS[length])
+ frac = self.read_bit_value(_N_FRAC_BITS[length])
+
+ frac_total = 1 << _N_FRAN_BITS[length]
+
+ if expn == 0:
+ if frac == 0:
+ return 0
+ else:
+ return ~frac + 1 if sign else frac
+ elif expn == frac_total - 1:
+ if frac == 0:
+ return float("-inf") if sign else float("inf")
+ else:
+ return float("nan")
+
+ return (-1 if sign else 1) * ( 2**(expn-_EXPN_BIAS[length]) ) * ( 1 + frac / frac_total )
+
+ def write_float_value(self, value, length=16):
+ """Writes a floating point number of length, which must be 16 (float16),
+ 32 (float), or 64 (double). See: http://en.wikipedia.org/wiki/IEEE_floating-point_standard"""
+ if n == 0: # n is zero, so we don't care about length
+ self.write_bit_value(0, length)
+
+ import math
+ if math.isnan(value):
+ self.one_fill(length)
+ return
+ elif value == float("-inf"): # negative infinity
+ self.one_fill(_N_EXPN_BITS[length] + 1) # sign merged
+ self.zero_fill(_N_FRAC_BITS[length])
+ return
+ elif value == float("inf"): # positive infinity
+ self.write_bit(False)
+ self.one_fill(_N_EXPN_BITS[length])
+ self.zero_fill(_N_FRAC_BITS[length])
+ return
+
+ if n < 0:
+ self.write_bit(True)
+ n = ~n + 1
+ else:
+ self.write_bit(False)
+
+ exp = _EXPN_BIAS[length]
+ if value < 1:
+ while int(value) != 1:
+ value *= 2
+ exp -= 1
+ else:
+ while int(value) != 1:
+ value /= 2
+ exp += 1
+
+ if exp < 0 or exp > ( 1 << _N_EXPN_BITS[length] ):
+ raise ValueError, "Exponent out of range in %s [%d]." % (_FLOAT_NAME[length], length)
+
+ frac_total = 1 << _N_FRAC_BITS
+ self.write_bit_value(exp, _N_EXPN_BITS[length])
+ self.write_bit_value(int((value-1)*frac_total) & (frac_total - 1), _N_FRAC_BITS[length])
+
+
+ def one_fill(self, amount):
+ """Fills amount bits with one. The equivalent of calling
+ self.write_boolean(True) amount times, but more efficient."""
+ self.bits[self.cursor:self.cursor+amount] = [True] * amount
+
+ def zero_fill(self, amount):
+ """Fills amount bits with zero. The equivalent of calling
+ self.write_boolean(False) amount times, but more efficient."""
+ self.bits[self.cursor:self.cursor+amount] = [False] * amount
+
+ def seek(self, offset, whence=os.SEEK_SET):
+ if whence == os.SEEK_SET:
+ self.cursor = offset
+ elif whence == os.SEEK_CUR:
+ self.cursor += offset
+ elif whence == os.SEEK_END:
+ self.cursor = len(self.bits) - abs(offset)
+
+ def rewind(self):
+ self.seek(0, os.SEEK_SET)
+
+ def skip_to_end(self):
+ self.seek(0, os.SEEK_END)
+
+ def serialize(self, align=ALIGN_RIGHT, endianness="<"):
+ """Serialize bit array into a byte string, aligning either on the right
+ (ALIGN_RIGHT) or left (ALIGN_LEFT)"""
+ list = self[:]
+ leftover = len(list) % 8
+ if leftover > 0 and align == BitStream.ALIGN_RIGHT:
+ list[:0] = [False] * (8-leftover) # Insert some False values to pad the list so it is aligned to the right.
+ list = BitStream(list)
+ bytes = [list.read_bit_value(8) for i in range(math.ceil(bits/8.0))]
+ return struct.pack("%s%dB" % (endianness, len(bytes)), *bytes)
+
+ def parse(self, string, endianness="<"):
+ """Parse a bit array from a byte string into this BitStream."""
+ bytes = list(struct.unpack("%s%dB" % (endianness, len(string))))
+ for byte in bytes:
+ self.write_bit_value(byte, 8)
More information about the Pypy-commit
mailing list