[pypy-svn] r18227 - in pypy/dist/pypy/translator/js: . test
ericvrp at codespeak.net
ericvrp at codespeak.net
Thu Oct 6 22:24:07 CEST 2005
Author: ericvrp
Date: Thu Oct 6 22:24:04 2005
New Revision: 18227
Added:
pypy/dist/pypy/translator/js/
pypy/dist/pypy/translator/js/__init__.py (contents, props changed)
pypy/dist/pypy/translator/js/arraynode.py (contents, props changed)
pypy/dist/pypy/translator/js/codewriter.py (contents, props changed)
pypy/dist/pypy/translator/js/database.py (contents, props changed)
pypy/dist/pypy/translator/js/exception.py (contents, props changed)
pypy/dist/pypy/translator/js/extfuncnode.py (contents, props changed)
pypy/dist/pypy/translator/js/funcnode.py (contents, props changed)
pypy/dist/pypy/translator/js/gc.py (contents, props changed)
pypy/dist/pypy/translator/js/js.py (contents, props changed)
pypy/dist/pypy/translator/js/log.py (contents, props changed)
pypy/dist/pypy/translator/js/node.py (contents, props changed)
pypy/dist/pypy/translator/js/opaquenode.py (contents, props changed)
pypy/dist/pypy/translator/js/opwriter.py (contents, props changed)
pypy/dist/pypy/translator/js/structnode.py (contents, props changed)
pypy/dist/pypy/translator/js/test/
pypy/dist/pypy/translator/js/test/__init__.py (contents, props changed)
pypy/dist/pypy/translator/js/test/runtest.py (contents, props changed)
pypy/dist/pypy/translator/js/test/test_trivial.py (contents, props changed)
pypy/dist/pypy/translator/js/varsize.py (contents, props changed)
Log:
Let me be ambitious by adding a Javascript backend.
This is at the moment still a stripped down version of the llvm backend
and as such does not work!
Added: pypy/dist/pypy/translator/js/__init__.py
==============================================================================
Added: pypy/dist/pypy/translator/js/arraynode.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/arraynode.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,198 @@
+import py
+from pypy.rpython import lltype
+from pypy.translator.llvm.log import log
+from pypy.translator.llvm.node import LLVMNode, ConstantLLVMNode
+from pypy.translator.llvm import varsize
+log = log.structnode
+
+class ArrayTypeNode(LLVMNode):
+ __slots__ = "db array arraytype ref constructor_ref constructor_decl".split()
+
+ def __init__(self, db, array):
+ assert isinstance(array, lltype.Array)
+ self.db = db
+ self.array = array
+ self.arraytype = arraytype = array.OF
+ # ref is used to reference the arraytype in llvm source
+ # constructor_ref is used to reference the constructor
+ # for the array type in llvm source code
+ # constructor_decl is used to declare the constructor
+ # for the array type (see writeimpl)
+ name = ""
+ if isinstance(arraytype, lltype.Ptr):
+ name += "ptr_"
+ arraytype = arraytype.TO
+ if hasattr(arraytype, "_name"):
+ name += arraytype._name
+ else:
+ name += str(arraytype)
+
+ self.ref = self.make_ref('%arraytype.', name)
+ self.constructor_ref = self.make_ref('%new.array.', name)
+ self.constructor_decl = "%s * %s(%s %%len)" % \
+ (self.ref,
+ self.constructor_ref,
+ self.db.get_machine_word())
+
+ def __str__(self):
+ return "<ArrayTypeNode %r>" % self.ref
+
+ def setup(self):
+ self.db.prepare_type(self.arraytype)
+
+ # ______________________________________________________________________
+ # entry points from genllvm
+ #
+ def writedatatypedecl(self, codewriter):
+ codewriter.arraydef(self.ref,
+ self.db.get_machine_word(),
+ self.db.repr_type(self.arraytype))
+
+ def writedecl(self, codewriter):
+ # declaration for constructor
+ codewriter.declare(self.constructor_decl)
+
+ def writeimpl(self, codewriter):
+ log.writeimpl(self.ref)
+ varsize.write_constructor(self.db, codewriter, self.ref,
+ self.constructor_decl,
+ self.array)
+
+
+class VoidArrayTypeNode(LLVMNode):
+ __slots__ = "db array ref".split()
+
+ def __init__(self, db, array):
+ assert isinstance(array, lltype.Array)
+ self.db = db
+ self.array = array
+ self.ref = "%arraytype.Void"
+
+ def writedatatypedecl(self, codewriter):
+ td = "%s = type { %s }" % (self.ref, self.db.get_machine_word())
+ codewriter.append(td)
+
+class ArrayNode(ConstantLLVMNode):
+ """ An arraynode. Elements can be
+ a primitive,
+ a struct,
+ pointer to struct/array
+ """
+ __slots__ = "db value arraytype ref".split()
+
+ def __init__(self, db, value):
+ assert isinstance(lltype.typeOf(value), lltype.Array)
+ self.db = db
+ self.value = value
+ self.arraytype = lltype.typeOf(value).OF
+ prefix = '%arrayinstance'
+ name = '' #str(value).split()[1]
+ self.ref = self.make_ref(prefix, name)
+
+ def __str__(self):
+ return "<ArrayNode %r>" % (self.ref,)
+
+ def setup(self):
+ for item in self.value.items:
+ self.db.prepare_constant(self.arraytype, item)
+
+ p, c = lltype.parentlink(self.value)
+ p, c = lltype.parentlink(self.value)
+ if p is not None:
+ self.db.prepare_constant(lltype.typeOf(p), p)
+
+ def get_length(self):
+ """ returns logical length of array """
+ items = self.value.items
+ return len(items)
+
+ def get_arrayvalue(self):
+ items = self.value.items
+ l = len(items)
+ r = "[%s]" % ", ".join([self.db.repr_constant(v)[1] for v in items])
+ return l, r
+
+ def get_typerepr(self):
+ arraylen = self.get_arrayvalue()[0]
+ typeval = self.db.repr_type(self.arraytype)
+ return "{ %s, [%s x %s] }" % (self.db.get_machine_word(),
+ arraylen, typeval)
+
+ def get_ref(self):
+ typeval = self.db.repr_type(lltype.typeOf(self.value))
+ ref = "cast (%s* %s to %s*)" % (self.get_typerepr(),
+ self.ref,
+ typeval)
+
+ p, c = lltype.parentlink(self.value)
+ assert p is None, "child arrays are NOT needed by rtyper"
+ return ref
+
+ def get_pbcref(self, toptr):
+ ref = self.ref
+ p, c = lltype.parentlink(self.value)
+ assert p is None, "child arrays are NOT needed by rtyper"
+
+ fromptr = "%s*" % self.get_typerepr()
+ ref = "cast(%s %s to %s)" % (fromptr, ref, toptr)
+ return ref
+
+ def get_childref(self, index):
+ return "getelementptr(%s* %s, int 0, uint 1, int %s)" %(
+ self.get_typerepr(),
+ self.ref,
+ index)
+
+ def constantvalue(self):
+ physicallen, arrayrepr = self.get_arrayvalue()
+ typeval = self.db.repr_type(self.arraytype)
+
+ # first length is logical, second is physical
+ value = "%s %s, [%s x %s] %s" % (self.db.get_machine_word(),
+ self.get_length(),
+ physicallen,
+ typeval,
+ arrayrepr)
+
+ s = "%s {%s}" % (self.get_typerepr(), value)
+ return s
+
+class StrArrayNode(ArrayNode):
+ __slots__ = "".split()
+
+ printables = dict([(ord(i), None) for i in
+ ("0123456789abcdefghijklmnopqrstuvwxyz" +
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "!#$%&()*+,-./:;<=>?@[]^_`{|}~ '")])
+
+ def get_arrayvalue(self):
+ items = self.value.items
+ item_length = len(items)
+ if item_length == 0 or items[-1] != chr(0):
+ items = items + [chr(0)]
+ item_length += 1
+ s = []
+ for c in items:
+ if ord(c) in StrArrayNode.printables:
+ s.append(c)
+ else:
+ s.append("\\%02x" % ord(c))
+
+ r = 'c"%s"' % "".join(s)
+ return item_length, r
+
+class VoidArrayNode(ConstantLLVMNode):
+ __slots__ = "db value ref".split()
+
+ def __init__(self, db, value):
+ assert isinstance(lltype.typeOf(value), lltype.Array)
+ self.db = db
+ self.value = value
+ prefix = '%arrayinstance'
+ name = '' #str(value).split()[1]
+ self.ref = self.make_ref(prefix, name)
+
+ def constantvalue(self):
+ return "{ %s } {%s %s}" % (self.db.get_machine_word(),
+ self.db.get_machine_word(),
+ len(self.value.items))
Added: pypy/dist/pypy/translator/js/codewriter.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/codewriter.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,154 @@
+import py
+from itertools import count
+from pypy.translator.llvm.log import log
+
+log = log.codewriter
+
+DEFAULT_TAIL = '' #/tail
+DEFAULT_CCONV = 'fastcc' #ccc/fastcc
+
+class CodeWriter(object):
+ def __init__(self, f, genllvm):
+ self.f = f
+ self.genllvm = genllvm
+ self.word = genllvm.db.get_machine_word()
+ self.uword = genllvm.db.get_machine_uword()
+
+ def append(self, line):
+ self.f.write(line + '\n')
+
+ def comment(self, line, indent=True):
+ line = ";; " + line
+ if indent:
+ self.indent(line)
+ else:
+ self.append(line)
+
+ def newline(self):
+ self.append("")
+
+ def indent(self, line):
+ self.append(" " + line)
+
+ def label(self, name):
+ self.newline()
+ self.append(" %s:" % name)
+
+ def globalinstance(self, name, typeandata):
+ self.append("%s = %s global %s" % (name, "internal", typeandata))
+
+ def structdef(self, name, typereprs):
+ self.append("%s = type { %s }" %(name, ", ".join(typereprs)))
+
+ def arraydef(self, name, lentype, typerepr):
+ self.append("%s = type { %s, [0 x %s] }" % (name, lentype, typerepr))
+
+ def funcdef(self, name, rettyperepr, argtypereprs):
+ self.append("%s = type %s (%s)" % (name, rettyperepr,
+ ", ".join(argtypereprs)))
+
+ def declare(self, decl, cconv=DEFAULT_CCONV):
+ self.append("declare %s %s" %(cconv, decl,))
+
+ def startimpl(self):
+ self.newline()
+ self.append("implementation")
+ self.newline()
+
+ def br_uncond(self, blockname):
+ self.indent("br label %%%s" %(blockname,))
+
+ def br(self, cond, blockname_false, blockname_true):
+ self.indent("br bool %s, label %%%s, label %%%s"
+ % (cond, blockname_true, blockname_false))
+
+ def switch(self, intty, cond, defaultdest, value_label):
+ labels = ''
+ for value, label in value_label:
+ labels += ' %s %s, label %%%s' % (intty, value, label)
+ self.indent("switch %s %s, label %%%s [%s ]"
+ % (intty, cond, defaultdest, labels))
+
+ def openfunc(self, decl, is_entrynode=False, cconv=DEFAULT_CCONV):
+ self.newline()
+ #if is_entrynode:
+ # linkage_type = ''
+ #else:
+ # linkage_type = 'internal '
+ linkage_type = 'internal '
+ self.append("%s%s %s {" % (linkage_type, cconv, decl,))
+
+ def closefunc(self):
+ self.append("}")
+
+ def ret(self, type_, ref):
+ if type_ == 'void':
+ self.indent("ret void")
+ else:
+ self.indent("ret %s %s" % (type_, ref))
+
+ def phi(self, targetvar, type_, refs, blocknames):
+ assert targetvar.startswith('%')
+ assert refs and len(refs) == len(blocknames), "phi node requires blocks"
+ mergelist = ", ".join(
+ ["[%s, %%%s]" % item
+ for item in zip(refs, blocknames)])
+ s = "%s = phi %s %s" % (targetvar, type_, mergelist)
+ self.indent(s)
+
+ def binaryop(self, name, targetvar, type_, ref1, ref2):
+ self.indent("%s = %s %s %s, %s" % (targetvar, name, type_, ref1, ref2))
+
+ def shiftop(self, name, targetvar, type_, ref1, ref2):
+ self.indent("%s = %s %s %s, ubyte %s" % (targetvar, name, type_, ref1, ref2))
+
+ #from: http://llvm.cs.uiuc.edu/docs/LangRef.html
+ #The optional "tail" marker indicates whether the callee function accesses any
+ # allocas or varargs in the caller. If the "tail" marker is present, the function
+ # call is eligible for tail call optimization. Note that calls may be marked
+ # "tail" even if they do not occur before a ret instruction.
+ def call(self, targetvar, returntype, functionref, argrefs, argtypes, label=None, except_label=None, tail=DEFAULT_TAIL, cconv=DEFAULT_CCONV):
+ if cconv is not 'fastcc':
+ tail_ = ''
+ else:
+ tail_ = tail
+ if tail_:
+ tail_ += ' '
+ args = ", ".join(["%s %s" % item for item in zip(argtypes, argrefs)])
+ if except_label:
+ self.genllvm.exceptionpolicy.invoke(self, targetvar, tail_, cconv, returntype, functionref, args, label, except_label)
+ else:
+ if returntype == 'void':
+ self.indent("%scall %s void %s(%s)" % (tail_, cconv, functionref, args))
+ else:
+ self.indent("%s = %scall %s %s %s(%s)" % (targetvar, tail_, cconv, returntype, functionref, args))
+
+ def cast(self, targetvar, fromtype, fromvar, targettype):
+ if fromtype == 'void' and targettype == 'void':
+ return
+ self.indent("%(targetvar)s = cast %(fromtype)s "
+ "%(fromvar)s to %(targettype)s" % locals())
+
+ def malloc(self, targetvar, type_, size=1, atomic=False, cconv=DEFAULT_CCONV):
+ for s in self.genllvm.gcpolicy.malloc(targetvar, type_, size, atomic, self.word, self.uword).split('\n'):
+ self.indent(s)
+
+ def getelementptr(self, targetvar, type, typevar, *indices):
+ word = self.word
+ res = "%(targetvar)s = getelementptr %(type)s %(typevar)s, %(word)s 0, " % locals()
+ res += ", ".join(["%s %s" % (t, i) for t, i in indices])
+ self.indent(res)
+
+ def load(self, targetvar, targettype, ptr):
+ self.indent("%(targetvar)s = load %(targettype)s* %(ptr)s" % locals())
+
+ def store(self, valuetype, valuevar, ptr):
+ self.indent("store %(valuetype)s %(valuevar)s, "
+ "%(valuetype)s* %(ptr)s" % locals())
+
+ def debugcomment(self, tempname, len, tmpname):
+ word = self.word
+ res = "%s = call ccc %(word)s (sbyte*, ...)* %%printf(" % locals()
+ res += "sbyte* getelementptr ([%s x sbyte]* %s, %(word)s 0, %(word)s 0) )" % locals()
+ res = res % (tmpname, len, tmpname)
+ self.indent(res)
Added: pypy/dist/pypy/translator/js/database.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/database.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,369 @@
+
+import sys
+
+from pypy.translator.llvm.log import log
+from pypy.translator.llvm.funcnode import FuncNode, FuncTypeNode
+from pypy.translator.llvm.extfuncnode import ExternalFuncNode
+from pypy.translator.llvm.structnode import StructNode, StructVarsizeNode, \
+ StructTypeNode, StructVarsizeTypeNode
+from pypy.translator.llvm.arraynode import ArrayNode, StrArrayNode, \
+ VoidArrayNode, ArrayTypeNode, VoidArrayTypeNode
+from pypy.translator.llvm.opaquenode import OpaqueNode, OpaqueTypeNode
+from pypy.translator.llvm.node import ConstantLLVMNode
+from pypy.rpython import lltype
+from pypy.objspace.flow.model import Constant, Variable
+
+log = log.database
+
+class Database(object):
+ def __init__(self, genllvm, translator):
+ self.genllvm = genllvm
+ self.translator = translator
+ self.obj2node = {}
+ self._pendingsetup = []
+ self._tmpcount = 1
+
+ # debug operation comments
+ self._opcomments = {}
+
+ self.primitives_init()
+
+ def primitives_init(self):
+ primitives = {
+ lltype.Char: "sbyte",
+ lltype.Bool: "bool",
+ lltype.Float: "double",
+ lltype.UniChar: "uint",
+ lltype.Void: "void"}
+
+ # 32 bit platform
+ if sys.maxint == 2**31-1:
+ primitives.update({
+ lltype.Signed: "int",
+ lltype.Unsigned: "uint" })
+
+ # 64 bit platform
+ elif sys.maxint == 2**63-1:
+ primitives.update({
+ lltype.Signed: "long",
+ lltype.Unsigned: "ulong" })
+
+ else:
+ assert False, "Unsupported platform"
+
+ self.primitives = primitives
+
+ #_______for debugging llvm code_________________________
+
+ def add_op2comment(self, lenofopstr, op):
+ """ internal method for adding comments on each operation """
+ tmpname = self.repr_tmpvar() + ".comment"
+ self._opcomments[op] = (lenofopstr, tmpname)
+ return tmpname
+
+ def get_op2comment(self, op):
+ """ internal method for adding comments on each operation """
+ return self._opcomments.get(op, None)
+
+ #_______debuggging______________________________________
+
+ def dump_pbcs(self):
+ r = ""
+ for k, v in self.obj2node.iteritems():
+
+ if isinstance(k, lltype.LowLevelType):
+ continue
+
+ assert isinstance(lltype.typeOf(k), lltype.ContainerType)
+ # Only dump top levels
+ p, _ = lltype.parentlink(k)
+ if p is None:
+ ref = v.get_ref()
+ pbc_ref = v.get_ref()
+
+ r += "\ndump_pbcs %s (%s)\n" \
+ "getref -> %s \n" \
+ "pbcref -> %s \n" % (v, k, ref, pbc_ref)
+ return r
+
+ #_______setting up and preperation______________________________
+
+ def create_constant_node(self, type_, value):
+ node = None
+ if isinstance(type_, lltype.FuncType):
+ if getattr(value._callable, "suggested_primitive", False):
+ node = ExternalFuncNode(self, value)
+ else:
+ node = FuncNode(self, value)
+
+ elif isinstance(type_, lltype.Struct):
+ if type_._arrayfld:
+ node = StructVarsizeNode(self, value)
+ else:
+ node = StructNode(self, value)
+
+ elif isinstance(type_, lltype.Array):
+ if type_.OF is lltype.Char:
+ node = StrArrayNode(self, value)
+ elif type_.OF is lltype.Void:
+ node = VoidArrayNode(self, value)
+ else:
+ node = ArrayNode(self, value)
+
+ elif isinstance(type_, lltype.OpaqueType):
+ node = OpaqueNode(self, value)
+
+ assert node is not None, "%s not supported" % (type_)
+ return node
+
+ def addpending(self, key, node):
+ # santity check we at least have a key of the right type
+ assert (isinstance(key, lltype.LowLevelType) or
+ isinstance(lltype.typeOf(key), lltype.ContainerType))
+
+ assert key not in self.obj2node, (
+ "node with key %r already known!" %(key,))
+
+ #log("added to pending nodes:", type(key), node)
+
+ self.obj2node[key] = node
+ self._pendingsetup.append(node)
+
+ def prepare_type(self, type_):
+ if type_ in self.obj2node:
+ return
+ if isinstance(type_, lltype.Primitive):
+ pass
+ elif isinstance(type_, lltype.Ptr):
+ self.prepare_type(type_.TO)
+
+ elif isinstance(type_, lltype.Struct):
+ if type_._arrayfld:
+ self.addpending(type_, StructVarsizeTypeNode(self, type_))
+ else:
+ self.addpending(type_, StructTypeNode(self, type_))
+ elif isinstance(type_, lltype.FuncType):
+ self.addpending(type_, FuncTypeNode(self, type_))
+
+ elif isinstance(type_, lltype.Array):
+ if type_.OF is lltype.Void:
+ self.addpending(type_, VoidArrayTypeNode(self, type_))
+ else:
+ self.addpending(type_, ArrayTypeNode(self, type_))
+
+ elif isinstance(type_, lltype.OpaqueType):
+ self.addpending(type_, OpaqueTypeNode(self, type_))
+
+ else:
+ assert False, "need to prepare typerepr %s %s" % (type_, type(type_))
+
+ def prepare_type_multi(self, types):
+ for type_ in types:
+ self.prepare_type(type_)
+
+ def prepare_constant(self, type_, value):
+ if isinstance(type_, lltype.Primitive):
+ #log.prepareconstant(value, "(is primitive)")
+ return
+
+ if isinstance(type_, lltype.Ptr):
+
+ type_ = type_.TO
+ value = value._obj
+
+ #log.prepareconstant("preparing ptr", value)
+
+ # we dont need a node for nulls
+ if value is None:
+ return
+
+ # we can share data via pointers
+ if value not in self.obj2node:
+ self.addpending(value, self.create_constant_node(type_, value))
+
+ # always add type (it is safe)
+ self.prepare_type(type_)
+
+ def prepare_arg_value(self, const_or_var):
+ """if const_or_var is not already in a dictionary self.obj2node,
+ the appropriate node gets constructed and gets added to
+ self._pendingsetup and to self.obj2node"""
+ if isinstance(const_or_var, Constant):
+ ct = const_or_var.concretetype
+ if isinstance(ct, lltype.Primitive):
+ #log.prepare(const_or_var, "(is primitive)")
+ return
+
+ assert isinstance(ct, lltype.Ptr), "Preparation of non primitive and non pointer"
+ value = const_or_var.value._obj
+
+ # Only prepare root values at this point
+ if isinstance(ct, lltype.Array) or isinstance(ct, lltype.Struct):
+ p, c = lltype.parentlink(value)
+ if p is None:
+ #log.prepareargvalue("skipping preparing non root", value)
+ return
+
+ if value is not None and value not in self.obj2node:
+ self.addpending(value, self.create_constant_node(ct.TO, value))
+ else:
+ assert isinstance(const_or_var, Variable)
+
+
+ def prepare_arg(self, const_or_var):
+ #log.prepare(const_or_var)
+ self.prepare_type(const_or_var.concretetype)
+ self.prepare_arg_value(const_or_var)
+
+
+ def setup_all(self):
+ while self._pendingsetup:
+ node = self._pendingsetup.pop()
+ #log.settingup(node)
+ node.setup()
+
+ def set_entrynode(self, key):
+ self.entrynode = self.obj2node[key]
+ return self.entrynode
+
+ def getnodes(self):
+ return self.obj2node.itervalues()
+
+ # __________________________________________________________
+ # Representing variables and constants in LLVM source code
+
+ def repr_arg(self, arg):
+ if isinstance(arg, Constant):
+ if isinstance(arg.concretetype, lltype.Primitive):
+ return self.primitive_to_str(arg.concretetype, arg.value)
+ else:
+ assert isinstance(arg.value, lltype._ptr)
+ node = self.obj2node.get(arg.value._obj)
+ if node is None:
+ return 'null'
+ else:
+ return node.get_ref()
+ else:
+ assert isinstance(arg, Variable)
+ return "%" + str(arg)
+
+ def repr_arg_type(self, arg):
+ assert isinstance(arg, (Constant, Variable))
+ ct = arg.concretetype
+ return self.repr_type(ct)
+
+ def repr_type(self, type_):
+ try:
+ return self.obj2node[type_].ref
+ except KeyError:
+ if isinstance(type_, lltype.Primitive):
+ return self.primitives[type_]
+ elif isinstance(type_, lltype.Ptr):
+ return self.repr_type(type_.TO) + '*'
+ else:
+ raise TypeError("cannot represent %r" %(type_,))
+
+ def repr_argwithtype(self, arg):
+ return self.repr_arg(arg), self.repr_arg_type(arg)
+
+ def repr_arg_multi(self, args):
+ return [self.repr_arg(arg) for arg in args]
+
+ def repr_arg_type_multi(self, args):
+ return [self.repr_arg_type(arg) for arg in args]
+
+ def repr_constant(self, value):
+ " returns node and repr as tuple "
+ type_ = lltype.typeOf(value)
+ if isinstance(type_, lltype.Primitive):
+ repr = self.primitive_to_str(type_, value)
+ return None, "%s %s" % (self.repr_type(type_), repr)
+
+ elif isinstance(type_, lltype.Ptr):
+ toptr = self.repr_type(type_)
+ value = value._obj
+
+ # special case, null pointer
+ if value is None:
+ return None, "%s null" % (toptr,)
+
+ node = self.obj2node[value]
+ ref = node.get_pbcref(toptr)
+ return node, "%s %s" % (toptr, ref)
+
+ elif isinstance(type_, lltype.Array) or isinstance(type_, lltype.Struct):
+ node = self.obj2node[value]
+ return node, node.constantvalue()
+
+ assert False, "%s not supported" % (type(value))
+
+ def repr_tmpvar(self):
+ count = self._tmpcount
+ self._tmpcount += 1
+ return "%tmp." + str(count)
+
+ def repr_constructor(self, type_):
+ return self.obj2node[type_].constructor_ref
+
+ def repr_name(self, obj):
+ return self.obj2node[obj].ref
+
+ # __________________________________________________________
+ # Primitive stuff
+
+ def float_to_str(self, value):
+ repr = "%f" % value
+ # llvm requires a . when using e notation
+ if "e" in repr and "." not in repr:
+ repr = repr.replace("e", ".0e")
+ elif repr in ["inf", "nan"]:
+ # Need hex repr
+ import struct
+ packed = struct.pack("d", value)
+ if sys.byteorder == 'little':
+ packed = packed[::-1]
+
+ repr = "0x" + "".join([("%02x" % ord(ii)) for ii in packed])
+ return repr
+
+ def char_to_str(self, value):
+ x = ord(value)
+ if x >= 128:
+ r = "cast (ubyte %s to sbyte)" % x
+ else:
+ r = str(x)
+ return r
+
+ def primitive_to_str(self, type_, value):
+ if type_ is lltype.Bool:
+ repr = str(value).lower() #False --> false
+ elif type_ is lltype.Char:
+ repr = self.char_to_str(value)
+ elif type_ is lltype.UniChar:
+ repr = str(ord(value))
+ elif type_ is lltype.Float:
+ repr = self.float_to_str(value)
+ else:
+ repr = str(value)
+ return repr
+
+ def get_machine_word(self):
+ return self.primitives[lltype.Signed]
+
+ def get_machine_uword(self):
+ return self.primitives[lltype.Unsigned]
+
+ # __________________________________________________________
+ # Other helpers
+
+ def is_function_ptr(self, arg):
+ if isinstance(arg, (Constant, Variable)):
+ arg = arg.concretetype
+ if isinstance(arg, lltype.Ptr):
+ if isinstance(arg.TO, lltype.FuncType):
+ return True
+ return False
+
+ def get_childref(self, parent, child):
+ node = self.obj2node[parent]
+ return node.get_childref(child)
Added: pypy/dist/pypy/translator/js/exception.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/exception.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,248 @@
+from pypy.translator.llvm.codewriter import DEFAULT_CCONV
+
+
+class ExceptionPolicy:
+ RINGBUGGER_SIZE = 8192
+ RINGBUFFER_ENTRY_MAXSIZE = 16
+ RINGBUGGER_OVERSIZE = RINGBUGGER_SIZE + RINGBUFFER_ENTRY_MAXSIZE
+ RINGBUFFER_LLVMCODE = '''
+internal fastcc sbyte* %%malloc_exception(uint %%nbytes) {
+ %%cond = setle uint %%nbytes, %d
+ br bool %%cond, label %%then, label %%else
+
+then:
+ %%tmp.3 = load uint* %%exception_ringbuffer_index
+ %%tmp.4 = getelementptr [%d x sbyte]* %%exception_ringbuffer, int 0, uint %%tmp.3
+ %%tmp.6 = add uint %%tmp.3, %%nbytes
+ %%tmp.7 = and uint %%tmp.6, %d
+ store uint %%tmp.7, uint* %%exception_ringbuffer_index
+ ret sbyte* %%tmp.4
+
+else:
+ %%tmp.8 = call ccc sbyte* %%GC_malloc(uint %%nbytes)
+ ret sbyte* %%tmp.8
+}
+''' % (RINGBUFFER_ENTRY_MAXSIZE, RINGBUGGER_OVERSIZE, RINGBUGGER_SIZE-1)
+
+ def __init__(self):
+ raise Exception, 'ExceptionPolicy should not be used directly'
+
+ def transform(self, translator, graph=None):
+ return
+
+ def _noresult(self, returntype):
+ r = returntype.strip()
+ if r == 'void':
+ return 'void'
+ elif r == 'bool':
+ return 'bool false'
+ elif r in 'float double'.split():
+ return r + ' 0.0'
+ elif r in 'ubyte sbyte ushort short uint int ulong long'.split():
+ return r + ' 0'
+ return r + ' null'
+
+ def _nonoderesult(self, node):
+ decl = node.getdecl()
+ returntype, name = decl.split(' ', 1)
+ noresult = self._noresult(returntype)
+ return noresult
+
+ def new(exceptionpolicy=None): #factory
+ exceptionpolicy = exceptionpolicy or 'fast'
+ if exceptionpolicy == 'cpython':
+ from pypy.translator.llvm.exception import CPythonExceptionPolicy
+ exceptionpolicy = CPythonExceptionPolicy()
+ elif exceptionpolicy == 'fast':
+ from pypy.translator.llvm.exception import FastExceptionPolicy
+ exceptionpolicy = FastExceptionPolicy()
+ elif exceptionpolicy == 'none':
+ from pypy.translator.llvm.exception import NoneExceptionPolicy
+ exceptionpolicy = NoneExceptionPolicy()
+ else:
+ raise Exception, 'unknown exceptionpolicy: ' + str(exceptionpolicy)
+ return exceptionpolicy
+ new = staticmethod(new)
+
+
+class NoneExceptionPolicy(ExceptionPolicy): #XXX untested
+ def __init__(self):
+ pass
+
+
+class CPythonExceptionPolicy(ExceptionPolicy): #uses issubclass() and llvm invoke&unwind
+ def __init__(self):
+ pass
+
+ def llvmcode(self, entrynode):
+ returntype, entrypointname = entrynode.getdecl().split('%', 1)
+ noresult = self._noresult(returntype)
+ cconv = DEFAULT_CCONV
+ return '''
+ccc %(returntype)s%%__entrypoint__%(entrypointname)s {
+ %%result = invoke %(cconv)s %(returntype)s%%%(entrypointname)s to label %%no_exception except label %%exception
+
+no_exception:
+ store %%RPYTHON_EXCEPTION_VTABLE* null, %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ ret %(returntype)s %%result
+
+exception:
+ ret %(noresult)s
+}
+
+ccc int %%__entrypoint__raised_LLVMException() {
+ %%tmp = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ %%result = cast %%RPYTHON_EXCEPTION_VTABLE* %%tmp to int
+ ret int %%result
+}
+
+internal fastcc void %%unwind() {
+ unwind
+}
+''' % locals() + self.RINGBUFFER_LLVMCODE
+
+ def invoke(self, codewriter, targetvar, tail_, cconv, returntype, functionref, args, label, except_label):
+ labels = 'to label %%%s except label %%%s' % (label, except_label)
+ if returntype == 'void':
+ codewriter.indent('%sinvoke %s void %s(%s) %s' % (tail_, cconv, functionref, args, labels))
+ else:
+ codewriter.indent('%s = %sinvoke %s %s %s(%s) %s' % (targetvar, tail_, cconv, returntype, functionref, args, labels))
+
+ def _is_raise_new_exception(self, db, graph, block):
+ from pypy.objspace.flow.model import mkentrymap
+ is_raise_new = False
+ entrylinks = mkentrymap(graph)[block]
+ entrylinks = [x for x in entrylinks if x.prevblock is not None]
+ inputargs = db.repr_arg_multi(block.inputargs)
+ for i, arg in enumerate(inputargs):
+ names = db.repr_arg_multi([link.args[i] for link in entrylinks])
+ for name in names: #These tests-by-name are a bit yikes, but I don't see a better way right now
+ if not name.startswith('%last_exception_') and not name.startswith('%last_exc_value_'):
+ is_raise_new = True
+ return is_raise_new
+
+ def write_exceptblock(self, funcnode, codewriter, block):
+ assert len(block.inputargs) == 2
+
+ db = funcnode.db
+ graph = funcnode.graph
+
+ if self._is_raise_new_exception(db, graph, block):
+ funcnode.write_block_phi_nodes(codewriter, block)
+
+ inputargs = db.repr_arg_multi(block.inputargs)
+ inputargtypes = db.repr_arg_type_multi(block.inputargs)
+
+ codewriter.store(inputargtypes[0], inputargs[0], '%last_exception_type')
+ codewriter.store(inputargtypes[1], inputargs[1], '%last_exception_value')
+ else:
+ codewriter.comment('reraise last exception')
+ #Reraising last_exception.
+ #Which is already stored in the global variables.
+ #So nothing needs to happen here!
+
+ codewriter.indent('unwind')
+
+ def fetch_exceptions(self, codewriter, exc_found_labels, lltype_of_exception_type, lltype_of_exception_value):
+ for label, target, last_exc_type_var, last_exc_value_var in exc_found_labels:
+ codewriter.label(label)
+ if last_exc_type_var:
+ codewriter.load(last_exc_type_var, lltype_of_exception_type, '%last_exception_type')
+ if last_exc_value_var:
+ codewriter.load(last_exc_value_var, lltype_of_exception_value, '%last_exception_value')
+ codewriter.br_uncond(target)
+
+ def reraise(self, funcnode, codewriter):
+ codewriter.comment('reraise when exception is not caught')
+ codewriter.indent('unwind')
+
+ def llc_options(self):
+ return '-enable-correct-eh-support'
+
+
+class FastExceptionPolicy(ExceptionPolicy): #uses issubclass() and last_exception tests after each call
+ def __init__(self):
+ self.invoke_count = 0
+
+ def llvmcode(self, entrynode):
+ returntype, entrypointname = entrynode.getdecl().split('%', 1)
+ noresult = self._noresult(returntype)
+ cconv = DEFAULT_CCONV
+ return '''
+ccc %(returntype)s%%__entrypoint__%(entrypointname)s {
+ store %%RPYTHON_EXCEPTION_VTABLE* null, %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ %%result = call %(cconv)s %(returntype)s%%%(entrypointname)s
+ %%tmp = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ %%exc = seteq %%RPYTHON_EXCEPTION_VTABLE* %%tmp, null
+ br bool %%exc, label %%no_exception, label %%exception
+
+no_exception:
+ ret %(returntype)s %%result
+
+exception:
+ ret %(noresult)s
+}
+
+ccc int %%__entrypoint__raised_LLVMException() {
+ %%tmp = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type
+ %%result = cast %%RPYTHON_EXCEPTION_VTABLE* %%tmp to int
+ ret int %%result
+}
+
+internal fastcc void %%unwind() {
+ ret void
+}
+''' % locals() + self.RINGBUFFER_LLVMCODE
+
+ def transform(self, translator, graph=None):
+ from pypy.translator.llvm.backendopt.exception import create_exception_handling
+ if graph:
+ create_exception_handling(translator, graph)
+ else:
+ for graph in translator.flowgraphs.itervalues():
+ create_exception_handling(translator, graph)
+ #translator.view()
+
+ def invoke(self, codewriter, targetvar, tail_, cconv, returntype, functionref, args, label, except_label):
+ if returntype == 'void':
+ codewriter.indent('%scall %s void %s(%s)' % (tail_, cconv, functionref, args))
+ else:
+ codewriter.indent('%s = %scall %s %s %s(%s)' % (targetvar, tail_, cconv, returntype, functionref, args))
+ tmp = '%%invoke.tmp.%d' % self.invoke_count
+ exc = '%%invoke.exc.%d' % self.invoke_count
+ self.invoke_count += 1
+ codewriter.indent('%(tmp)s = load %%RPYTHON_EXCEPTION_VTABLE** %%last_exception_type' % locals())
+ codewriter.indent('%(exc)s = seteq %%RPYTHON_EXCEPTION_VTABLE* %(tmp)s, null' % locals())
+ codewriter.indent('br bool %(exc)s, label %%%(label)s, label %%%(except_label)s' % locals())
+
+ def write_exceptblock(self, funcnode, codewriter, block):
+ assert len(block.inputargs) == 2
+
+ noresult = self._nonoderesult(funcnode)
+
+ funcnode.write_block_phi_nodes(codewriter, block)
+
+ inputargs = funcnode.db.repr_arg_multi(block.inputargs)
+ inputargtypes = funcnode.db.repr_arg_type_multi(block.inputargs)
+
+ codewriter.store(inputargtypes[0], inputargs[0], '%last_exception_type')
+ codewriter.store(inputargtypes[1], inputargs[1], '%last_exception_value')
+ codewriter.indent('ret ' + noresult)
+
+ def fetch_exceptions(self, codewriter, exc_found_labels, lltype_of_exception_type, lltype_of_exception_value):
+ for label, target, last_exc_type_var, last_exc_value_var in exc_found_labels:
+ codewriter.label(label)
+ if last_exc_type_var:
+ codewriter.load(last_exc_type_var, lltype_of_exception_type, '%last_exception_type')
+ if last_exc_value_var:
+ codewriter.load(last_exc_value_var, lltype_of_exception_value, '%last_exception_value')
+ codewriter.store(lltype_of_exception_type , 'null', '%last_exception_type')
+ codewriter.store(lltype_of_exception_value, 'null', '%last_exception_value')
+ codewriter.br_uncond(target)
+
+ def reraise(self, funcnode, codewriter):
+ noresult = self._nonoderesult(funcnode)
+ codewriter.indent('ret ' + noresult)
+
+ def llc_options(self):
+ return ''
Added: pypy/dist/pypy/translator/js/extfuncnode.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/extfuncnode.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,30 @@
+import py
+from pypy.translator.llvm.node import ConstantLLVMNode
+from pypy.translator.llvm.log import log
+log = log.extfuncnode
+
+class ExternalFuncNode(ConstantLLVMNode):
+ used_external_functions = {}
+
+ def __init__(self, db, value):
+ self.db = db
+ self.value = value
+ name = value._callable.__name__
+ assert name.startswith("ll")
+ name = "LL" + name[2:]
+ self.ref = self.make_ref("%", name)
+ self.used_external_functions[self.ref] = True
+
+ def getdecl(self):
+ T = self.value._TYPE
+ args = [self.db.repr_type(a) for a in T.ARGS]
+ decl = "%s %s(%s)" % (self.db.repr_type(T.RESULT),
+ self.ref,
+ ", ".join(args))
+ return decl
+
+ def writedecl(self, codewriter):
+ codewriter.declare(self.getdecl())
+
+ def writeglobalconstants(self, codewriter):
+ pass
Added: pypy/dist/pypy/translator/js/funcnode.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/funcnode.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,217 @@
+import py
+import sys
+from pypy.objspace.flow.model import Block, Constant, Variable, Link
+from pypy.objspace.flow.model import flatten, mkentrymap, traverse, last_exception
+from pypy.rpython import lltype
+from pypy.translator.llvm.node import LLVMNode, ConstantLLVMNode
+from pypy.translator.llvm.opwriter import OpWriter
+from pypy.translator.llvm.log import log
+from pypy.translator.llvm.backendopt.removeexcmallocs import remove_exception_mallocs
+from pypy.translator.llvm.backendopt.mergemallocs import merge_mallocs
+from pypy.translator.unsimplify import remove_double_links
+log = log.funcnode
+
+class FuncTypeNode(LLVMNode):
+ __slots__ = "db type_ ref".split()
+
+ def __init__(self, db, type_):
+ self.db = db
+ assert isinstance(type_, lltype.FuncType)
+ self.type_ = type_
+ self.ref = self.make_ref('%functiontype', '')
+
+ def __str__(self):
+ return "<FuncTypeNode %r>" % self.ref
+
+ def setup(self):
+ self.db.prepare_type(self.type_.RESULT)
+ self.db.prepare_type_multi(self.type_._trueargs())
+
+ def writedatatypedecl(self, codewriter):
+ returntype = self.db.repr_type(self.type_.RESULT)
+ inputargtypes = [self.db.repr_type(a) for a in self.type_._trueargs()]
+ codewriter.funcdef(self.ref, returntype, inputargtypes)
+
+class FuncNode(ConstantLLVMNode):
+ __slots__ = "db value ref graph block_to_name".split()
+
+ def __init__(self, db, value):
+ self.db = db
+ self.value = value
+ self.ref = self.make_ref('%pypy_', value.graph.name)
+ self.graph = value.graph
+
+ self.db.genllvm.exceptionpolicy.transform(self.db.translator, self.graph)
+ remove_exception_mallocs(self.db.translator, self.graph, self.ref)
+ #merge_mallocs(self.db.translator, self.graph, self.ref)
+
+ remove_double_links(self.db.translator, self.graph)
+
+ def __str__(self):
+ return "<FuncNode %r>" %(self.ref,)
+
+ def setup(self):
+ #log("setup", self)
+ def visit(node):
+ if isinstance(node, Link):
+ map(self.db.prepare_arg, node.args)
+ elif isinstance(node, Block):
+ block = node
+ map(self.db.prepare_arg, block.inputargs)
+ for op in block.operations:
+ map(self.db.prepare_arg, op.args)
+ self.db.prepare_arg(op.result)
+ if block.exitswitch != Constant(last_exception):
+ continue
+ for link in block.exits[1:]:
+ self.db.prepare_constant(lltype.typeOf(link.llexitcase),
+ link.llexitcase)
+
+ assert self.graph, "cannot traverse"
+ traverse(visit, self.graph)
+
+ # ______________________________________________________________________
+ # main entry points from genllvm
+ def writedecl(self, codewriter):
+ codewriter.declare(self.getdecl())
+
+ def writeimpl(self, codewriter):
+ graph = self.graph
+ log.writeimpl(graph.name)
+ codewriter.openfunc(self.getdecl(), self is self.db.entrynode)
+ nextblock = graph.startblock
+ args = graph.startblock.inputargs
+ l = [x for x in flatten(graph) if isinstance(x, Block)]
+ self.block_to_name = {}
+ for i, block in enumerate(l):
+ self.block_to_name[block] = "block%s" % i
+ for block in l:
+ codewriter.label(self.block_to_name[block])
+ for name in 'startblock returnblock exceptblock'.split():
+ if block is getattr(graph, name):
+ getattr(self, 'write_' + name)(codewriter, block)
+ break
+ else:
+ self.write_block(codewriter, block)
+ codewriter.closefunc()
+
+ def writecomments(self, codewriter):
+ """ write operations strings for debugging purposes. """
+ blocks = [x for x in flatten(self.graph) if isinstance(x, Block)]
+ for block in blocks:
+ for op in block.operations:
+ strop = str(op) + "\n\x00"
+ l = len(strop)
+ if strop.find("direct_call") == -1:
+ continue
+ tempname = self.db.add_op2comment(l, op)
+ printables = dict([(ord(i), None) for i in
+ ("0123456789abcdefghijklmnopqrstuvwxyz" +
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "!#$%&()*+,-./:;<=>?@[\\]^_`{|}~ '")])
+ s = []
+ for c in strop:
+ if ord(c) in printables:
+ s.append(c)
+ else:
+ s.append("\\%02x" % ord(c))
+ r = 'c"%s"' % "".join(s)
+ typeandata = '[%s x sbyte] %s' % (l, r)
+ codewriter.globalinstance(tempname, typeandata)
+
+ def writeglobalconstants(self, codewriter):
+ pass
+
+ # ______________________________________________________________________
+ # writing helpers for entry points
+
+ def getdecl(self):
+ startblock = self.graph.startblock
+ returnblock = self.graph.returnblock
+ startblock_inputargs = [a for a in startblock.inputargs
+ if a.concretetype is not lltype.Void]
+
+ inputargs = self.db.repr_arg_multi(startblock_inputargs)
+ inputargtypes = self.db.repr_arg_type_multi(startblock_inputargs)
+ returntype = self.db.repr_arg_type(self.graph.returnblock.inputargs[0])
+ result = "%s %s" % (returntype, self.ref)
+ args = ["%s %s" % item for item in zip(inputargtypes, inputargs)]
+ result += "(%s)" % ", ".join(args)
+ return result
+
+ def write_block(self, codewriter, block):
+ self.write_block_phi_nodes(codewriter, block)
+ self.write_block_operations(codewriter, block)
+ self.write_block_branches(codewriter, block)
+
+ def get_phi_data(self, block):
+ data = []
+ entrylinks = mkentrymap(self.graph)[block]
+ entrylinks = [x for x in entrylinks if x.prevblock is not None]
+ inputargs = self.db.repr_arg_multi(block.inputargs)
+ inputargtypes = self.db.repr_arg_type_multi(block.inputargs)
+ for i, (arg, type_) in enumerate(zip(inputargs, inputargtypes)):
+ names = self.db.repr_arg_multi([link.args[i] for link in entrylinks])
+ blocknames = [self.block_to_name[link.prevblock]
+ for link in entrylinks]
+ for i, link in enumerate(entrylinks): #XXX refactor into a transformation
+ if link.prevblock.exitswitch == Constant(last_exception) and \
+ link.prevblock.exits[0].target != block:
+ blocknames[i] += '_exception_found_branchto_' + self.block_to_name[block]
+ data.append( (arg, type_, names, blocknames) )
+ return data
+
+ def write_block_phi_nodes(self, codewriter, block):
+ for arg, type_, names, blocknames in self.get_phi_data(block):
+ if type_ != "void":
+ codewriter.phi(arg, type_, names, blocknames)
+
+ def write_block_branches(self, codewriter, block):
+ #assert len(block.exits) <= 2 #more exits are possible (esp. in combination with exceptions)
+ if block.exitswitch == Constant(last_exception):
+ #codewriter.comment('FuncNode(ConstantLLVMNode) *last_exception* write_block_branches @%s@' % str(block.exits))
+ return
+ if len(block.exits) == 1:
+ codewriter.br_uncond(self.block_to_name[block.exits[0].target])
+ elif len(block.exits) == 2:
+ cond = self.db.repr_arg(block.exitswitch)
+ codewriter.br(cond, self.block_to_name[block.exits[0].target],
+ self.block_to_name[block.exits[1].target])
+
+ def write_block_operations(self, codewriter, block):
+ opwriter = OpWriter(self.db, codewriter, self, block)
+ if block.exitswitch == Constant(last_exception):
+ last_op_index = len(block.operations) - 1
+ else:
+ last_op_index = None
+ for op_index, op in enumerate(block.operations):
+ if False: # print out debug string
+ codewriter.newline()
+ codewriter.comment("** %s **" % str(op))
+ info = self.db.get_op2comment(op)
+ if info is not None:
+ lenofopstr, opstrname = info
+ codewriter.debugcomment(self.db.repr_tmpvar(),
+ lenofopstr,
+ opstrname)
+ if op_index == last_op_index:
+ #could raise an exception and should therefor have a function
+ #implementation that can be invoked by the llvm-code.
+ invoke_prefix = 'invoke:'
+ assert not op.opname.startswith(invoke_prefix)
+ op.opname = invoke_prefix + op.opname
+ opwriter.write_operation(op)
+
+ def write_startblock(self, codewriter, block):
+ self.write_block_operations(codewriter, block)
+ self.write_block_branches(codewriter, block)
+
+ def write_returnblock(self, codewriter, block):
+ assert len(block.inputargs) == 1
+ self.write_block_phi_nodes(codewriter, block)
+ inputargtype = self.db.repr_arg_type(block.inputargs[0])
+ inputarg = self.db.repr_arg(block.inputargs[0])
+ codewriter.ret(inputargtype, inputarg)
+
+ def write_exceptblock(self, codewriter, block):
+ self.db.genllvm.exceptionpolicy.write_exceptblock(self, codewriter, block)
Added: pypy/dist/pypy/translator/js/gc.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/gc.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,95 @@
+import py
+from pypy.tool.ansi_print import ansi_log
+log = py.log.Producer("llvm")
+log.setconsumer("llvm", ansi_log)
+
+
+class GcPolicy:
+ def __init__(self):
+ raise Exception, 'GcPolicy should not be used directly'
+
+ def gc_libraries(self):
+ return []
+
+ def declarations(self):
+ return ''
+
+ def malloc(self, targetvar, type_, size, is_atomic, word, uword):
+ s = str(size)
+ return '%(targetvar)s = malloc %(type_)s, uint %(s)s' % locals()
+
+ def pyrex_code(self):
+ return ''
+
+ def new(gcpolicy=None): #factory
+ gcpolicy = gcpolicy or 'boehm'
+
+ from os.path import exists
+ boehm_on_path = exists('/usr/lib/libgc.so') or exists('/usr/lib/libgc.a')
+ if gcpolicy == 'boehm' and not boehm_on_path:
+ log.gc.WARNING('warning: Boehm GC libary not found in /usr/lib, falling back on no gc')
+ gcpolicy = 'none'
+
+ if gcpolicy == 'boehm':
+ from pypy.translator.llvm.gc import BoehmGcPolicy
+ gcpolicy = BoehmGcPolicy()
+ elif gcpolicy == 'ref':
+ from pypy.translator.llvm.gc import RefcountingGcPolicy
+ gcpolicy = RefcountingGcPolicy()
+ elif gcpolicy == 'none':
+ from pypy.translator.llvm.gc import NoneGcPolicy
+ gcpolicy = NoneGcPolicy()
+ else:
+ raise Exception, 'unknown gcpolicy: ' + str(gcpolicy)
+ return gcpolicy
+ new = staticmethod(new)
+
+
+class NoneGcPolicy(GcPolicy):
+ def __init__(self):
+ pass
+
+
+class BoehmGcPolicy(GcPolicy):
+ def __init__(self):
+ self.n_malloced = 0
+
+ def gc_libraries(self):
+ return ['gc'] # xxx on windows?
+
+ def declarations(self):
+ return '''
+declare ccc sbyte* %GC_malloc(uint)
+declare ccc sbyte* %GC_malloc_atomic(uint)
+%GC_all_interior_pointers = external global int
+'''
+
+ def malloc(self, targetvar, type_, size, is_atomic, word, uword):
+ s = str(size)
+ self.n_malloced += 1
+ cnt = '.%d' % self.n_malloced
+ atomic = is_atomic and '_atomic' or ''
+ t = '''
+%%malloc.Size%(cnt)s = getelementptr %(type_)s* null, %(uword)s %(s)s
+%%malloc.SizeU%(cnt)s = cast %(type_)s* %%malloc.Size%(cnt)s to %(uword)s
+%%malloc.Ptr%(cnt)s = call ccc sbyte* %%GC_malloc%(atomic)s(%(uword)s %%malloc.SizeU%(cnt)s)
+%(targetvar)s = cast sbyte* %%malloc.Ptr%(cnt)s to %(type_)s*
+''' % locals()
+ if is_atomic:
+ t += '''
+call ccc void %%llvm.memset(sbyte* %%malloc.Ptr%(cnt)s, ubyte 0, uint %%malloc.SizeU%(cnt)s, uint 0)
+''' % locals()
+ return t
+
+ def pyrex_code(self):
+ return '''
+cdef extern int GC_get_heap_size()
+
+def GC_get_heap_size_wrapper():
+ return GC_get_heap_size()
+'''
+
+
+class RefcountingGcPolicy(GcPolicy):
+ def __init__(self):
+ raise NotImplementedError, 'RefcountingGcPolicy'
Added: pypy/dist/pypy/translator/js/js.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/js.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,152 @@
+'''
+reference material:
+ http://webreference.com/javascript/reference/core_ref/
+ http://webreference.com/programming/javascript/
+ http://mochikit.com/
+
+'''
+
+#import os
+#import time
+#import types
+#import urllib
+
+import py
+
+#from pypy.translator.llvm import build_llvm_module
+from pypy.translator.llvm.database import Database
+#from pypy.translator.llvm.pyxwrapper import write_pyx_wrapper
+from pypy.rpython.rmodel import inputconst, getfunctionptr
+from pypy.rpython import lltype
+from pypy.tool.udir import udir
+from pypy.translator.llvm.codewriter import CodeWriter
+#from pypy.translator.llvm.codewriter import , DEFAULT_TAIL, DEFAULT_CCONV
+#from pypy.translator.llvm import extfuncnode
+#from pypy.translator.llvm.module.extfunction import extdeclarations, extfunctions, dependencies
+#from pypy.translator.llvm.node import JSNode
+#from pypy.translator.llvm.structnode import StructNode
+#from pypy.translator.llvm.externs2ll import post_setup_externs, generate_llfile
+from pypy.translator.llvm.gc import GcPolicy
+from pypy.translator.llvm.exception import ExceptionPolicy
+#from pypy.translator.translator import Translator
+
+from pypy.translator.js.log import log
+
+function_count = {}
+#llexterns_header = llexterns_functions = None
+
+
+class JS(object): # JS = Javascript
+
+ def __init__(self, translator, func=None, gcpolicy=None, exceptionpolicy=None, debug=False):
+ self.db = Database(self, translator)
+ self.translator = translator
+ self.gcpolicy = GcPolicy.new(gcpolicy)
+ self.exceptionpolicy = ExceptionPolicy.new(exceptionpolicy)
+ #extfuncnode.ExternalFuncNode.used_external_functions = {}
+ self.debug = debug # for debug we create comments of every operation that may be executed
+ if debug:
+ translator.checkgraphs()
+
+ if func is None:
+ func = self.translator.entrypoint
+ self.entrypoint = func
+
+ ptr = getfunctionptr(self.translator, func)
+ c = inputconst(lltype.typeOf(ptr), ptr)
+ entry_point = c.value._obj
+ self.db.prepare_arg_value(c)
+
+ # set up all nodes
+ self.db.setup_all()
+ self.entrynode = self.db.set_entrynode(entry_point)
+ entryfunc_name = self.entrynode.getdecl().split('%', 1)[1].split('(')[0]
+
+ ## post set up externs
+ #extern_decls = post_setup_externs(self.db)
+ #self.translator.rtyper.specialize_more_blocks()
+ #self.db.setup_all()
+ #using_external_functions = extfuncnode.ExternalFuncNode.used_external_functions.keys() != []
+ #
+ #support_functions = "%raisePyExc_IOError %raisePyExc_ValueError "\
+ # "%raisePyExc_OverflowError %raisePyExc_ZeroDivisionError "\
+ # "%prepare_ZeroDivisionError %prepare_OverflowError %prepare_ValueError "\
+ # "%RPyString_FromString %RPyString_AsString %RPyString_Size".split()
+ #
+ #global llexterns_header, llexterns_functions
+ #if llexterns_header is None and using_external_functions:
+ # llexterns_header, llexterns_functions = generate_llfile(self.db, extern_decls, support_functions, self.debug)
+
+ # prevent running the same function twice in a test
+ if func.func_name in function_count:
+ postfix = '_%d' % function_count[func.func_name]
+ function_count[func.func_name] += 1
+ else:
+ postfix = ''
+ function_count[func.func_name] = 1
+ filename = udir.join(func.func_name + postfix).new(ext='.js')
+ f = open(str(filename),'w')
+ codewriter = CodeWriter(f, self)
+ comment = codewriter.comment
+ nl = codewriter.newline
+
+ #if using_external_functions:
+ # nl(); comment("External Function Declarations") ; nl()
+ # codewriter.append(llexterns_header)
+
+ nl(); comment("Type Declarations"); nl()
+ #for c_name, obj in extern_decls:
+ # if isinstance(obj, lltype.LowLevelType):
+ # if isinstance(obj, lltype.Ptr):
+ # obj = obj.TO
+ # l = "%%%s = type %s" % (c_name, self.db.repr_type(obj))
+ # codewriter.append(l)
+
+ for typ_decl in self.db.getnodes():
+ typ_decl.writedatatypedecl(codewriter)
+
+ nl(); comment("Global Data") ; nl()
+ for typ_decl in self.db.getnodes():
+ typ_decl.writeglobalconstants(codewriter)
+
+ nl(); comment("Function Prototypes") ; nl()
+ #codewriter.append(extdeclarations)
+ #codewriter.append(self.gcpolicy.declarations())
+
+ for typ_decl in self.db.getnodes():
+ typ_decl.writedecl(codewriter)
+
+ nl(); comment("Function Implementation")
+ codewriter.startimpl()
+
+ for typ_decl in self.db.getnodes():
+ typ_decl.writeimpl(codewriter)
+
+ #codewriter.append(self.exceptionpolicy.llvmcode(self.entrynode))
+ #
+ ## XXX we need to create our own main() that calls the actual entry_point function
+ #if entryfunc_name == 'pypy_entry_point': #XXX just to get on with translate_pypy
+ # extfuncnode.ExternalFuncNode.used_external_functions['%main'] = True
+ #
+ #elif entryfunc_name == 'pypy_main_noargs': #XXX just to get on with bpnn & richards
+ # extfuncnode.ExternalFuncNode.used_external_functions['%main_noargs'] = True
+ #
+ #for f in support_functions:
+ # extfuncnode.ExternalFuncNode.used_external_functions[f] = True
+ #
+ #depdone = {}
+ #for funcname,value in extfuncnode.ExternalFuncNode.used_external_functions.iteritems():
+ # deps = dependencies(funcname,[])
+ # deps.reverse()
+ # for dep in deps:
+ # if dep not in depdone:
+ # if dep in extfunctions: #else external function that is shared with genc
+ # codewriter.append(extfunctions[dep][1])
+ # depdone[dep] = True
+ #
+ #if using_external_functions:
+ # nl(); comment("External Function Implementation") ; nl()
+ # codewriter.append(llexterns_functions)
+
+ comment("End of file") ; nl()
+ self.filename = filename
Added: pypy/dist/pypy/translator/js/log.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/log.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,4 @@
+import py
+from pypy.tool.ansi_print import ansi_log
+log = py.log.Producer("js")
+log.setconsumer("js", ansi_log)
Added: pypy/dist/pypy/translator/js/node.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/node.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,67 @@
+from pypy.rpython import lltype
+
+class LLVMNode(object):
+ __slots__ = "".split()
+
+ nodename_count = {}
+
+ def make_name(self, name):
+ " helper for creating names"
+ if " " in name or "<" in name:
+ name = '"%s"' % name
+
+ if name in self.nodename_count:
+ postfix = '.%d' % self.nodename_count[name]
+ self.nodename_count[name] += 1
+ else:
+ postfix = ''
+ self.nodename_count[name] = 1
+ return name + postfix
+
+ def make_ref(self, prefix, name):
+ return self.make_name(prefix + name)
+
+ def setup(self):
+ pass
+
+ # __________________ before "implementation" ____________________
+ def writedatatypedecl(self, codewriter):
+ """ write out declare names of data types
+ (structs/arrays/function pointers)
+ """
+
+ def writeglobalconstants(self, codewriter):
+ """ write out global values. """
+
+ def writedecl(self, codewriter):
+ """ write function forward declarations. """
+
+ def writecomments(self, codewriter):
+ """ write operations strings for debugging purposes. """
+
+ # __________________ after "implementation" ____________________
+ def writeimpl(self, codewriter):
+ """ write function implementations. """
+
+class ConstantLLVMNode(LLVMNode):
+ __slots__ = "".split()
+
+ def get_ref(self):
+ """ Returns a reference as used for operations in blocks. """
+ return self.ref
+
+ def get_pbcref(self, toptr):
+ """ Returns a reference as a pointer used per pbc. """
+ return self.ref
+
+ def constantvalue(self):
+ """ Returns the constant representation for this node. """
+ raise AttributeError("Must be implemented in subclass")
+
+ # ______________________________________________________________________
+ # entry points from genllvm
+
+ def writeglobalconstants(self, codewriter):
+ p, c = lltype.parentlink(self.value)
+ if p is None:
+ codewriter.globalinstance(self.ref, self.constantvalue())
Added: pypy/dist/pypy/translator/js/opaquenode.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/opaquenode.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,33 @@
+from pypy.translator.llvm.node import LLVMNode, ConstantLLVMNode
+from pypy.rpython import lltype
+
+class OpaqueTypeNode(LLVMNode):
+
+ def __init__(self, db, opaquetype):
+ assert isinstance(opaquetype, lltype.OpaqueType)
+ self.db = db
+ self.opaquetype = opaquetype
+ self.ref = "%%opaquetype.%s" % (opaquetype.tag)
+
+ def __str__(self):
+ return "<OpaqueNode %r>" %(self.ref,)
+
+ # ______________________________________________________________________
+ # main entry points from genllvm
+
+ def writedatatypedecl(self, codewriter):
+ # XXX Dummy - not sure what what we want
+ codewriter.funcdef(self.ref, 'sbyte*', ['sbyte *'])
+
+
+class OpaqueNode(ConstantLLVMNode):
+ def __init__(self, db, value):
+ self.db = db
+ self.value = value
+ self.ref = "null"
+ # ______________________________________________________________________
+ # main entry points from genllvm
+
+ def writeglobalconstants(self, codewriter):
+ # XXX Dummy - not sure what what we want
+ pass
Added: pypy/dist/pypy/translator/js/opwriter.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/opwriter.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,514 @@
+import py
+from pypy.objspace.flow.model import Constant
+from pypy.rpython import lltype
+from pypy.translator.llvm.module.extfunction import extfunctions
+from pypy.translator.llvm.extfuncnode import ExternalFuncNode
+from pypy.translator.llvm.log import log
+log = log.opwriter
+
+class OpWriter(object):
+ binary_operations = {'int_mul': 'mul',
+ 'int_add': 'add',
+ 'int_sub': 'sub',
+ 'int_floordiv': 'div',
+ 'int_mod': 'rem',
+ 'int_and': 'and',
+ 'int_or': 'or',
+ 'int_xor': 'xor',
+ 'int_lt': 'setlt',
+ 'int_le': 'setle',
+ 'int_eq': 'seteq',
+ 'int_ne': 'setne',
+ 'int_ge': 'setge',
+ 'int_gt': 'setgt',
+
+ 'uint_mul': 'mul',
+ 'uint_add': 'add',
+ 'uint_sub': 'sub',
+ 'uint_floordiv': 'div',
+ 'uint_mod': 'rem',
+ 'uint_and': 'and',
+ 'uint_or': 'or',
+ 'uint_xor': 'xor',
+ 'uint_lt': 'setlt',
+ 'uint_le': 'setle',
+ 'uint_eq': 'seteq',
+ 'uint_ne': 'setne',
+ 'uint_ge': 'setge',
+ 'uint_gt': 'setgt',
+
+ 'unichar_lt': 'setlt',
+ 'unichar_le': 'setle',
+ 'unichar_eq': 'seteq',
+ 'unichar_ne': 'setne',
+ 'unichar_ge': 'setge',
+ 'unichar_gt': 'setgt',
+
+ 'float_mul': 'mul',
+ 'float_add': 'add',
+ 'float_sub': 'sub',
+ 'float_truediv': 'div',
+ 'float_mod': 'rem',
+ 'float_lt': 'setlt',
+ 'float_le': 'setle',
+ 'float_eq': 'seteq',
+ 'float_ne': 'setne',
+ 'float_ge': 'setge',
+ 'float_gt': 'setgt',
+
+ 'ptr_eq': 'seteq',
+ 'ptr_ne': 'setne',
+ }
+
+ shift_operations = {'int_lshift': 'shl',
+ 'int_rshift': 'shr',
+
+ 'uint_lshift': 'shl',
+ 'uint_rshift': 'shr',
+ }
+
+
+ char_operations = {'char_lt': 'setlt',
+ 'char_le': 'setle',
+ 'char_eq': 'seteq',
+ 'char_ne': 'setne',
+ 'char_ge': 'setge',
+ 'char_gt': 'setgt'}
+
+ def __init__(self, db, codewriter, node, block):
+ self.db = db
+ self.codewriter = codewriter
+ self.node = node
+ self.block = block
+
+ def write_operation(self, op):
+ invoke = op.opname.startswith('invoke:')
+ if invoke:
+ self.invoke(op)
+ else:
+ if op.opname in self.binary_operations:
+ self.binaryop(op)
+ elif op.opname in self.shift_operations:
+ self.shiftop(op)
+ elif op.opname in self.char_operations:
+ self.char_binaryop(op)
+ elif op.opname.startswith('cast_'):
+ if op.opname == 'cast_char_to_int':
+ self.cast_char_to_int(op)
+ else:
+ self.cast_primitive(op)
+ else:
+ meth = getattr(self, op.opname, None)
+ if not meth:
+ raise Exception, "operation %s not found" % op.opname
+ return
+ meth(op)
+
+ def _generic_pow(self, op, onestr):
+ mult_type = self.db.repr_arg_type(op.args[0])
+ mult_val = self.db.repr_arg(op.args[0])
+ last_val = mult_val
+ try:
+ value = "NO VALUE"
+ value = op.args[1].value
+ operand = int(value)
+ except Exception, exc:
+ msg = 'XXX: Error: _generic_pow: Variable '\
+ '%s - failed to convert to int %s' % (value, str(exc))
+ self.codewriter.comment(msg)
+ return
+ if operand < 1:
+ res_val = onestr
+ else:
+ res_val = mult_val
+ for ii in range(operand - 1):
+ res_val = self.db.repr_tmpvar()
+ self.codewriter.binaryop("mul",
+ res_val,
+ mult_type,
+ last_val,
+ mult_val)
+ last_val = res_val
+ targetvar = self.db.repr_arg(op.result)
+ self.codewriter.cast(targetvar, mult_type, res_val, mult_type)
+
+ def int_abs(self, op):
+ functionref = '%' + op.opname
+ ExternalFuncNode.used_external_functions[functionref] = True
+ self.codewriter.call(self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.result),
+ functionref,
+ [self.db.repr_arg(op.args[0])],
+ [self.db.repr_arg_type(op.args[0])])
+ float_abs = int_abs
+
+ def int_pow(self, op):
+ self._generic_pow(op, "1")
+ uint_pow = int_pow
+
+ def float_pow(self, op):
+ self._generic_pow(op, "1.0")
+
+ def _generic_neg(self, op, zerostr):
+ self.codewriter.binaryop("sub",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ zerostr,
+ self.db.repr_arg(op.args[0]),
+ )
+ def int_neg(self, op):
+ self._generic_neg(op, "0")
+
+ #this is really generated, don't know why
+ # XXX rxe: Surely that cant be right?
+ uint_neg = int_neg
+
+ def float_neg(self, op):
+ self._generic_neg(op, "0.0")
+
+ def bool_not(self, op):
+ self.codewriter.binaryop("xor",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ "true")
+
+ def int_invert(self, op):
+ self.codewriter.binaryop("xor",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ -1)
+
+ def uint_invert(self, op):
+ self.codewriter.binaryop("xor",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ str((1L<<32) - 1))
+
+ def binaryop(self, op):
+ name = self.binary_operations[op.opname]
+ assert len(op.args) == 2
+ self.codewriter.binaryop(name,
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ self.db.repr_arg(op.args[1]))
+
+ def char_binaryop(self, op):
+ name = self.char_operations[op.opname]
+ assert len(op.args) == 2
+ res = self.db.repr_arg(op.result)
+ c1 = self.db.repr_tmpvar()
+ c2 = self.db.repr_tmpvar()
+ self.codewriter.cast(c1, "sbyte", self.db.repr_arg(op.args[0]), "ubyte")
+ self.codewriter.cast(c2, "sbyte", self.db.repr_arg(op.args[1]), "ubyte")
+ self.codewriter.binaryop(name, res, "ubyte", c1, c2)
+
+
+ def shiftop(self, op):
+ name = self.shift_operations[op.opname]
+ assert len(op.args) == 2
+ if isinstance(op.args[1], Constant):
+ tmpvar = self.db.repr_arg(op.args[1])
+ else:
+ tmpvar = self.db.repr_tmpvar()
+ self.codewriter.cast(tmpvar, self.db.repr_arg_type(op.args[1]), self.db.repr_arg(op.args[1]), 'ubyte')
+ self.codewriter.shiftop(name,
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ tmpvar)
+
+ def cast_char_to_int(self, op):
+ " works for all casts "
+ assert len(op.args) == 1
+ targetvar = self.db.repr_arg(op.result)
+ targettype = self.db.repr_arg_type(op.result)
+ fromvar = self.db.repr_arg(op.args[0])
+ fromtype = self.db.repr_arg_type(op.args[0])
+ intermediate = self.db.repr_tmpvar()
+ self.codewriter.cast(intermediate, fromtype, fromvar, "ubyte")
+ self.codewriter.cast(targetvar, "ubyte", intermediate, targettype)
+
+ def cast_primitive(self, op):
+ " works for all casts "
+ assert len(op.args) == 1
+ targetvar = self.db.repr_arg(op.result)
+ targettype = self.db.repr_arg_type(op.result)
+ fromvar = self.db.repr_arg(op.args[0])
+ fromtype = self.db.repr_arg_type(op.args[0])
+ self.codewriter.cast(targetvar, fromtype, fromvar, targettype)
+ same_as = cast_primitive
+
+ def int_is_true(self, op):
+ self.codewriter.binaryop("setne",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ "0")
+ uint_is_true = int_is_true
+
+ def float_is_true(self, op):
+ self.codewriter.binaryop("setne",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ "0.0")
+
+ def ptr_nonzero(self, op):
+ self.codewriter.binaryop("setne",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ "null")
+
+ def ptr_iszero(self, op):
+ self.codewriter.binaryop("seteq",
+ self.db.repr_arg(op.result),
+ self.db.repr_arg_type(op.args[0]),
+ self.db.repr_arg(op.args[0]),
+ "null")
+
+ def direct_call(self, op):
+ op_args = [arg for arg in op.args
+ if arg.concretetype is not lltype.Void]
+ assert len(op_args) >= 1
+ targetvar = self.db.repr_arg(op.result)
+ returntype = self.db.repr_arg_type(op.result)
+ functionref = self.db.repr_arg(op_args[0])
+ argrefs = self.db.repr_arg_multi(op_args[1:])
+ argtypes = self.db.repr_arg_type_multi(op_args[1:])
+ if self.db.is_function_ptr(op.result):
+ returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
+ self.codewriter.call(targetvar,returntype,functionref,argrefs,argtypes)
+
+ def last_exception_type_ptr(self, op):
+ e = self.db.translator.rtyper.getexceptiondata()
+ lltype_of_exception_type = ('%structtype.' + e.lltype_of_exception_type.TO.__name__ + '*')
+ self.codewriter.load('%'+str(op.result), lltype_of_exception_type, '%last_exception_type')
+
+ def invoke(self, op):
+ op_args = [arg for arg in op.args
+ if arg.concretetype is not lltype.Void]
+
+ if op.opname == 'invoke:direct_call':
+ functionref = self.db.repr_arg(op_args[0])
+ else: #operation
+ opname = op.opname.split(':',1)[1]
+ op_args = ['%' + opname] + op_args
+ functionref = op_args[0]
+ if functionref in extfunctions:
+ ExternalFuncNode.used_external_functions[functionref] = True
+ else:
+ msg = "exception raising operation %s not found" %(op.opname,)
+ self.codewriter.comment('XXX: Error: ' + msg)
+ # XXX commented out for testing
+ #assert functionref in extfunctions, msg
+
+ assert len(op_args) >= 1
+ # at least one label and one exception label
+ assert len(self.block.exits) >= 2
+
+ link = self.block.exits[0]
+ assert link.exitcase is None
+
+ targetvar = self.db.repr_arg(op.result)
+ returntype = self.db.repr_arg_type(op.result)
+ argrefs = self.db.repr_arg_multi(op_args[1:])
+ argtypes = self.db.repr_arg_type_multi(op_args[1:])
+
+ none_label = self.node.block_to_name[link.target]
+ block_label = self.node.block_to_name[self.block]
+ exc_label = block_label + '_exception_handling'
+
+ if self.db.is_function_ptr(op.result): #use longhand form
+ returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
+ self.codewriter.call(targetvar, returntype, functionref, argrefs,
+ argtypes, none_label, exc_label)
+
+ e = self.db.translator.rtyper.getexceptiondata()
+ ll_exception_match = '%pypy_' + e.ll_exception_match.__name__
+ lltype_of_exception_type = ('%structtype.' +
+ e.lltype_of_exception_type.TO.__name__
+ + '*')
+ lltype_of_exception_value = ('%structtype.' +
+ e.lltype_of_exception_value.TO.__name__
+ + '*')
+
+ self.codewriter.label(exc_label)
+
+ exc_found_labels, last_exception_type = [], None
+ catch_all = False
+ for link in self.block.exits[1:]:
+ assert issubclass(link.exitcase, Exception)
+
+ etype = self.db.obj2node[link.llexitcase._obj]
+ current_exception_type = etype.get_ref()
+ target = self.node.block_to_name[link.target]
+ exc_found_label = block_label + '_exception_found_branchto_' + target
+ last_exc_type_var, last_exc_value_var = None, None
+
+ for p in self.node.get_phi_data(link.target):
+ arg, type_, names, blocknames = p
+ for name, blockname in zip(names, blocknames):
+ if blockname != exc_found_label:
+ continue
+ if name.startswith('%last_exception_'):
+ last_exc_type_var = name
+ if name.startswith('%last_exc_value_'):
+ last_exc_value_var = name
+
+ t = (exc_found_label,target,last_exc_type_var,last_exc_value_var)
+ exc_found_labels.append(t)
+
+ not_this_exception_label = block_label + '_not_exception_' + etype.ref[1:]
+
+ if current_exception_type.find('getelementptr') == -1: #catch all (except:)
+ catch_all = True
+ self.codewriter.br_uncond(exc_found_label)
+ else: #catch specific exception (class) type
+ if not last_exception_type: #load pointer only once
+ last_exception_type = self.db.repr_tmpvar()
+ self.codewriter.load(last_exception_type, lltype_of_exception_type, '%last_exception_type')
+ self.codewriter.newline()
+ ll_issubclass_cond = self.db.repr_tmpvar()
+ self.codewriter.call(ll_issubclass_cond,
+ 'bool',
+ ll_exception_match,
+ [last_exception_type, current_exception_type],
+ [lltype_of_exception_type, lltype_of_exception_type])
+ self.codewriter.br(ll_issubclass_cond, not_this_exception_label, exc_found_label)
+ self.codewriter.label(not_this_exception_label)
+
+ ep = self.codewriter.genllvm.exceptionpolicy
+ if not catch_all:
+ ep.reraise(self.node, self.codewriter)
+ ep.fetch_exceptions(self.codewriter, exc_found_labels, lltype_of_exception_type, lltype_of_exception_value)
+
+ def malloc_exception(self, op):
+ arg_type = op.args[0].value
+ targetvar = self.db.repr_arg(op.result)
+ type_ = self.db.repr_type(arg_type)
+ tmpvar1 = self.db.repr_tmpvar()
+ tmpvar2 = self.db.repr_tmpvar()
+ tmpvar3 = self.db.repr_tmpvar()
+ self.codewriter.indent('%(tmpvar1)s = getelementptr %(type_)s* null, int 1' % locals())
+ self.codewriter.cast(tmpvar2, type_+'*', tmpvar1, 'uint')
+ self.codewriter.call(tmpvar3, 'sbyte*', '%malloc_exception', [tmpvar2], ['uint'])
+ self.codewriter.cast(targetvar, 'sbyte*', tmpvar3, type_+'*')
+
+ def malloc(self, op):
+ arg_type = op.args[0].value
+ targetvar = self.db.repr_arg(op.result)
+ type_ = self.db.repr_type(arg_type)
+ self.codewriter.malloc(targetvar, type_, atomic=arg_type._is_atomic())
+
+ def malloc_varsize(self, op):
+ arg_type = op.args[0].value
+ if isinstance(arg_type, lltype.Array) and arg_type.OF is lltype.Void:
+ # This is a backend decision to NOT represent a void array with
+ # anything and save space - therefore not varsized anymore
+ self.malloc(op)
+ return
+
+ targetvar = self.db.repr_arg(op.result)
+ type_ = self.db.repr_type(arg_type) + "*"
+ type_cons = self.db.repr_constructor(arg_type)
+ argrefs = self.db.repr_arg_multi(op.args[1:])
+ argtypes = self.db.repr_arg_type_multi(op.args[1:])
+ self.codewriter.call(targetvar, type_, type_cons, argrefs, argtypes)
+
+ def _getindexhelper(self, name, struct):
+ assert name in list(struct._names)
+
+ fieldnames = struct._names_without_voids()
+ try:
+ index = fieldnames.index(name)
+ except ValueError:
+ index = -1
+ return index
+
+ def getfield(self, op):
+ tmpvar = self.db.repr_tmpvar()
+ struct, structtype = self.db.repr_argwithtype(op.args[0])
+ index = self._getindexhelper(op.args[1].value, op.args[0].concretetype.TO)
+ targetvar = self.db.repr_arg(op.result)
+ targettype = self.db.repr_arg_type(op.result)
+ if targettype != "void":
+ assert index != -1
+ self.codewriter.getelementptr(tmpvar, structtype, struct,
+ ("uint", index))
+ self.codewriter.load(targetvar, targettype, tmpvar)
+ else:
+ self.codewriter.comment("***Skipping operation getfield()***")
+
+ def getsubstruct(self, op):
+ struct, structtype = self.db.repr_argwithtype(op.args[0])
+ index = self._getindexhelper(op.args[1].value, op.args[0].concretetype.TO)
+ targetvar = self.db.repr_arg(op.result)
+ targettype = self.db.repr_arg_type(op.result)
+ assert targettype != "void"
+ self.codewriter.getelementptr(targetvar, structtype,
+ struct, ("uint", index))
+
+ def setfield(self, op):
+ tmpvar = self.db.repr_tmpvar()
+ struct, structtype = self.db.repr_argwithtype(op.args[0])
+ index = self._getindexhelper(op.args[1].value, op.args[0].concretetype.TO)
+ valuevar, valuetype = self.db.repr_argwithtype(op.args[2])
+ if valuetype != "void":
+ #Structure types require uint constants!
+ #see: http://llvm.cs.uiuc.edu/docs/LangRef.html#i_getelementptr
+ self.codewriter.getelementptr(tmpvar, structtype, struct,
+ ("uint", index))
+ self.codewriter.store(valuetype, valuevar, tmpvar)
+ else:
+ self.codewriter.comment("***Skipping operation setfield()***")
+
+ def getarrayitem(self, op):
+ array, arraytype = self.db.repr_argwithtype(op.args[0])
+ index = self.db.repr_arg(op.args[1])
+ indextype = self.db.repr_arg_type(op.args[1])
+ tmpvar = self.db.repr_tmpvar()
+ targetvar = self.db.repr_arg(op.result)
+ targettype = self.db.repr_arg_type(op.result)
+ if targettype != "void":
+ self.codewriter.getelementptr(tmpvar, arraytype, array,
+ ("uint", 1), (indextype, index))
+ self.codewriter.load(targetvar, targettype, tmpvar)
+ else:
+ self.codewriter.comment("***Skipping operation getarrayitem()***")
+
+ def getarraysubstruct(self, op):
+ array, arraytype = self.db.repr_argwithtype(op.args[0])
+ index = self.db.repr_arg(op.args[1])
+ indextype = self.db.repr_arg_type(op.args[1])
+ targetvar = self.db.repr_arg(op.result)
+ self.codewriter.getelementptr(targetvar, arraytype, array,
+ ("uint", 1), (indextype, index))
+
+ def setarrayitem(self, op):
+ array, arraytype = self.db.repr_argwithtype(op.args[0])
+ index = self.db.repr_arg(op.args[1])
+ indextype = self.db.repr_arg_type(op.args[1])
+
+ tmpvar = self.db.repr_tmpvar()
+
+ valuevar = self.db.repr_arg(op.args[2])
+ valuetype = self.db.repr_arg_type(op.args[2])
+ if valuetype != "void":
+ self.codewriter.getelementptr(tmpvar, arraytype, array,
+ ("uint", 1), (indextype, index))
+ self.codewriter.store(valuetype, valuevar, tmpvar)
+ else:
+ self.codewriter.comment("***Skipping operation setarrayitem()***")
+
+ def getarraysize(self, op):
+ array, arraytype = self.db.repr_argwithtype(op.args[0])
+ tmpvar = self.db.repr_tmpvar()
+ self.codewriter.getelementptr(tmpvar, arraytype, array, ("uint", 0))
+ targetvar = self.db.repr_arg(op.result)
+ targettype = self.db.repr_arg_type(op.result)
+ self.codewriter.load(targetvar, targettype, tmpvar)
Added: pypy/dist/pypy/translator/js/structnode.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/structnode.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,235 @@
+import py
+from pypy.translator.llvm.log import log
+from pypy.translator.llvm.node import LLVMNode, ConstantLLVMNode
+from pypy.translator.llvm import varsize
+from pypy.rpython import lltype
+
+log = log.structnode
+
+class StructTypeNode(LLVMNode):
+ __slots__ = "db struct ref name".split()
+
+ def __init__(self, db, struct):
+ assert isinstance(struct, lltype.Struct)
+ self.db = db
+ self.struct = struct
+ prefix = '%structtype.'
+ name = self.struct._name
+ self.ref = self.make_ref(prefix, name)
+ self.name = self.ref[len(prefix):]
+
+ def __str__(self):
+ return "<StructTypeNode %r>" %(self.ref,)
+
+ def _fields(self):
+ return [getattr(self.struct, name)
+ for name in self.struct._names_without_voids()]
+
+ def setup(self):
+ # Recurse
+ for field in self._fields():
+ self.db.prepare_type(field)
+
+ # ______________________________________________________________________
+ # main entry points from genllvm
+
+ def writedatatypedecl(self, codewriter):
+ fields_types = [self.db.repr_type(f) for f in self._fields()]
+ codewriter.structdef(self.ref, fields_types)
+
+class StructVarsizeTypeNode(StructTypeNode):
+ __slots__ = "constructor_ref constructor_decl".split()
+
+ def __init__(self, db, struct):
+ super(StructVarsizeTypeNode, self).__init__(db, struct)
+ prefix = '%new.varsizestruct.'
+ self.constructor_ref = self.make_ref(prefix, self.name)
+ self.constructor_decl = "%s * %s(%s %%len)" % \
+ (self.ref,
+ self.constructor_ref,
+ self.db.get_machine_word())
+
+ def __str__(self):
+ return "<StructVarsizeTypeNode %r>" %(self.ref,)
+
+ # ______________________________________________________________________
+ # main entry points from genllvm
+
+ def writedecl(self, codewriter):
+ # declaration for constructor
+ codewriter.declare(self.constructor_decl)
+
+ def writeimpl(self, codewriter):
+ log.writeimpl(self.ref)
+
+ # build up a list of indices to get to the last
+ # var-sized struct (or rather the according array)
+ indices_to_array = []
+ current = self.struct
+ while isinstance(current, lltype.Struct):
+ last_pos = len(current._names_without_voids()) - 1
+ indices_to_array.append(("uint", last_pos)) #struct requires uint consts
+ name = current._names_without_voids()[-1]
+ current = current._flds[name]
+ assert isinstance(current, lltype.Array)
+ varsize.write_constructor(self.db,
+ codewriter,
+ self.ref,
+ self.constructor_decl,
+ current,
+ indices_to_array)
+
+class StructNode(ConstantLLVMNode):
+ """ A struct constant. Can simply contain
+ a primitive,
+ a struct,
+ pointer to struct/array
+ """
+ __slots__ = "db value structtype ref _get_ref_cache _get_types".split()
+
+ def __init__(self, db, value):
+ self.db = db
+ self.value = value
+ self.structtype = self.value._TYPE
+ prefix = '%structinstance.'
+ name = str(value).split()[1]
+ self.ref = self.make_ref(prefix, name)
+ self._get_ref_cache = None
+ self._get_types = self._compute_types()
+
+ def __str__(self):
+ return "<StructNode %r>" % (self.ref,)
+
+ def _compute_types(self):
+ return [(name, self.structtype._flds[name])
+ for name in self.structtype._names_without_voids()]
+
+ def _getvalues(self):
+ values = []
+ for name, T in self._get_types:
+ value = getattr(self.value, name)
+ values.append(self.db.repr_constant(value)[1])
+ return values
+
+ def setup(self):
+ for name, T in self._get_types:
+ assert T is not lltype.Void
+ value = getattr(self.value, name)
+ self.db.prepare_constant(T, value)
+
+ p, c = lltype.parentlink(self.value)
+ if p is not None:
+ self.db.prepare_constant(lltype.typeOf(p), p)
+
+ def get_typerepr(self):
+ return self.db.repr_type(self.structtype)
+
+ def get_childref(self, index):
+ pos = 0
+ found = False
+ for name in self.structtype._names_without_voids():
+ if name == index:
+ found = True
+ break
+ pos += 1
+ #Structure types require uint constants!
+ #see: http://llvm.cs.uiuc.edu/docs/LangRef.html#i_getelementptr
+ return "getelementptr(%s* %s, int 0, uint %s)" %(
+ self.get_typerepr(),
+ self.get_ref(),
+ pos)
+
+ def get_ref(self):
+ """ Returns a reference as used for operations in blocks. """
+ if self._get_ref_cache:
+ return self._get_ref_cache
+ p, c = lltype.parentlink(self.value)
+ if p is None:
+ ref = self.ref
+ else:
+ ref = self.db.get_childref(p, c)
+ self._get_ref_cache = ref
+ return ref
+
+ def get_pbcref(self, toptr):
+ """ Returns a reference as used per pbc. """
+ return self.get_ref()
+
+ def constantvalue(self):
+ """ Returns the constant representation for this node. """
+ values = self._getvalues()
+ all_values = ",\n ".join(values)
+ return "%s {\n %s\n }\n" % (self.get_typerepr(), all_values)
+
+
+class StructVarsizeNode(StructNode):
+ """ A varsize struct constant. Can simply contain
+ a primitive,
+ a struct,
+ pointer to struct/array
+
+ and the last element *must* be
+ an array
+ OR
+ a series of embedded structs, which has as its last element an array.
+ """
+
+ def __str__(self):
+ return "<StructVarsizeNode %r>" % (self.ref,)
+
+ def _getvalues(self):
+ values = []
+ for name, T in self._get_types[:-1]:
+ value = getattr(self.value, name)
+ values.append(self.db.repr_constant(value)[1])
+ values.append(self._get_lastnoderepr())
+ return values
+
+ def _get_lastnode_helper(self):
+ lastname, LASTT = self._get_types[-1]
+ assert isinstance(LASTT, lltype.Array) or (
+ isinstance(LASTT, lltype.Struct) and LASTT._arrayfld)
+ value = getattr(self.value, lastname)
+ return self.db.repr_constant(value)
+
+ def _get_lastnode(self):
+ return self._get_lastnode_helper()[0]
+
+ def _get_lastnoderepr(self):
+ return self._get_lastnode_helper()[1]
+
+ def setup(self):
+ super(StructVarsizeNode, self).setup()
+
+ def get_typerepr(self):
+ try:
+ return self._get_typerepr_cache
+ except:
+ # last type is a special case and need to be worked out recursively
+ types = self._get_types[:-1]
+ types_repr = [self.db.repr_type(T) for name, T in types]
+ types_repr.append(self._get_lastnode().get_typerepr())
+ result = "{%s}" % ", ".join(types_repr)
+ self._get_typerepr_cache = result
+ return result
+
+ def get_ref(self):
+ if self._get_ref_cache:
+ return self._get_ref_cache
+ ref = super(StructVarsizeNode, self).get_ref()
+ typeval = self.db.repr_type(lltype.typeOf(self.value))
+ ref = "cast (%s* %s to %s*)" % (self.get_typerepr(),
+ ref,
+ typeval)
+ self._get_ref_cache = ref
+ return ref
+
+ def get_pbcref(self, toptr):
+ """ Returns a reference as used per pbc. """
+ ref = self.ref
+ p, c = lltype.parentlink(self.value)
+ assert p is None, "child arrays are NOT needed by rtyper"
+ fromptr = "%s*" % self.get_typerepr()
+ refptr = "getelementptr (%s %s, int 0)" % (fromptr, ref)
+ ref = "cast(%s %s to %s)" % (fromptr, refptr, toptr)
+ return ref
Added: pypy/dist/pypy/translator/js/test/__init__.py
==============================================================================
Added: pypy/dist/pypy/translator/js/test/runtest.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/test/runtest.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,49 @@
+import py, os
+from pypy.translator.translator import Translator
+from pypy.translator.js.js import JS
+from pypy.translator.js.log import log
+log = log.runtest
+
+
+def _CLI_is_on_path():
+ try:
+ py.path.local.sysfind('js') #we recommend Spidermonkey
+ except py.error.ENOENT:
+ return False
+ return True
+
+def write_wrapper(js_filename):
+ jswrapper_filename = js_filename.new(ext='_wrapper.js')
+ f = open(str(jswrapper_filename), 'w')
+ f.write('print(42);\n')
+ f.close()
+ log('Written:', jswrapper_filename)
+ return jswrapper_filename
+
+class jscallable(object):
+ def __init__(self, jswrapper_filename):
+ self.jswrapper_filename = jswrapper_filename
+
+ def __call__(self):
+ cmd = 'js "%s"' % str(self.jswrapper_filename)
+ s = os.popen(cmd).read()
+ e = eval(s)
+ return e
+
+def compile(function, annotation=[], view=False):
+ if not _CLI_is_on_path():
+ py.test.skip('Javascript CLI (js) not found')
+
+ t = Translator(function)
+ a = t.annotate(annotation)
+ a.simplify()
+ t.specialize()
+ t.backend_optimizations()
+ if view:
+ t.view()
+
+ js = JS(t, function)
+ log('Written:', js.filename)
+
+ jswrapper_filename = write_wrapper(js.filename)
+ return jscallable(jswrapper_filename)
Added: pypy/dist/pypy/translator/js/test/test_trivial.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/test/test_trivial.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,8 @@
+import py
+from pypy.translator.js.test.runtest import compile
+
+def test_CLI():
+ def simple1():
+ return 42
+ f = compile(simple1)
+ assert f() == simple1()
Added: pypy/dist/pypy/translator/js/varsize.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js/varsize.py Thu Oct 6 22:24:04 2005
@@ -0,0 +1,38 @@
+from pypy.rpython.rstr import STR
+
+def write_constructor(db, codewriter, ref, constructor_decl, ARRAY,
+ indices_to_array=()):
+
+ #varsized arrays and structs look like this:
+ #Array: {int length , elemtype*}
+ #Struct: {...., Array}
+
+ # the following indices access the last element in the array
+ elemtype = db.repr_type(ARRAY.OF)
+ word = lentype = db.get_machine_word()
+ uword = db.get_machine_uword()
+
+ codewriter.openfunc(constructor_decl)
+
+ # Need room for NUL terminator
+ if ARRAY is STR.chars:
+ codewriter.binaryop("add", "%actuallen", lentype, "%len", 1)
+ else:
+ codewriter.cast("%actuallen", lentype, "%len", lentype)
+
+ elemindices = list(indices_to_array) + [("uint", 1), (lentype, "%actuallen")]
+ codewriter.getelementptr("%size", ref + "*", "null", *elemindices)
+ codewriter.cast("%usize", elemtype + "*", "%size", uword)
+ codewriter.malloc("%ptr", "sbyte", "%usize", atomic=ARRAY._is_atomic())
+ codewriter.cast("%result", "sbyte*", "%ptr", ref + "*")
+
+ indices_to_arraylength = tuple(indices_to_array) + (("uint", 0),)
+ # the following accesses the length field of the array
+ codewriter.getelementptr("%arraylength", ref + "*",
+ "%result",
+ *indices_to_arraylength)
+ codewriter.store(lentype, "%len", "%arraylength")
+
+ codewriter.ret(ref + "*", "%result")
+ codewriter.closefunc()
+
More information about the Pypy-commit
mailing list