[pypy-svn] r34241 - in pypy/dist/pypy/translator: jvm jvm/src jvm/test oosupport
niko at codespeak.net
niko at codespeak.net
Sun Nov 5 15:55:08 CET 2006
Author: niko
Date: Sun Nov 5 15:55:06 2006
New Revision: 34241
Added:
pypy/dist/pypy/translator/jvm/builtin.py
pypy/dist/pypy/translator/jvm/constant.py
pypy/dist/pypy/translator/jvm/test/test_class.py
pypy/dist/pypy/translator/oosupport/constant.py
pypy/dist/pypy/translator/oosupport/database.py
Modified:
pypy/dist/pypy/translator/jvm/database.py
pypy/dist/pypy/translator/jvm/generator.py
pypy/dist/pypy/translator/jvm/genjvm.py
pypy/dist/pypy/translator/jvm/node.py
pypy/dist/pypy/translator/jvm/src/PyPy.java
pypy/dist/pypy/translator/jvm/typesystem.py
pypy/dist/pypy/translator/oosupport/metavm.py
Log:
Rather large check-in with JVM restructing. Warning: new code in oosupport
will likely change to match CLI more closely as I integrate those. Highlights:
1. Begin the work pulling out constant generation and database code and making
it common between CLI and JVM. Right now, it's only used by the JVM. Next
check-in will be to integrate with CLI.
2. Unify database nodes and type system both for instances and built-ins.
This simplifies JVM code considerably.
3. Implement several other random bug fixes.
Added: pypy/dist/pypy/translator/jvm/builtin.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/builtin.py Sun Nov 5 15:55:06 2006
@@ -0,0 +1,96 @@
+from pypy.translator.jvm import typesystem as jvmtype
+from pypy.translator.jvm import generator as jvmgen
+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.jvm.typesystem import \
+ jInt, jVoid, jStringBuilder, jString, jPyPy, jChar
+
+jStringBuilder = jvmtype.jStringBuilder
+
+# ______________________________________________________________________
+# Mapping of built-in OOTypes to JVM types
+
+class JvmBuiltInType(jvmtype.JvmClassType):
+
+ """
+ Represents built-in types to JVM. May optionally be associated
+ with an OOTYPE; if it is, then we will support lookup of the OOTYPE
+ methods and will re-map them as needed to the JVM equivalents.
+ """
+
+ def __init__(self, db, classty, OOTYPE):
+ jvmtype.JvmClassType.__init__(self, classty.name)
+ self.db = db
+ self.OOTYPE = OOTYPE # might be None
+
+ # We need to create a mapping for any generic parameters this
+ # OOTYPE may have. Other than SELFTYPE_T, we map each generic
+ # argument to ootype.ROOT. We use a hack here where we assume
+ # that the only generic parameters are named SELFTYPE_T,
+ # ITEMTYPE_T, KEYTYPE_T, or VALUETYPE_T.
+ self.generics = {}
+ if hasattr(self.OOTYPE, 'SELFTYPE_T'):
+ self.generics[self.OOTYPE.SELFTYPE_T] = self.OOTYPE
+ for param in ('ITEMTYPE_T', 'KEYTYPE_T', 'VALUETYPE_T'):
+ if hasattr(self.OOTYPE, param):
+ self.generics[getattr(self.OOTYPE, param)] = ootype.ROOT
+
+ def lookup_field(self, fieldnm):
+ """ Given a field name, returns a jvmgen.Field object """
+ _, FIELDTY = self.OOTYPE._lookup_field(fieldnm)
+ jfieldty = self.db.lltype_to_cts(FIELDTY)
+ return jvmgen.Field(
+ self.descriptor.class_name(), fieldnm, jfieldty, False)
+
+ def _map(self, ARG):
+ """ Maps ootype ARG to a java type. If arg is one of our
+ generic arguments, substitutes the appropriate type before
+ performing the mapping. """
+ return self.db.lltype_to_cts(self.generics.get(ARG,ARG))
+
+ def lookup_method(self, methodnm):
+ """ Given the method name, returns a jvmgen.Method object """
+
+ # Look for a shortcut method
+ try:
+ key = (self.OOTYPE.__class__, methodnm)
+ print "key=%r" % (key,)
+ print "hash=%r" % (built_in_methods,)
+ return built_in_methods[key]
+ except KeyError: pass
+
+ # Lookup the generic method by name.
+ GENMETH = self.OOTYPE._GENERIC_METHODS[methodnm]
+
+ # Create an array with the Java version of each type in the
+ # argument list and return type.
+ jargtypes = [self._map(P) for P in GENMETH.ARGS]
+ jrettype = self._map(GENMETH.RESULT)
+ return jvmgen.Method.v(self, methodnm, jargtypes, jrettype)
+
+# When we lookup a method on a BuiltInClassNode, we first check
+# the 'built_in_methods' table. This allows us to redirect to other
+# methods if we like.
+
+def _ll_build_method():
+ # Choose an appropriate ll_build depending on what representation
+ # we are using for ootype.String:
+ if True: # XXX db.using_byte_array...
+ return jvmgen.Method.v(
+ jStringBuilder, "toString", (),jString)
+ return jvmgen.Method.s(
+ jvmgen.PYPYJAVA, "ll_build", (jStringBuilder,), jOOString)
+
+built_in_methods = {
+ (ootype.StringBuilder.__class__, "ll_allocate"):
+ jvmgen.Method.v(jStringBuilder, "ensureCapacity", (jInt,), jVoid),
+
+ (ootype.StringBuilder.__class__, "ll_append_char"):
+ jvmgen.Method.s(jPyPy, "ll_append_char", (jStringBuilder, jChar), jVoid),
+
+ (ootype.StringBuilder.__class__, "ll_append"):
+ jvmgen.Method.s(jPyPy, "ll_append", (jStringBuilder, jString), jVoid),
+
+ (ootype.StringBuilder.__class__, "ll_build"):
+ _ll_build_method()
+
+ }
Added: pypy/dist/pypy/translator/jvm/constant.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/constant.py Sun Nov 5 15:55:06 2006
@@ -0,0 +1,81 @@
+from pypy.translator.jvm.generator import \
+ Field, Method, ACONST_NULL, ICONST, LDC, DCONST_0, DCONST_1, LDC2
+from pypy.translator.oosupport.constant import \
+ RecordConst, InstanceConst, ClassConst
+from pypy.translator.jvm.typesystem import jPyPyConst
+
+# ___________________________________________________________________________
+# Simple Constants
+#
+# We create simple dummy constant objects that follow the same
+# inteface as the complex constants from oosupport/constant.py. None
+# of these requires initialization, so they only support push() and
+# they should never find their way into the database's constant list.
+
+class Const(object):
+ def push(self, gen):
+ """ Emits code required to reference a constant. Usually invoked
+ by generator.emit() """
+ raise NotImplementedError
+
+class VoidConst(object):
+ def push(self, gen):
+ pass
+
+class NullConst(object):
+ def push(self, gen):
+ gen.emit(ACONST_NULL)
+
+class DoubleConst(Const):
+ def __init__(self, value):
+ self.value = value
+ def push(self, gen):
+ if value == 0.0:
+ gen.emit(DCONST_0)
+ elif value == 1.0:
+ gen.emit(DCONST_1)
+ else:
+ gen.emit(LDC2, self.value)
+
+class UnicodeConst(Const):
+ def __init__(self, value):
+ self.value = value
+ def push(self, gen):
+ assert isinstance(self.value, unicode)
+ gen.emit(LDC, res)
+
+# ___________________________________________________________________________
+# Complex Constants
+
+class JVMFieldStorage(object):
+ """ A mix-in for the oosupport constant classes that stores the
+ pointer for the constant into a field on a class. It implements
+ the push() and store() methods used by the oosupport classes and
+ elsewhere."""
+ def __init__(self):
+ # Note that self.name and self.value are set by the oosupport
+ # constance class:
+ fieldty = self.db.lltype_to_cts(self.value._TYPE)
+ self.fieldobj = Field(jPyPyConst.name, self.name, fieldty, True)
+
+ def push(self, gen):
+ self.fieldobj.load(gen)
+
+ def store(self, gen):
+ self.fieldobj.store(gen)
+
+class JVMRecordConst(RecordConst, JVMFieldStorage):
+ def __init__(self, db, record, count):
+ RecordConst.__init__(self, db, record, count)
+ JVMFieldStorage.__init__(self)
+
+class JVMInstanceConst(InstanceConst, JVMFieldStorage):
+ def __init__(self, db, obj, record, count):
+ InstanceConst.__init__(self, db, obj, record, count)
+ JVMFieldStorage.__init__(self)
+
+class JVMClassConst(ClassConst, JVMFieldStorage):
+ def __init__(self, db, class_, count):
+ ClassConst.__init__(self, db, class_, count)
+ JVMFieldStorage.__init__(self)
+
Modified: pypy/dist/pypy/translator/jvm/database.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/database.py (original)
+++ pypy/dist/pypy/translator/jvm/database.py Sun Nov 5 15:55:06 2006
@@ -1,144 +1,69 @@
"""
-The database tracks which graphs have already been generated, and maintains
-a worklist. It also contains a pointer to the type system. It is passed
-into every node for generation along with the generator.
+The database centralizes information about the state of our translation,
+and the mapping between the OOTypeSystem and the Java type system.
"""
+
from cStringIO import StringIO
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.ootypesystem import ootype
-from pypy.translator.jvm.typesystem import jvm_method_desc, ootype_to_jvm
+from pypy.translator.jvm import typesystem as jvmtype
from pypy.translator.jvm import node
from pypy.translator.jvm.option import getoption
import pypy.translator.jvm.generator as jvmgen
+import pypy.translator.jvm.constant as jvmconst
from pypy.translator.jvm.typesystem import \
- jStringBuilder, jInt, jVoid, jString, jOOString, jChar
+ jStringBuilder, jInt, jVoid, jString, jChar, jPyPyConst, jObject
+from pypy.translator.jvm.builtin import JvmBuiltInType
-# When we lookup a method on a BuiltInClassNode, we first check
-# the 'built_in_methods' table. This allows us to redirect to other
-# methods if we like.
-
-def _ll_build_method():
- # Choose an appropriate ll_build depending on what representation
- # we are using for ootype.String:
- if jOOString == jString:
- return jvmgen.Method.v(
- jStringBuilder.class_name(), "toString", (),jString)
- return jvmgen.Method.s(
- jvmgen.PYPYJAVA, "ll_build", (jStringBuilder,), jOOString)
-
-built_in_methods = {
- (ootype.StringBuilder.__class__, "ll_allocate"):
- jvmgen.Method.v(jStringBuilder.class_name(), "ensureCapacity",
- (jInt,), jVoid),
-
- (ootype.StringBuilder.__class__, "ll_append_char"):
- jvmgen.Method.s(jvmgen.PYPYJAVA, "ll_append_char",
- (jStringBuilder, jChar), jVoid),
-
- (ootype.StringBuilder.__class__, "ll_append"):
- jvmgen.Method.s(jvmgen.PYPYJAVA, "ll_append",
- (jStringBuilder, jOOString), jVoid),
-
- # XXX will not work with --byte-arrays
- (ootype.StringBuilder.__class__, "ll_build"):
- _ll_build_method()
-
- }
+from pypy.translator.oosupport.database import Database as OODatabase
-class BuiltInClassNode(object):
- """
- This is a fake node that is returned instead of a node.Class object
- when pending_class is invoked on a built-in type. It allows other
- code to query the fields and methods.
- """
-
- def __init__(self, db, OOTYPE):
- self.db = db
- self.OOTYPE = OOTYPE
- self.jvmtype = db.lltype_to_cts(OOTYPE)
-
- # Create a generic mapping. Other than SELFTYPE_T, we map each
- # generic argument to ootype.ROOT. We use a hack here where
- # we assume that the only generic parameters are named
- # SELFTYPE_T, ITEMTYPE_T, KEYTYPE_T, or VALUETYPE_T.
-
- self.generics = {}
-
- if hasattr(self.OOTYPE, 'SELFTYPE_T'):
- self.generics[self.OOTYPE.SELFTYPE_T] = self.OOTYPE
-
- for param in ('ITEMTYPE_T', 'KEYTYPE_T', 'VALUETYPE_T'):
- if hasattr(self.OOTYPE, param):
- self.generics[getattr(self.OOTYPE, param)] = ootype.ROOT
-
- def jvm_type(self):
- return self.jvmtype
-
- def lookup_field(self, fieldnm):
- """ Given a field name, returns a jvmgen.Field object """
- _, FIELDTY = self.OOTYPE._lookup_field(fieldnm)
- jfieldty = self.db.lltype_to_cts(FIELDTY)
- return jvmgen.Field(
- self.jvmtype.class_name(), fieldnm, jfieldty, False)
-
- def _map(self, ARG):
- """ Maps ootype ARG to a java type. If arg is one of our
- generic arguments, substitutes the appropriate type before
- performing the mapping. """
- return self.db.lltype_to_cts(self.generics.get(ARG,ARG))
-
- def lookup_method(self, methodnm):
- """ Given the method name, returns a jvmgen.Method object """
-
- # Look for a shortcut method
- try:
- key = (self.OOTYPE.__class__, methodnm)
- print "key=%r" % (key,)
- print "hash=%r" % (built_in_methods,)
- return built_in_methods[key]
- except KeyError: pass
-
- # Lookup the generic method by name.
- GENMETH = self.OOTYPE._GENERIC_METHODS[methodnm]
-
- # Create an array with the Java version of each type in the
- # argument list and return type.
- jargtypes = [self._map(P) for P in GENMETH.ARGS]
- jrettype = self._map(GENMETH.RESULT)
- return jvmgen.Method(
- self.jvmtype.class_name(),
- methodnm,
- jvm_method_desc(jargtypes, jrettype),
- opcode=jvmgen.INVOKEVIRTUAL)
-
+# ______________________________________________________________________
+# Database object
-class Database:
+class Database(OODatabase):
def __init__(self, genoo):
- # Public attributes:
- self.genoo = genoo
+ OODatabase.__init__(self, genoo)
# Private attributes:
self._classes = {} # Maps ootype class objects to node.Class objects,
# and JvmType objects as well
- self._counter = 0 # Used to create unique names
self._functions = {} # graph -> jvmgen.Method
self._function_names = {} # graph --> function_name
self._constants = {} # flowmodel.Variable --> jvmgen.Const
- self._pending_nodes = set() # Worklist
- self._rendered_nodes = set()
+ # _________________________________________________________________
+ # Java String vs Byte Array
+ #
+ # We allow the user to configure whether Python strings are stored
+ # as Java strings, or as byte arrays. The latter saves space; the
+ # former may be faster.
+ using_byte_array = False
+
+ # XXX have to fill this in
+
+ # _________________________________________________________________
+ # Miscellaneous
+
def _uniq(self, nm):
- cnt = self._counter
- self._counter += 1
- return nm + "_" + str(cnt) + "_"
+ return nm + "_" + str(self.unique())
def _pkg(self, nm):
return "%s.%s" % (getoption('package'), nm)
+ def class_name(self, TYPE):
+ jtype = self.lltype_to_cts(TYPE)
+ assert isinstance(jtype, jvmtype.JvmClassType)
+ return jtype.name
+
+ # _________________________________________________________________
+ # Node Creation
+ #
+ # Creates nodes that represents classes, functions, simple constants.
+
def _function_for_graph(self, classobj, funcnm, is_static, graph):
"""
@@ -153,46 +78,45 @@
funcobj = node.Function(
self, classobj, funcnm, jargtypes, jrettype, graph, is_static)
return funcobj
-
- def pending_node(self, node):
- self._pending_nodes.add(node)
-
- def pending_class(self, OOCLASS):
- if not isinstance(OOCLASS, ootype.Instance):
- return BuiltInClassNode(self, OOCLASS)
+
+ def _translate_instance(self, OOTYPE):
+ assert isinstance(OOTYPE, ootype.Instance)
+ assert OOTYPE is not ootype.ROOT
# Create class object if it does not already exist:
- if OOCLASS in self._classes:
- return self._classes[OOCLASS]
+ if OOTYPE in self._classes:
+ return self._classes[OOTYPE]
# Resolve super class first
- if OOCLASS._superclass:
- superclsnm = self.lltype_to_cts(OOCLASS._superclass).class_name()
- else:
- superclsobj = "java.lang.Object" #?
+ assert OOTYPE._superclass
+ supercls = self.pending_class(OOTYPE._superclass)
# TODO --- make package of java class reflect the package of the
# OO class?
clsnm = self._pkg(
- self._uniq(OOCLASS._name.replace('.','_')))
- clsobj = node.Class(clsnm, superclsnm)
+ self._uniq(OOTYPE._name.replace('.','_')))
+ clsobj = node.Class(clsnm, supercls)
+
+ print "Class %s has super %s" % (
+ clsnm, supercls.name)
# Store the class object for future calls
- self._classes[OOCLASS] = clsobj
- self._classes[clsobj.jvm_type()] = clsobj
+ self._classes[OOTYPE] = clsobj
# TODO --- mangle field and method names? Must be
# deterministic, or use hashtable to avoid conflicts between
# classes?
# Add fields:
- for fieldnm, (FIELDOOTY, fielddef) in OOCLASS._fields.iteritems():
+ for fieldnm, (FIELDOOTY, fielddef) in OOTYPE._fields.iteritems():
+ print "Class %s has field %s of type %s" % (
+ clsobj.name, fieldnm, FIELDOOTY)
if FIELDOOTY is ootype.Void: continue
fieldty = self.lltype_to_cts(FIELDOOTY)
clsobj.add_field(jvmgen.Field(clsnm, fieldnm, fieldty, False))
# Add methods:
- for mname, mimpl in OOCLASS._methods.iteritems():
+ for mname, mimpl in OOTYPE._methods.iteritems():
if not hasattr(mimpl, 'graph'):
# Abstract method
TODO
@@ -203,21 +127,21 @@
# there would be a type mismatch.
args = mimpl.graph.getargs()
SELF = args[0].concretetype
- if not ootype.isSubclass(OOCLASS, SELF): continue
+ if not ootype.isSubclass(OOTYPE, SELF): continue
mobj = self._function_for_graph(
clsobj, mname, False, mimpl.graph)
clsobj.add_method(mobj)
# currently, we always include a special "dump" method for debugging
# purposes
- dump_method = node.TestDumpMethod(self, OOCLASS, clsobj)
+ dump_method = node.TestDumpMethod(self, OOTYPE, clsobj)
clsobj.add_dump_method(dump_method)
self.pending_node(clsobj)
return clsobj
- def class_obj_for_jvm_type(self, jvmtype):
- return self._classes[jvmtype]
+ def pending_class(self, OOTYPE):
+ return self.lltype_to_cts(OOTYPE)
def pending_function(self, graph):
"""
@@ -230,48 +154,66 @@
if graph in self._functions:
return self._functions[graph]
classnm = self._pkg(self._uniq(graph.name))
- classobj = node.Class(classnm, 'java.lang.Object')
+ classobj = node.Class(classnm, self.pending_class(ootype.ROOT))
funcobj = self._function_for_graph(classobj, "invoke", True, graph)
classobj.add_method(funcobj)
self.pending_node(classobj)
res = self._functions[graph] = funcobj.method()
return res
- def len_pending(self):
- return len(self._pending_nodes)
-
- def pop(self):
- return self._pending_nodes.pop()
-
- def gen_constants(self, gen):
- pass
+ # _________________________________________________________________
+ # Constant Emitting
+ #
+ # We place all constants in a special "constant" class
+ #
+ # XXX I don't particularly like this code being here. database
+ # shouldn't be so specific? Guess it's okay...
+
+ RecordConst = jvmconst.JVMRecordConst
+ InstanceConst = jvmconst.JVMInstanceConst
+ ClassConst = jvmconst.JVMClassConst
+
+ def _begin_gen_constants(self, gen, all_constants):
+ gen.begin_class(jPyPyConst, jObject)
- def record_const(self, constobj):
- TYPE = constobj.concretetype
-
- # Handle the simple cases:
- if TYPE is ootype.Void:
- return jvmgen.VoidConst()
- elif TYPE in (ootype.Bool, ootype.Signed):
- return jvmgen.SignedIntConst(int(constobj.value))
- elif TYPE is ootype.Char or TYPE is ootype.UniChar:
- return jvmgen.SignedIntConst(ord(constobj.value))
- elif TYPE is ootype.SignedLongLong:
- return jvmgen.SignedLongConst(int(constobj.value))
- elif TYPE is ootype.UnsignedLongLong:
- return jvmgen.UnsignedLongConst(int(constobj.value))
- elif TYPE is ootype.Float:
- return jvmgen.DoubleConst(constobj.value)
-
- # Handle the complex cases:
- # In this case, we will need to create a method to
- # initialize the value and a field.
- # For NOW, we create a new class PER constant.
- # Clearly this is probably undesirable in the long
- # term.
- return jvmgen.WarnNullConst() # TODO
+ for c in all_constants:
+ assert isinstance(c, jvmconst.JVMFieldStorage)
+ gen.add_field(c.fieldobj)
+
+ # the constant initialization code is broken up into special
+ # methods that are then invoked from <clinit> --- this is to
+ # prevent the init functions from getting too big
+ self._constant_steps = 1
+ gen.begin_function('constant_init_0', [], [], jVoid, True)
+ return gen
+
+ def _interrupt_gen_constants(self):
+ gen.return_val(jVoid)
+ gen.end_function() # end constant_init_N
+
+ next_nm = "constant_init_%d" % self._constant_steps
+ self._constant_steps += 1
+ gen.begin_function(next_nm, [], [], jVoid, True)
+
+ def _end_gen_constants(self, gen):
+ gen.return_val(jVoid)
+ gen.end_function() # end constant_init_N
+
+ # The static init code just needs to call constant_init_1..N
+ gen.begin_function('<clinit>', [], [], jVoid, True)
+ for x in range(self._constant_steps):
+ m = jvmgen.Method.s(jPyPyConst, "constant_init_%d" % x, [], jVoid)
+ gen.emit(m)
+ gen.return_val(jVoid)
+ gen.end_function()
+
+ gen.end_class()
- # Other
+ # _________________________________________________________________
+ # Type printing functions
+ #
+ # Returns a method that prints details about the value out to
+ # stdout. Should generalize to make it allow for stderr as well.
_type_printing_methods = {
ootype.Signed:jvmgen.PYPYDUMPINT,
@@ -282,16 +224,35 @@
ootype.Class:jvmgen.PYPYDUMPOBJECT,
ootype.String:jvmgen.PYPYDUMPSTRING,
ootype.StringBuilder:jvmgen.PYPYDUMPOBJECT,
+ ootype.Void:jvmgen.PYPYDUMPVOID,
}
def generate_dump_method_for_ootype(self, OOTYPE):
+ """
+ Assuming than an instance of type OOTYPE is pushed on the
+ stack, returns a Method object that you can invoke. This
+ method will require that you also push an integer (usually 0)
+ that represents the indentation, and then invoke it. i.e., you
+ can do something like:
+
+ > gen.load(var)
+ > mthd = db.generate_dump_method_for_ootype(var.concretetype)
+ > gen.emit(jvmgen.ICONST, 0)
+ > mthd.invoke(gen)
+
+ to print the value of 'var'.
+ """
if OOTYPE in self._type_printing_methods:
return self._type_printing_methods[OOTYPE]
pclass = self.pending_class(OOTYPE)
assert hasattr(pclass, 'dump_method'), "No dump_method for %r" % (OOTYPE, )
return pclass.dump_method.method()
+ # _________________________________________________________________
# Type translation functions
+ #
+ # Functions which translate from OOTypes to JvmType instances.
+ # FIX --- JvmType and their Class nodes should not be different.
def escape_name(self, nm):
# invoked by oosupport/function.py; our names don't need escaping?
@@ -302,29 +263,56 @@
and name of the given variable"""
return self.lltype_to_cts(llv.concretetype), llv.name
+ # Dictionary for scalar types; in this case, if we see the key, we
+ # will return the value
+ ootype_to_scalar = {
+ ootype.Void: jvmtype.jVoid,
+ ootype.Signed: jvmtype.jInt,
+ ootype.Unsigned: jvmtype.jInt,
+ ootype.SignedLongLong: jvmtype.jLong,
+ ootype.UnsignedLongLong: jvmtype.jLong,
+ ootype.Bool: jvmtype.jBool,
+ ootype.Float: jvmtype.jDouble,
+ ootype.Char: jvmtype.jByte,
+ ootype.UniChar: jvmtype.jChar,
+ ootype.Class: jvmtype.jClass,
+ ootype.ROOT: jvmtype.jObject, # count this as a scalar...
+ }
+
+ # Dictionary for non-scalar types; in this case, if we see the key, we
+ # will return a JvmBuiltInType based on the value
+ ootype_to_builtin = {
+ ootype.String: jvmtype.jString,
+ ootype.StringBuilder: jvmtype.jStringBuilder
+ }
+
def lltype_to_cts(self, OOT):
""" Returns an instance of JvmType corresponding to
- the given OOType"""
-
- # Check the easy cases
- if OOT in ootype_to_jvm:
- return ootype_to_jvm[OOT]
+ the given OOType """
- # Now handle the harder ones
+ # Handle built-in types:
+ if OOT in self.ootype_to_scalar:
+ return self.ootype_to_scalar[OOT]
if isinstance(OOT, lltype.Ptr) and isinstance(t.TO, lltype.OpaqueType):
return jObject
+ if OOT in self.ootype_to_builtin:
+ return JvmBuiltInType(self, self.ootype_to_builtin[OOT], OOT)
+
+ # Handle non-built-in-types:
if isinstance(OOT, ootype.Instance):
- return self.pending_class(OOT).jvm_type()
+ return self._translate_instance(OOT)
if isinstance(OOT, ootype.Record):
- return XXX
+ return self._translate_record(OOT)
if isinstance(OOT, ootype.StaticMethod):
return XXX
+
+ assert False, "Untranslatable type %s!" % OOT
- # Uh-oh
- unhandled_case
-
- # Invoked by genoo:
- # I am not sure that we need them
+ # _________________________________________________________________
+ # Uh....
+ #
+ # These functions are invoked by the code in oosupport, but I
+ # don't think we need them or use them otherwise.
def record_function(self, graph, name):
self._function_names[graph] = name
Modified: pypy/dist/pypy/translator/jvm/generator.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/generator.py (original)
+++ pypy/dist/pypy/translator/jvm/generator.py Sun Nov 5 15:55:06 2006
@@ -1,29 +1,49 @@
import os #
from pypy.objspace.flow import model as flowmodel
from pypy.translator.oosupport.metavm import Generator
-from pypy.translator.jvm.typesystem import \
- JvmType, jObject, jPrintStream, jvm_for_class, jVoid, jvm_method_desc, \
- jInt, jByteArray, jOOString, jString, jStringBuilder
from pypy.rpython.ootypesystem import ootype
+from pypy.translator.oosupport.constant import push_constant
+from pypy.translator.jvm.typesystem import \
+ JvmType, jString, jInt, jLong, jDouble, jBool, jString, \
+ jPyPy, jVoid, jMath, desc_for_method, jPrintStream, jClass, jChar, \
+ jObject, jByteArray
# ___________________________________________________________________________
# Helper class string constants
-PYPYJAVA = "pypy.PyPy"
+PYPYJAVA = jPyPy.name
# ___________________________________________________________________________
-# JVM Opcode Flags:
-#
-# Indicates certain properties of each opcode. Used mainly for debugging
-# assertions
+# Miscellaneous helper functions
+
+def _isnan(v):
+ return v != v*1.0 or (v == 1.0 and v == 2.0)
-NOFLAGS = 0
-BRANCH = 1 # Opcode is a branching opcode (implies a label argument)
-INVOKE = 2 # Opcode is a Method object
-CONST5 = 4 # Opcode is specialized for int arguments from -1 to 5
-CONST3 = 8 # Opcode is specialized for int arguments from 0 to 3
-CLASSINM = 16 # Argument is an internal class name
-FIELD = 32 # Opcode is a Field object
+def _isinf(v):
+ return v!=0 and (v == v*2)
+
+def _unsigned_to_signed_32(val):
+ """ In the JVM, we store unsigned integers in a signed integer slot
+ (since JVM has no signed integers). This function converts an
+ unsigned value Python integer (possibly a long) into its corresponding
+ Python signed integer. """
+ if val <= 0x7FFFFFFF:
+ return int(val)
+ return int(_two_comp_32(val))
+
+def _unsigned_to_signed_64(val):
+ """ Same as _unsigned_to_signed_32, but for longs. """
+ if val <= 0x7FFFFFFFFFFFFFFF:
+ return val
+ return _two_comp_64(val)
+
+def _two_comp_32(val):
+ """ Returns the 32 bit two's complement. """
+ return -((val ^ 0xFFFFFFFF)+1)
+
+def _two_comp_64(val):
+ """ Returns the 64 bit two's complement. """
+ return -((val ^ 0xFFFFFFFFFFFFFFFF)+1)
# ___________________________________________________________________________
# JVM Opcodes:
@@ -31,40 +51,49 @@
# Map from symbolic name to an instance of the Opcode class
class Opcode(object):
- def __init__(self, flags, jvmstr):
+ def __init__(self, jvmstr):
"""
flags is a set of flags (see above) that describe opcode
jvmstr is the name for jasmin printouts
"""
- self.flags = flags
self.jvmstr = jvmstr
def __repr__(self):
return "<Opcode %s:%x>" % (self.jvmstr, self.flags)
-
- def specialize_opcode(self, args):
+
+ def specialize(self, args):
""" Process the argument list according to the various flags.
Returns a tuple (OPCODE, ARGS) where OPCODE is a string representing
- the new opcode, and ARGS is a list of arguments or empty tuple """
-
- if self.flags & CONST5:
- assert len(args) == 1
- if args[0] == -1:
- return self.jvmstr + "_m1", ()
- elif args[0] >= 0 and args[0] <= 5:
- return self.jvmstr + "_" + str(args[0]), ()
- else:
- return "ldc", args # HACK
-
- if self.flags & CONST3:
- assert len(args) == 1
- if args[0] >= 0 and args[0] <= 3:
- return self.jvmstr + "_" + str(args[0]), ()
-
- if self.flags & CLASSINM:
- assert len(args) == 1
- args = [args[0].int_class_name()]
-
+ the new opcode, and ARGS is a list of arguments or empty tuple.
+ Most of these do not do anything. """
+ return (self.jvmstr, args)
+
+class IntConstOpcode(Opcode):
+ """ The ICONST opcode specializes itself for small integer opcodes. """
+ def specialize(self, args):
+ assert len(args) == 1
+ if args[0] == -1:
+ return self.jvmstr + "_m1", ()
+ elif args[0] >= 0 and args[0] <= 5:
+ return self.jvmstr + "_" + str(args[0]), ()
+ # Non obvious: convert ICONST to LDC if the constant is out of
+ # range
+ return "ldc", args
+
+class VarOpcode(Opcode):
+ """ An Opcode which takes a variable index as an argument; specialized
+ to small integer indices. """
+ def specialize(self, args):
+ assert len(args) == 1
+ if args[0] >= 0 and args[0] <= 3:
+ return self.jvmstr + "_" + str(args[0]), ()
+ return Opcode.specialize(self, args)
+
+class IntClassNameOpcode(Opcode):
+ """ An opcode which takes an internal class name as its argument;
+ the actual argument will be a JvmType instance. """
+ def specialize(self, args):
+ args = [args[0].descriptor.int_class_name()]
return self.jvmstr, args
class OpcodeFamily(object):
@@ -76,12 +105,14 @@
defines one 'family' of opcodes, such as the LOAD family shown
above, and produces Opcode objects specific to a particular type.
"""
- def __init__(self, flags, suffix):
+ def __init__(self, opcclass, suffix):
"""
- flags is a set of flags (see above) that describe opcode
+ opcclass is the opcode subclass to use (see above) when
+ instantiating a particular opcode
+
jvmstr is the name for jasmin printouts
"""
- self.flags = flags
+ self.opcode_class = opcclass
self.suffix = suffix
self.cache = {}
@@ -89,27 +120,30 @@
try:
return self.cache[prefix]
except KeyError:
- self.cache[prefix] = obj = Opcode(self.flags, prefix+self.suffix)
+ self.cache[prefix] = obj = self.opcode_class(
+ prefix+self.suffix)
return obj
def for_type(self, argtype):
""" Returns a customized opcode of this family appropriate to
'argtype', a JvmType object. """
+ desc = argtype.descriptor
+
# These are always true:
- if argtype[0] == 'L': return self._o("a") # Objects
- if argtype[0] == '[': return self._o("a") # Arrays
- if argtype == 'I': return self._o("i") # Integers
- if argtype == 'J': return self._o("l") # Integers
- if argtype == 'D': return self._o("d") # Doubles
- if argtype == 'V': return self._o("") # Void [used by RETURN]
+ if desc[0] == 'L': return self._o("a") # Objects
+ if desc[0] == '[': return self._o("a") # Arrays
+ if desc == 'I': return self._o("i") # Integers
+ if desc == 'J': return self._o("l") # Integers
+ if desc == 'D': return self._o("d") # Doubles
+ if desc == 'V': return self._o("") # Void [used by RETURN]
# Chars/Bytes/Booleans are normally represented as ints
# in the JVM, but some opcodes are different. They use a
# different OpcodeFamily (see ArrayOpcodeFamily for ex)
- if argtype == 'C': return self._o("i") # Characters
- if argtype == 'B': return self._o("i") # Bytes
- if argtype == 'Z': return self._o("i") # Boolean
+ if desc == 'C': return self._o("i") # Characters
+ if desc == 'B': return self._o("i") # Bytes
+ if desc == 'Z': return self._o("i") # Boolean
assert False, "Unknown argtype=%s" % repr(argtype)
raise NotImplementedError
@@ -130,81 +164,83 @@
for cmpop in ('ne', 'eq', 'lt', 'gt', 'le', 'ge'):
ifop = "if%s" % cmpop
if_icmpop = "if_icmp%s" % cmpop
- globals()[ifop.upper()] = Opcode(BRANCH, ifop)
- globals()[if_icmpop.upper()] = Opcode(BRANCH, if_icmpop)
+ globals()[ifop.upper()] = Opcode(ifop)
+ globals()[if_icmpop.upper()] = Opcode(if_icmpop)
# Compare references, either against NULL or against each other
-IFNULL = Opcode(BRANCH, 'ifnull')
-IFNONNULL = Opcode(BRANCH, 'ifnonnull')
-IF_ACMPEQ = Opcode(BRANCH, 'if_acmpeq')
-IF_ACMPNE = Opcode(BRANCH, 'if_acmpne')
+IFNULL = Opcode('ifnull')
+IFNONNULL = Opcode('ifnonnull')
+IF_ACMPEQ = Opcode('if_acmpeq')
+IF_ACMPNE = Opcode('if_acmpne')
# Method invocation
-INVOKESTATIC = Opcode(INVOKE, 'invokestatic')
-INVOKEVIRTUAL = Opcode(INVOKE, 'invokevirtual')
-INVOKESPECIAL = Opcode(INVOKE, 'invokespecial')
+INVOKESTATIC = Opcode('invokestatic')
+INVOKEVIRTUAL = Opcode('invokevirtual')
+INVOKESPECIAL = Opcode('invokespecial')
# Other opcodes
-LDC = Opcode(NOFLAGS, 'ldc') # single-word types
-LDC2 = Opcode(NOFLAGS, 'ldc2_w') # double-word types: doubles and longs
-GOTO = Opcode(BRANCH, 'goto')
-ICONST = Opcode(CONST5, 'iconst')
-ACONST_NULL=Opcode(NOFLAGS, 'aconst_null')
-DCONST_0 = Opcode(NOFLAGS, 'dconst_0')
-DCONST_1 = Opcode(NOFLAGS, 'dconst_0')
-LCONST_0 = Opcode(NOFLAGS, 'lconst_1')
-LCONST_1 = Opcode(NOFLAGS, 'lconst_1')
-GETFIELD = Opcode(FIELD, 'getfield')
-PUTFIELD = Opcode(FIELD, 'putfield')
-GETSTATIC = Opcode(FIELD, 'getstatic')
-PUTSTATIC = Opcode(FIELD, 'putstatic')
-CHECKCAST = Opcode(CLASSINM, 'checkcast')
-INEG = Opcode(NOFLAGS, 'ineg')
-IXOR = Opcode(NOFLAGS, 'ixor')
-IADD = Opcode(NOFLAGS, 'iadd')
-ISUB = Opcode(NOFLAGS, 'isub')
-IMUL = Opcode(NOFLAGS, 'imul')
-IDIV = Opcode(NOFLAGS, 'idiv')
-IREM = Opcode(NOFLAGS, 'irem')
-IAND = Opcode(NOFLAGS, 'iand')
-IOR = Opcode(NOFLAGS, 'ior')
-ISHL = Opcode(NOFLAGS, 'ishl')
-ISHR = Opcode(NOFLAGS, 'ishr')
-IUSHR = Opcode(NOFLAGS, 'iushr')
-DCMPG = Opcode(NOFLAGS, 'dcmpg')
-DCMPL = Opcode(NOFLAGS, 'dcmpl')
-NOP = Opcode(NOFLAGS, 'nop')
-I2D = Opcode(NOFLAGS, 'i2d')
-I2L = Opcode(NOFLAGS, 'i2l')
-D2I= Opcode(NOFLAGS, 'd2i')
-L2I = Opcode(NOFLAGS, 'l2i')
-ATHROW = Opcode(NOFLAGS, 'athrow')
-DNEG = Opcode(NOFLAGS, 'dneg')
-DADD = Opcode(NOFLAGS, 'dadd')
-DSUB = Opcode(NOFLAGS, 'dsub')
-DMUL = Opcode(NOFLAGS, 'dmul')
-DDIV = Opcode(NOFLAGS, 'ddiv')
-DREM = Opcode(NOFLAGS, 'drem')
-LNEG = Opcode(NOFLAGS, 'lneg')
-LADD = Opcode(NOFLAGS, 'ladd')
-LSUB = Opcode(NOFLAGS, 'lsub')
-LMUL = Opcode(NOFLAGS, 'lmul')
-LDIV = Opcode(NOFLAGS, 'ldiv')
-LREM = Opcode(NOFLAGS, 'lrem')
-LAND = Opcode(NOFLAGS, 'land')
-LOR = Opcode(NOFLAGS, 'lor')
-LXOR = Opcode(NOFLAGS, 'lxor')
-LSHL = Opcode(NOFLAGS, 'lshl')
-LSHR = Opcode(NOFLAGS, 'lshr')
-LUSHR = Opcode(NOFLAGS, 'lushr')
-NEW = Opcode(CLASSINM, 'new')
-DUP = Opcode(NOFLAGS, 'dup')
-POP = Opcode(NOFLAGS, 'pop')
-INSTANCEOF= Opcode(CLASSINM, 'instanceof')
+LDC = Opcode('ldc') # single-word types
+LDC2 = Opcode('ldc2_w') # double-word types: doubles and longs
+GOTO = Opcode('goto')
+ICONST = IntConstOpcode('iconst')
+ACONST_NULL=Opcode('aconst_null')
+DCONST_0 = Opcode('dconst_0')
+DCONST_1 = Opcode('dconst_0')
+LCONST_0 = Opcode('lconst_1')
+LCONST_1 = Opcode('lconst_1')
+GETFIELD = Opcode('getfield')
+PUTFIELD = Opcode('putfield')
+GETSTATIC = Opcode('getstatic')
+PUTSTATIC = Opcode('putstatic')
+CHECKCAST = IntClassNameOpcode('checkcast')
+INEG = Opcode('ineg')
+IXOR = Opcode('ixor')
+IADD = Opcode('iadd')
+ISUB = Opcode('isub')
+IMUL = Opcode('imul')
+IDIV = Opcode('idiv')
+IREM = Opcode('irem')
+IAND = Opcode('iand')
+IOR = Opcode('ior')
+ISHL = Opcode('ishl')
+ISHR = Opcode('ishr')
+IUSHR = Opcode('iushr')
+DCMPG = Opcode('dcmpg')
+DCMPL = Opcode('dcmpl')
+NOP = Opcode('nop')
+I2D = Opcode('i2d')
+I2L = Opcode('i2l')
+D2I= Opcode('d2i')
+L2I = Opcode('l2i')
+ATHROW = Opcode('athrow')
+DNEG = Opcode('dneg')
+DADD = Opcode('dadd')
+DSUB = Opcode('dsub')
+DMUL = Opcode('dmul')
+DDIV = Opcode('ddiv')
+DREM = Opcode('drem')
+LNEG = Opcode('lneg')
+LADD = Opcode('ladd')
+LSUB = Opcode('lsub')
+LMUL = Opcode('lmul')
+LDIV = Opcode('ldiv')
+LREM = Opcode('lrem')
+LAND = Opcode('land')
+LOR = Opcode('lor')
+LXOR = Opcode('lxor')
+LSHL = Opcode('lshl')
+LSHR = Opcode('lshr')
+LUSHR = Opcode('lushr')
+NEW = IntClassNameOpcode('new')
+DUP = Opcode('dup')
+DUP2 = Opcode('dup2')
+POP = Opcode('pop')
+POP2 = Opcode('pop2')
+INSTANCEOF= IntClassNameOpcode('instanceof')
# Loading/storing local variables
-LOAD = OpcodeFamily(CONST3, "load")
-STORE = OpcodeFamily(CONST3, "store")
-RETURN = OpcodeFamily(NOFLAGS, "return")
+LOAD = OpcodeFamily(VarOpcode, "load")
+STORE = OpcodeFamily(VarOpcode, "store")
+RETURN = OpcodeFamily(Opcode, "return")
# Loading/storing from arrays
# *NOTE*: This family is characterized by the type of the ELEMENT,
@@ -213,9 +249,27 @@
# Also: here I break from convention by naming the objects ARRLOAD
# rather than ALOAD, even though the suffix is 'aload'. This is to
# avoid confusion with the ALOAD opcode.
-ARRLOAD = ArrayOpcodeFamily(NOFLAGS, "aload")
-ARRSTORE = ArrayOpcodeFamily(NOFLAGS, "astore")
+ARRLOAD = ArrayOpcodeFamily(Opcode, "aload")
+ARRSTORE = ArrayOpcodeFamily(Opcode, "astore")
+
+# ___________________________________________________________________________
+# Labels
+#
+# We use a class here just for sanity checks and debugging print-outs.
+
+class Label(object):
+
+ def __init__(self, number, desc):
+ """ number is a unique integer
+ desc is a short, descriptive string that is a valid java identifier """
+ self.label = "%s_%s" % (desc, number)
+ def __repr__(self):
+ return "Label(%s)"%self.label
+
+ def jasmin_syntax(self):
+ return self.label
+
# ___________________________________________________________________________
# Methods
#
@@ -227,13 +281,37 @@
class Method(object):
- def v(classnm, methnm, argtypes, rettype):
- return Method(classnm, methnm, jvm_method_desc(argtypes, rettype),
+ def v(classty, methnm, argtypes, rettype):
+ """
+ Shorthand to create a virtual method.
+ 'class' - JvmType object for the class
+ 'methnm' - name of the method (Python string)
+ 'argtypes' - list of JvmType objects, one for each argument but
+ not the this ptr
+ 'rettype' - JvmType for return type
+ """
+ assert isinstance(classty, JvmType)
+ classnm = classty.name
+ argtypes = [a.descriptor for a in argtypes]
+ rettype = rettype.descriptor
+ return Method(classnm, methnm, desc_for_method(argtypes, rettype),
opcode=INVOKEVIRTUAL)
v = staticmethod(v)
- def s(classnm, methnm, argtypes, rettype):
- return Method(classnm, methnm, jvm_method_desc(argtypes, rettype))
+ def s(classty, methnm, argtypes, rettype):
+ """
+ Shorthand to create a static method.
+ 'class' - JvmType object for the class
+ 'methnm' - name of the method (Python string)
+ 'argtypes' - list of JvmType objects, one for each argument but
+ not the this ptr
+ 'rettype' - JvmType for return type
+ """
+ assert isinstance(classty, JvmType)
+ classnm = classty.name
+ argtypes = [a.descriptor for a in argtypes]
+ rettype = rettype.descriptor
+ return Method(classnm, methnm, desc_for_method(argtypes, rettype))
s = staticmethod(s)
def __init__(self, classnm, methnm, desc, opcode=INVOKESTATIC):
@@ -248,48 +326,35 @@
self.method_name,
self.descriptor)
-MATHIABS = Method('java.lang.Math', 'abs', '(I)I')
-MATHLABS = Method('java.lang.Math', 'abs', '(L)L')
-MATHDABS = Method('java.lang.Math', 'abs', '(D)D')
-MATHFLOOR = Method('java.lang.Math', 'floor', '(D)D')
-PRINTSTREAMPRINTSTR = Method('java.io.PrintStream', 'print',
- '(Ljava/lang/String;)V', opcode=INVOKEVIRTUAL)
-PYPYUINTCMP = Method(PYPYJAVA, 'uint_cmp', '(II)I')
-PYPYULONGCMP = Method(PYPYJAVA, 'ulong', '(LL)I')
-PYPYUINTTODOUBLE = Method(PYPYJAVA, 'uint_to_double', '(I)D')
-PYPYDOUBLETOUINT = Method(PYPYJAVA, 'double_to_uint', '(D)I')
-PYPYLONGBITWISENEGATE = Method(PYPYJAVA, 'long_bitwise_negate', '(L)L')
-PYPYARRAYTOLIST = Method(PYPYJAVA, 'array_to_list',
- '([Ljava/lang/Object;)Ljava/util/List;')
-PYPYSTRTOINT = Method(PYPYJAVA, 'str_to_int',
- '(Ljava/lang/String;)I')
-PYPYSTRTOUINT = Method(PYPYJAVA, 'str_to_uint',
- '(Ljava/lang/String;)I')
-PYPYSTRTOLONG = Method(PYPYJAVA, 'str_to_long',
- '(Ljava/lang/String;)J')
-PYPYSTRTOULONG = Method(PYPYJAVA, 'str_to_ulong',
- '(Ljava/lang/String;)J')
-PYPYSTRTOBOOL = Method(PYPYJAVA, 'str_to_bool',
- '(Ljava/lang/String;)Z')
-PYPYSTRTODOUBLE = Method(PYPYJAVA, 'str_to_double',
- '(Ljava/lang/String;)D')
-PYPYSTRTOCHAR = Method(PYPYJAVA, 'str_to_char',
- '(Ljava/lang/String;)C')
-PYPYDUMPINDENTED = Method(PYPYJAVA, 'dump_indented',
- '(ILjava/lang/String;)V')
-PYPYDUMPINT = Method(PYPYJAVA, 'dump_int', '(II)V')
-PYPYDUMPUINT = Method(PYPYJAVA, 'dump_uint', '(II)V')
-PYPYDUMPLONG = Method(PYPYJAVA, 'dump_long', '(LI)V')
-PYPYDUMPDOUBLE = Method(PYPYJAVA, 'dump_double', '(DI)V')
-PYPYDUMPSTRING = Method(PYPYJAVA, 'dump_string',
- jvm_method_desc((jOOString,jInt),jVoid))
-PYPYDUMPBOOLEAN = Method(PYPYJAVA, 'dump_boolean', '(ZI)V')
-PYPYDUMPOBJECT = Method(PYPYJAVA, 'dump_object',
- '(Ljava/lang/Object;I)V')
-PYPYRUNTIMENEW = Method(PYPYJAVA, 'RuntimeNew',
- '(Ljava/lang/Class;)Ljava/lang/Object;')
-PYPYSTRING2BYTES = Method(PYPYJAVA, 'string2bytes',
- jvm_method_desc((jString),jByteArray))
+MATHIABS = Method.s(jMath, 'abs', (jInt,), jInt)
+MATHLABS = Method.s(jMath, 'abs', (jLong,), jLong)
+MATHDABS = Method.s(jMath, 'abs', (jDouble,), jDouble)
+MATHFLOOR = Method.s(jMath, 'floor', (jDouble,), jDouble)
+PRINTSTREAMPRINTSTR = Method.v(jPrintStream, 'print', (jString,), jVoid)
+CLASSFORNAME = Method.s(jClass, 'forName', (jString,), jClass)
+PYPYUINTCMP = Method.s(jPyPy, 'uint_cmp', (jInt,jInt,), jInt)
+PYPYULONGCMP = Method.s(jPyPy, 'ulong_cmp', (jLong,jLong), jInt)
+PYPYUINTTODOUBLE = Method.s(jPyPy, 'uint_to_double', (jInt,), jDouble)
+PYPYDOUBLETOUINT = Method.s(jPyPy, 'double_to_uint', (jDouble,), jInt)
+PYPYLONGBITWISENEGATE = Method.s(jPyPy, 'long_bitwise_negate', (jLong,), jLong)
+PYPYSTRTOINT = Method.s(jPyPy, 'str_to_int', (jString,), jInt)
+PYPYSTRTOUINT = Method.s(jPyPy, 'str_to_uint', (jString,), jInt)
+PYPYSTRTOLONG = Method.s(jPyPy, 'str_to_long', (jString,), jLong)
+PYPYSTRTOULONG = Method.s(jPyPy, 'str_to_ulong', (jString,), jLong)
+PYPYSTRTOBOOL = Method.s(jPyPy, 'str_to_bool', (jString,), jBool)
+PYPYSTRTODOUBLE = Method.s(jPyPy, 'str_to_double', (jString,), jDouble)
+PYPYSTRTOCHAR = Method.s(jPyPy, 'str_to_char', (jString,), jChar)
+PYPYDUMPINDENTED = Method.s(jPyPy, 'dump_indented', (jInt,jString,), jVoid)
+PYPYDUMPINT = Method.s(jPyPy, 'dump_int', (jInt,jInt), jVoid)
+PYPYDUMPUINT = Method.s(jPyPy, 'dump_uint', (jInt,jInt), jVoid)
+PYPYDUMPLONG = Method.s(jPyPy, 'dump_long', (jLong,jInt), jVoid)
+PYPYDUMPDOUBLE = Method.s(jPyPy, 'dump_double', (jDouble,jInt), jVoid)
+PYPYDUMPSTRING = Method.s(jPyPy, 'dump_string', (jString,jInt), jVoid)
+PYPYDUMPBOOLEAN = Method.s(jPyPy, 'dump_boolean', (jBool,jInt), jVoid)
+PYPYDUMPOBJECT = Method.s(jPyPy, 'dump_object', (jObject,jInt,), jVoid)
+PYPYDUMPVOID = Method.s(jPyPy, 'dump_void', (jInt,), jVoid)
+PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject)
+PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray)
# ___________________________________________________________________________
@@ -316,135 +381,15 @@
gen._instr(PUTFIELD, self)
def jasmin_syntax(self):
return "%s/%s %s" % (
- self.class_name.replace('.','/'), self.field_name, self.jtype)
-
-SYSTEMOUT = Field('java.lang.System', 'out', jPrintStream, True)
-SYSTEMERR = Field('java.lang.System', 'err', jPrintStream, True)
-
-# ___________________________________________________________________________
-# Constants
-#
-# Constant objects record constants of various types, and can be used
-# to emit the required instructions to load their value.
-
-class Const(object):
- def load(self, gen):
- """ Emits code required to reference a constant. Usually invoked
- by generator.emit() """
- raise NotImplementedError
- def initialize(self, gen):
- """ Emits code required to DEFINE a constant (if any). Default
- version does nothing. """
- pass
-
-class VoidConst(object):
- def load(self, gen):
- pass
-
-class NullConst(object):
- def load(self, gen):
- gen.emit(ACONST_NULL)
-
-class WarnNullConst(NullConst):
- def load(self, gen):
- gen.add_comment(" substituting NULL")
- NullConst.load(self, gen)
-
-class SignedIntConst(Const):
- def __init__(self, value):
- self.value = value
- def load(self, gen):
- # In theory, we could get rid of CONST5 flag and do optimization
- # here, but then all code would have to use SignedIntConst, and
- # that seems uglier
- gen.emit(ICONST, self.value)
-
-class UnsignedIntConst(SignedIntConst):
- def __init__(self, value):
- assert value >= 0
- if value <= 0x7FFFFFFF:
- SignedIntConst.__init__(self, value)
- else:
- # Find the negative version of the value that will
- # represent this constant, and treat it like a signed
- # integer:
- value = value ^ 0xFFFFFFFF
- value += 1
- value *= -1
- assert value < 0
- value = int(value)
- SignedIntConst.__init__(self, value)
-
-class DoubleConst(Const):
- def __init__(self, value):
- self.value = value
- def load(self, gen):
- if value == 0.0:
- gen.emit(DCONST_0)
- elif value == 1.0:
- gen.emit(DCONST_1)
- else:
- gen.emit(LDC2, self.value)
-
-class SignedLongConst(Const):
- def __init__(self, value):
- self.value = value
- def load(self, gen):
- if value == 0:
- gen.emit(LCONST_0)
- elif value == 1:
- gen.emit(LCONST_1)
- else:
- gen.emit(LDC2, self.value)
-
-class UnsignedLongConst(SignedLongConst):
- def __init__(self, value):
- assert value >= 0
- if value <= 0x7FFFFFFFFFFFFFFFL:
- SignedIntConst.__init__(self, value)
- else:
- # Find the negative version of the value that will
- # represent this constant, and treat it like a signed
- # integer:
- value = value ^ 0xFFFFFFFFFFFFFFFF
- value += 1
- value *= -1
- assert value < 0
- SignedLongConst.__init__(self, value)
-
-class UnicodeConst(Const):
- def __init__(self, value):
- self.value = value
- def load(self, gen):
- assert isinstance(self.value, unicode)
- def escape(char):
- if char == '"': return r'\"'
- if char == '\n': return r'\n'
- return char
- res = ('"' +
- "".join(escape(c) for c in self.value.encode('utf-8')) +
- '"')
- gen.emit(LDC, res)
-
-class ComplexConst(Const):
- def __init__(self, fieldinfo, methodinfo):
- """
- Stores information about "complex" constants. These are constants
- that we cannot embed in the Java file and which require a method
- to initialize. They are stored in static fields, and initialized
- with static methods that should be embedded in a class's static{}
- section.
-
- fieldinfo --- the static field that will hold the value
- methodinfo --- a static method that initializes the value. Should
- have no arguments.
- """
- self.fieldinfo = fieldinfo
- self.methodinfo = methodinfo
- def load(self, gen):
- self.fieldinfo.load(gen)
- def initialize(self, gen):
- gen.emit(self.methodinfo)
+ self.class_name.replace('.','/'),
+ self.field_name,
+ self.jtype.descriptor)
+
+SYSTEMOUT = Field('java.lang.System', 'out', jPrintStream, True)
+SYSTEMERR = Field('java.lang.System', 'err', jPrintStream, True)
+DOUBLENAN = Field('java.lang.Double', 'NaN', jDouble, True)
+DOUBLEPOSINF = Field('java.lang.Double', 'POSITIVE_INFINITY', jDouble, True)
+DOUBLENEGINF = Field('java.lang.Double', 'NEGATIVE_INFINITY', jDouble, True)
# ___________________________________________________________________________
# Generator State
@@ -452,9 +397,9 @@
class ClassState(object):
""" When you invoked begin_class(), one of these objects is allocated
and tracks the state as we go through the definition process. """
- def __init__(self, classnm, superclassnm):
- self.class_name = classnm
- self.superclass_name = superclassnm
+ def __init__(self, classty, superclassty):
+ self.class_type = classty
+ self.superclass_type = superclassty
def out(self, arg):
self.file.write(arg)
@@ -468,7 +413,7 @@
def add_var(self, jvar, jtype):
""" Adds new entry for variable 'jvar', of java type 'jtype' """
idx = self.next_offset
- self.next_offset += jtype.type_width()
+ self.next_offset += jtype.descriptor.type_width()
if jvar:
assert jvar not in self.local_vars # never been added before
self.local_vars[jvar] = idx
@@ -504,7 +449,7 @@
# If the name does not begin with '_', it will be called from
# outside the generator.
- def begin_class(self, classnm, superclsnm):
+ def begin_class(self, classty, superclsty):
"""
Begins a class declaration. Overall flow of class declaration
looks like:
@@ -517,11 +462,11 @@
Where items in brackets may appear anywhere from 0 to inf times.
- classnm --- full Java name of the class (i.e., "java.lang.String")
- superclassnm --- full Java name of the super class
+ classty --- JvmType for the class
+ superclassty --- JvmType for the superclass
"""
assert not self.curclass
- self.curclass = ClassState(classnm, superclsnm)
+ self.curclass = ClassState(classty, superclsty)
self._begin_class()
def end_class(self):
@@ -550,10 +495,9 @@
superclsnm --- same Java name of super class as from begin_class
"""
- jtype = jvm_for_class(self.curclass.class_name)
- self.begin_function("<init>", [], [jtype], jVoid)
- self.load_jvm_var(jtype, 0)
- jmethod = Method(self.curclass.superclass_name, "<init>", "()V",
+ self.begin_function("<init>", [], [self.curclass.class_type], jVoid)
+ self.load_jvm_var(self.curclass.class_type, 0)
+ jmethod = Method(self.curclass.superclass_type.name, "<init>", "()V",
opcode=INVOKESPECIAL)
jmethod.invoke(self)
self.return_val(jVoid)
@@ -614,8 +558,19 @@
self._instr(RETURN.for_type(vartype))
def load_string(self, str):
- uni = str.decode('utf-8')
- UnicodeConst(uni).load(self)
+ """ Pushes a Java version of a Python string onto the stack.
+ 'str' should be a Python string encoded in UTF-8 (I think) """
+ # Create an escaped version of str:
+ def escape(char):
+ if char == '"': return r'\"'
+ if char == '\n': return r'\n'
+ return char
+ res = ('"' +
+ "".join(escape(c) for c in str) +
+ '"')
+ # Use LDC to load the Java version:
+ # XXX --- support byte arrays here? Would be trickier!
+ self._instr(LDC, res)
def load_jvm_var(self, vartype, varidx):
""" Loads from jvm slot #varidx, which is expected to hold a value of
@@ -657,9 +612,8 @@
identifier.
'mark' --- if True, then also calls self.mark() with the new lbl """
- labelnum = self.label_counter
+ res = Label(self.label_counter, desc)
self.label_counter += 1
- res = ('Label', labelnum, desc)
if mark:
self.mark(res)
return res
@@ -668,7 +622,7 @@
""" Convenience method. Be sure you only call it from a
virtual method, not static methods. """
self.load_jvm_var(jObject, 0)
-
+
# __________________________________________________________________
# Exception Handling
@@ -749,7 +703,7 @@
return self.load_jvm_var(jty, idx)
if isinstance(value, flowmodel.Constant):
- return self.db.record_const(value).load(self)
+ return push_constant(self.db, value.concretetype, value.value, self)
raise Exception('Unexpected type for v in load(): '+
repr(value.concretetype) + " v=" + repr(value))
@@ -765,25 +719,14 @@
raise Exception('Unexpected type for v in store(): '+v)
def set_field(self, CONCRETETYPE, fieldname):
- if fieldname == "meta":
- # temporary hack
- self.add_comment(" WARNING: emulating meta for now")
- self.emit(POP)
- self.emit(POP)
- else:
- clsobj = self.db.pending_class(CONCRETETYPE)
- fieldobj = clsobj.lookup_field(fieldname)
- fieldobj.store(self)
+ clsobj = self.db.pending_class(CONCRETETYPE)
+ fieldobj = clsobj.lookup_field(fieldname)
+ fieldobj.store(self)
def get_field(self, CONCRETETYPE, fieldname):
- if fieldname == 'meta':
- self.add_comment(" WARNING: emulating meta for now")
- self.emit(POP)
- self.emit(ACONST_NULL)
- else:
- clsobj = self.db.pending_class(CONCRETETYPE)
- fieldobj = clsobj.lookup_field(fieldname)
- fieldobj.load(self)
+ clsobj = self.db.pending_class(CONCRETETYPE)
+ fieldobj = clsobj.lookup_field(fieldname)
+ fieldobj.load(self)
def downcast(self, TYPE):
jtype = self.db.lltype_to_cts(TYPE)
@@ -817,17 +760,17 @@
def call_oostring(self, OOTYPE):
cts_type = self.db.lltype_to_cts(OOTYPE)
if cts_type != jByteArray:
- mthd = Method.s(PYPYJAVA, 'oostring', [cts_type, jInt], jString)
+ mthd = Method.s(jPyPy, 'oostring', [cts_type, jInt], jString)
self.emit(mthd)
- if jOOString == jByteArray:
+ if self.db.using_byte_array:
self.emit(PYPYSTRING2BYTES)
else:
- mthd = Method.s(PYPYJAVA, 'oostring',
+ mthd = Method.s(jPyPy, 'oostring',
[jByteArray, jInt], jByteArray)
def new(self, TYPE):
jtype = self.db.lltype_to_cts(TYPE)
- ctor = Method(jtype.class_name(), "<init>", "()V", opcode=INVOKESPECIAL)
+ ctor = Method(jtype.name, "<init>", "()V", opcode=INVOKESPECIAL)
self.emit(NEW, jtype)
self.emit(DUP)
self.emit(ctor)
@@ -835,6 +778,69 @@
def instantiate(self):
self.emit(PYPYRUNTIMENEW)
+ def getclassobject(self, OOINSTANCE):
+ jvmtype = self.db.lltype_to_cts(OOINSTANCE)
+ self.load_string(jvmtype.name)
+ CLASSFORNAME.invoke(self)
+
+ def dup(self, OOTYPE):
+ jvmtype = self.db.lltype_to_cts(OOTYPE)
+ if jvmtype.descriptor.type_width() == 1:
+ self.emit(DUP)
+ else:
+ self.emit(DUP2)
+
+ def pop(self, OOTYPE):
+ jvmtype = self.db.lltype_to_cts(OOTYPE)
+ if jvmtype.descriptor.type_width() == 1:
+ self.emit(POP)
+ else:
+ self.emit(POP2)
+
+ def push_null(self, OOTYPE):
+ self.emit(ACONST_NULL)
+
+ def push_primitive_constant(self, TYPE, value):
+ if TYPE is ootype.Void:
+ return
+ elif TYPE in (ootype.Bool, ootype.Signed):
+ self.emit(ICONST, int(value))
+ elif TYPE is ootype.Unsigned:
+ # Converts the unsigned int into its corresponding signed value
+ # and emits it using ICONST.
+ self.emit(ICONST, _unsigned_to_signed_32(value))
+ elif TYPE is ootype.Char or TYPE is ootype.UniChar:
+ self.emit(ICONST, ord(value))
+ elif TYPE is ootype.SignedLongLong:
+ self._push_long_constant(long(value))
+ elif TYPE is ootype.UnsignedLongLong:
+ self._push_long_constant(_unsigned_to_signed_64(value))
+ elif TYPE is ootype.Float:
+ self._push_double_constant(float(value))
+ elif TYPE is ootype.String:
+ self.load_string(str(value))
+
+ def _push_long_constant(self, value):
+ if value == 0:
+ gen.emit(LCONST_0)
+ elif value == 1:
+ gen.emit(LCONST_1)
+ else:
+ gen.emit(LDC2, value)
+
+ def _push_double_constant(self, value):
+ if _isnan(value):
+ DOUBLENAN.load(self)
+ elif _isinf(value):
+ if value > 0: DOUBLEPOSINF.load(self)
+ else: DOUBLENEGINF.load(self)
+ elif value == 0.0:
+ gen.emit(DCONST_0)
+ elif value == 1.0:
+ gen.emit(DCONST_1)
+ else:
+ gen.emit(LDC2, self.value)
+
# __________________________________________________________________
# Methods invoked directly by strings in jvm/opcode.py
@@ -945,8 +951,8 @@
classnm --- full Java name of the class (i.e., "java.lang.String")
"""
- iclassnm = self.curclass.class_name.replace('.', '/')
- isuper = self.curclass.superclass_name.replace('.', '/')
+ iclassnm = self.curclass.class_type.descriptor.int_class_name()
+ isuper = self.curclass.superclass_type.descriptor.int_class_name()
jfile = "%s/%s.j" % (self.outdir, iclassnm)
@@ -970,8 +976,10 @@
self.curclass.out(" ; %s\n" % comment)
def add_field(self, fobj):
- self.curclass.out('.field public %s %s\n' % (
- fobj.field_name, fobj.jtype))
+ kw = ['public']
+ if fobj.is_static: kw.append('static')
+ self.curclass.out('.field %s %s %s\n' % (
+ " ".join(kw), fobj.field_name, fobj.jtype.descriptor))
def _begin_function(self, funcname, argtypes, rettype, static):
@@ -981,8 +989,10 @@
kw = ['public']
if static: kw.append('static')
self.curclass.out('.method %s %s(%s)%s\n' % (
- " ".join(kw), funcname,
- "".join(argtypes), rettype))
+ " ".join(kw),
+ funcname,
+ "".join([a.descriptor for a in argtypes]),
+ rettype.descriptor))
def _end_function(self):
self.curclass.out('.limit stack 100\n') # HACK, track max offset
@@ -991,21 +1001,16 @@
def mark(self, lbl):
""" Marks the point that a label indicates. """
- _, lblnum, lbldesc = lbl
- assert _ == "Label"
- self.curclass.out(' %s_%s:\n' % (lbldesc, lblnum))
+ assert isinstance(lbl, Label)
+ self.curclass.out(' %s:\n' % lbl.jasmin_syntax())
def _instr(self, opcode, *args):
- jvmstr, args = opcode.specialize_opcode(args)
- # XXX this whole opcode flag things is stupid, redo to be class based
- if opcode.flags & BRANCH:
- assert len(args) == 1
- _, lblnum, lbldesc = args[0]
- args = ('%s_%s' % (lbldesc, lblnum),)
- if opcode.flags & (INVOKE|FIELD):
- assert len(args) == 1
- args = (args[0].jasmin_syntax(),)
- instr_text = ' %s %s' % (jvmstr, " ".join([str(s) for s in args]))
+ jvmstr, args = opcode.specialize(args)
+ def jasmin_syntax(arg):
+ if hasattr(arg, 'jasmin_syntax'): return arg.jasmin_syntax()
+ return str(arg)
+ strargs = [jasmin_syntax(arg) for arg in args]
+ instr_text = '%s %s' % (jvmstr, " ".join(strargs))
self.curclass.out(' %-60s ; %d\n' % (
instr_text, self.curfunc.instr_counter))
self.curfunc.instr_counter+=1
Modified: pypy/dist/pypy/translator/jvm/genjvm.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/genjvm.py (original)
+++ pypy/dist/pypy/translator/jvm/genjvm.py Sun Nov 5 15:55:06 2006
@@ -193,6 +193,7 @@
""" Creates and returns a Generator object according to the
configuration. Right now, however, there is only one kind of
generator: JasminGenerator """
+ print "Uh...?"
return JasminGenerator(
self.db, self.jvmsrc.javadir, self.jvmsrc.package)
Modified: pypy/dist/pypy/translator/jvm/node.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/node.py (original)
+++ pypy/dist/pypy/translator/jvm/node.py Sun Nov 5 15:55:06 2006
@@ -1,14 +1,24 @@
"""
-Rendering nodes for the JVM. I suspect that a lot of this could be
-made to be common between CLR and JVM.
+Nodes describe Java structures that we are building. They know how to
+render themselves so as to build the java structure they describe.
+They are entered onto the database worklist as we go.
+
+Some nodes describe parts of the JVM structure that already exist ---
+for example, there are nodes that are used to describe built-in JVM
+types like String, etc. In this case, they are never placed on the
+database worklist, and don't know how to render themselves (since they
+don't have to).
+
+Nodes representing classes that we will build also implement the JvmType
+interface defined by database.JvmType.
"""
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.ootypesystem import ootype
from pypy.translator.jvm.typesystem import \
- jString, jStringArray, jVoid, jThrowable
-from pypy.translator.jvm.typesystem import jvm_for_class, jvm_method_desc, jInt
+ JvmClassType, jString, jStringArray, jVoid, jThrowable, jInt, jPyPyMain, \
+ jObject
from pypy.translator.jvm.opcodes import opcodes
from pypy.translator.jvm.option import getoption
from pypy.translator.oosupport.function import Function as OOFunction
@@ -62,7 +72,7 @@
}
def render(self, gen):
- gen.begin_class('pypy.Main', 'java.lang.Object')
+ gen.begin_class(jPyPyMain, jObject)
gen.begin_function(
'main', (), [jStringArray], jVoid, static=True)
@@ -105,10 +115,10 @@
""" Represents a function to be emitted. """
- def __init__(self, db, classobj, name, jargtypes,
+ def __init__(self, db, classty, name, jargtypes,
jrettype, graph, is_static):
"""
- classobj: the Class object this is a part of (even static
+ classty: the JvmClassType object this is a part of (even static
functions have a class)
name: the name of the function
jargtypes: JvmType of each argument
@@ -117,7 +127,7 @@
is_static: boolean flag indicate whether func is static (!)
"""
OOFunction.__init__(self, db, graph, name, not is_static)
- self.classnm = classobj.name
+ self.classty = classty
self.jargtypes = jargtypes
self.jrettype = jrettype
self._block_labels = {}
@@ -125,13 +135,13 @@
def method(self):
""" Returns a jvmgen.Method that can invoke this function """
if not self.is_method:
- opcode = jvmgen.INVOKESTATIC
+ ctor = jvmgen.Method.s
startidx = 0
else:
- opcode = jvmgen.INVOKEVIRTUAL
+ ctor = jvmgen.Method.v
startidx = 1
- mdesc = jvm_method_desc(self.jargtypes[startidx:], self.jrettype)
- return jvmgen.Method(self.classnm, self.name, mdesc, opcode=opcode)
+ return ctor(self.classty, self.name,
+ self.jargtypes[startidx:], self.jrettype)
def begin_render(self):
# Prepare argument lists for begin_function call
@@ -203,25 +213,22 @@
OOFunction._render_op(self, op)
-class Class(Node):
+class Class(Node, JvmClassType):
""" Represents a class to be emitted. Note that currently, classes
are emitted all in one shot, not piecemeal. """
- def __init__(self, name, supername):
+ def __init__(self, name, supercls):
"""
- 'name' and 'super_name' should be fully qualified Java class names like
- "java.lang.String"
+ 'name' should be a fully qualified Java class name like
+ "java.lang.String", supercls is a Class object
"""
- self.name = name # public attribute
- self.super_name = supername # public attribute
+ JvmClassType.__init__(self, name)
+ self.super_class = supercls
self.fields = {}
self.rendered = False
self.methods = {}
- def jvm_type(self):
- return jvm_for_class(self.name)
-
def add_field(self, fieldobj):
""" Creates a new field accessed via the jvmgen.Field
descriptor 'fieldobj'. Must be called before render()."""
@@ -230,11 +237,15 @@
def lookup_field(self, fieldnm):
""" Given a field name, returns a jvmgen.Field object """
- return self.fields[fieldnm]
+ if fieldnm in self.fields:
+ return self.fields[fieldnm]
+ return self.super_class.lookup_field(fieldnm)
def lookup_method(self, methodnm):
""" Given the method name, returns a jvmgen.Method object """
- return self.methods[methodnm].method()
+ if methodnm in self.methods:
+ return self.methods[methodnm].method()
+ return self.super_class.lookup_method(methodnm)
def add_method(self, func):
""" Creates a new method in this class, represented by the
@@ -249,7 +260,7 @@
def render(self, gen):
self.rendered = True
- gen.begin_class(self.name, self.super_name)
+ gen.begin_class(self, self.super_class)
for field in self.fields.values():
gen.add_field(field)
@@ -268,14 +279,13 @@
self.OOCLASS = OOCLASS
self.clsobj = clsobj
self.name = "_pypy_dump"
- self.jargtypes = [clsobj.jvm_type(), jInt]
+ self.jargtypes = [clsobj, jInt]
self.jrettype = jVoid
def method(self):
""" Returns a jvmgen.Method that can invoke this function """
- mdesc = jvm_method_desc(self.jargtypes[1:], self.jrettype)
- return jvmgen.Method(self.clsobj.name, self.name, mdesc,
- opcode=jvmgen.INVOKEVIRTUAL)
+ return jvmgen.Method.v(
+ self.clsobj, self.name, self.jargtypes[1:], self.jrettype)
def render(self, gen):
clsobj = self.clsobj
Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java
==============================================================================
--- pypy/dist/pypy/translator/jvm/src/PyPy.java (original)
+++ pypy/dist/pypy/translator/jvm/src/PyPy.java Sun Nov 5 15:55:06 2006
@@ -194,6 +194,9 @@
System.out.println(text);
}
+ public static void dump_void(int indent) {
+ }
+
public static void dump_int(int i, int indent) {
dump_indented(indent, Integer.toString(i));
}
Added: pypy/dist/pypy/translator/jvm/test/test_class.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/test/test_class.py Sun Nov 5 15:55:06 2006
@@ -0,0 +1,10 @@
+import py
+from pypy.translator.jvm.test.runtest import JvmTest
+from pypy.rpython.test.test_rclass import BaseTestRclass
+from pypy.rpython.test.test_rspecialcase import BaseTestRspecialcase
+
+class TestJvmClass(JvmTest, BaseTestRclass):
+ pass
+
+#class TestCliSpecialCase(CliTest, BaseTestRspecialcase):
+# pass
Modified: pypy/dist/pypy/translator/jvm/typesystem.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/typesystem.py (original)
+++ pypy/dist/pypy/translator/jvm/typesystem.py Sun Nov 5 15:55:06 2006
@@ -34,13 +34,25 @@
from pypy.translator.jvm.option import getoption
from pypy.translator.jvm.log import log
-class JvmType(str):
+# ___________________________________________________________________________
+# Type Descriptors
+#
+# Internal representations of types for the JVM. Generally speaking,
+# only the generator code should deal with these and even it tries to
+# avoid them except write before dumping to the output file.
+
+class JvmTypeDescriptor(str):
"""
- The class we use to represent JVM types; it is just a string with
- the JVM type descriptor at the moment. Using JvmType allows us to
- use isinstance, however. The grammar for type descriptors can be
- read about here:
+ An internal class representing JVM type descriptors, which are
+ essentially Java's short hand for types. This is the lowest level
+ of our representation for types and are mainly used when defining
+ the types of fields or arguments to methods. The grammar for type
+ descriptors can be read about here:
+
http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html
+
+ We use this class also to represent method descriptors, which define
+ a set of argument and return types.
"""
def is_scalar(self):
return self[0] != 'L' and self[0] != '['
@@ -48,6 +60,8 @@
return not self.is_scalar()
def is_array(self):
return self[0] == '['
+ def is_method(self):
+ return self[0] == '('
def class_name(self):
""" Converts a descriptor like Ljava/lang/Object; to
full class name java.lang.Object """
@@ -68,71 +82,114 @@
# JVM type functions
-def jvm_array_of(jtype):
+def desc_for_array_of(jdescr):
""" Returns a JvmType representing an array of 'jtype', which must be
another JvmType """
- assert isinstance(jtype, JvmType)
- return JvmType('['+str(jtype))
+ assert isinstance(jdescr, JvmTypeDescriptor)
+ return JvmTypeDescriptor('['+jdescr)
-def jvm_for_class(classnm):
+def desc_for_class(classnm):
""" Returns a JvmType representing a particular class 'classnm', which
should be a fully qualified java class name (i.e., 'java.lang.String') """
- return JvmType('L%s;' % classnm.replace('.','/'))
-
-# Common JVM types
-jVoid = JvmType('V')
-jInt = JvmType('I')
-jLong = JvmType('J')
-jBool = JvmType('Z')
-jDouble = JvmType('D')
-jByte = JvmType('B')
-jByteArray = jvm_array_of(jByte)
-jChar = JvmType('C')
-jThrowable = jvm_for_class('java.lang.Throwable')
-jObject = jvm_for_class('java.lang.Object')
-jString = jvm_for_class('java.lang.String')
-jStringArray = jvm_array_of(jString)
-jArrayList = jvm_for_class('java.util.ArrayList')
-jHashMap = jvm_for_class('java.util.HashMap')
-jIterator = jvm_for_class('java.util.Iterator')
-jClass = jvm_for_class('java.lang.Class')
-jStringBuilder = jvm_for_class('java.lang.StringBuilder')
-jPrintStream = jvm_for_class('java.io.PrintStream')
-
-# Map from OOType to an internal JVM type descriptor
-# only handles the simple cases
-ootype_to_jvm = {
- ootype.Void: jVoid,
- ootype.Signed: jInt,
- ootype.Unsigned: jInt,
- ootype.SignedLongLong: jLong,
- ootype.UnsignedLongLong: jLong,
- ootype.Bool: jBool,
- ootype.Float: jDouble,
- ootype.Char: jByte,
- ootype.UniChar: jChar,
- ootype.String: jString,
- ootype.ROOT: jObject,
-
- # We may want to use PyPy wrappers here later:
- llmemory.WeakGcAddress: jObject, # XXX
- ootype.StringBuilder: jStringBuilder,
- ootype.Class: jClass,
- ootype.List: jArrayList,
- ootype.Dict: jHashMap,
- ootype.DictItemsIterator:jIterator
- }
-
-# Determine which class we will use to represent strings:
-if getoption('byte-arrays'):
- ootype_to_jvm[ootype.String] = jByteArray
-jOOString = ootype_to_jvm[ootype.String]
+ return JvmTypeDescriptor('L%s;' % classnm.replace('.','/'))
-# Method descriptor construction
-def jvm_method_desc(argtypes, rettype):
+def desc_for_method(argtypes, rettype):
""" A Java method has a descriptor, which is a string specified
its argument and return types. This function converts a list of
argument types (JvmTypes) and the return type (also a JvmType),
into one of these descriptor strings. """
- return "(%s)%s" % ("".join(argtypes), rettype)
+ return JvmTypeDescriptor("(%s)%s" % ("".join(argtypes), rettype))
+
+# ______________________________________________________________________
+# Basic JVM Types
+
+class JvmType(object):
+ """
+ The JvmType interface defines the interface for type objects
+ that we return in the database in various places.
+ """
+ def __init__(self, descriptor):
+ """ 'descriptor' should be a jvm.generator.JvmTypeDescriptor object
+ for this type """
+ self.descriptor = descriptor # public
+ self.name = None # public, string like "java.lang.Object"
+ # (None for scalars and arrays)
+ def lookup_field(self, fieldnm):
+ """ Returns a jvm.generator.Field object representing the field
+ with the given name, or raises KeyError if that field does not
+ exist on this type. """
+ raise NotImplementedException
+ def lookup_method(self, methodnm):
+ """ Returns a jvm.generator.Method object representing the method
+ with the given name, or raises KeyError if that field does not
+ exist on this type. """
+ raise NotImplementedException
+
+ def __repr__(self):
+ return "%s<%s>" % (self.__class__.__name__, self.descriptor)
+
+class JvmScalarType(JvmType):
+ """
+ Subclass used for all scalar type instances.
+ """
+ def __init__(self, descrstr):
+ JvmType.__init__(self, JvmTypeDescriptor(descrstr))
+ def lookup_field(self, fieldnm):
+ raise KeyError(fieldnm) # Scalar objects have no fields
+ def lookup_method(self, methodnm):
+ raise KeyError(methodnm) # Scalar objects have no methods
+
+jVoid = JvmScalarType('V')
+jInt = JvmScalarType('I')
+jLong = JvmScalarType('J')
+jBool = JvmScalarType('Z')
+jDouble = JvmScalarType('D')
+jByte = JvmScalarType('B')
+jChar = JvmScalarType('C')
+class JvmClassType(JvmType):
+ """
+ Base class used for all class instances. Kind of an abstract class;
+ instances of this class do not support field or method lookup and
+ only work to obtain the descriptor. We use it on occasion for classes
+ like java.lang.Object etc.
+ """
+ def __init__(self, classnm):
+ JvmType.__init__(self, desc_for_class(classnm))
+ self.name = classnm # public String, like 'java.lang.Object'
+ def lookup_field(self, fieldnm):
+ raise KeyError(fieldnm) # we treat as opaque type
+ def lookup_method(self, methodnm):
+ raise KeyError(fieldnm) # we treat as opaque type
+
+jThrowable = JvmClassType('java.lang.Throwable')
+jObject = JvmClassType('java.lang.Object')
+jString = JvmClassType('java.lang.String')
+jArrayList = JvmClassType('java.util.ArrayList')
+jHashMap = JvmClassType('java.util.HashMap')
+jIterator = JvmClassType('java.util.Iterator')
+jClass = JvmClassType('java.lang.Class')
+jStringBuilder = JvmClassType('java.lang.StringBuilder')
+jPrintStream = JvmClassType('java.io.PrintStream')
+jMath = JvmClassType('java.lang.Math')
+jList = JvmClassType('java.util.List')
+jPyPy = JvmClassType('pypy.PyPy')
+jPyPyConst = JvmClassType('pypy.Constant')
+jPyPyMain = JvmClassType('pypy.Main')
+
+class JvmArrayType(JvmType):
+ """
+ Subclass used for all array instances.
+ """
+ def __init__(self, elemtype):
+ JvmType.__init__(self, desc_for_array_of(elemtype.descriptor))
+ self.element_type = elemtype
+ def lookup_field(self, fieldnm):
+ raise KeyError(fieldnm) # TODO adjust interface to permit opcode here
+ def lookup_method(self, methodnm):
+ raise KeyError(methodnm) # Arrays have no methods
+
+jByteArray = JvmArrayType(jByte)
+jObjectArray = JvmArrayType(jObject)
+jStringArray = JvmArrayType(jString)
+
Added: pypy/dist/pypy/translator/oosupport/constant.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/oosupport/constant.py Sun Nov 5 15:55:06 2006
@@ -0,0 +1,332 @@
+"""
+___________________________________________________________________________
+Constants
+
+Complex code for representing constants. For each complex constant,
+we create an object and record it in the database. These objects
+contain the knowledge about how to access the value of the constant,
+as well as the how to initialize it. The constants are initialized in
+several phases so that interdependencies do not prevent a problem.
+
+The initialization process works like this:
+
+1. create_pointer(): this creates uninitialized pointers, so that
+ circular references can be handled.
+
+2. initialize_opaque(): initializes all objects except for
+ CustomDicts. This basically allows any operation that treats the
+ object as an opaque pointer. Most initializations complete here.
+
+3. initialize_full(): initializes custom dicts: objects are inserted
+ into dicts here because their fields have been initialized. This
+ assumes that no custom dicts are inserted into any other custom dicts.
+
+These three methods will be invoked by the database's gen_constants()
+routine.
+"""
+
+from pypy.rpython.ootypesystem import ootype
+
+PRIMITIVE_TYPES = set([ootype.Void, ootype.Bool, ootype.Char, ootype.UniChar,
+ ootype.Float, ootype.Signed, ootype.Unsigned,
+ ootype.String, ootype.SignedLongLong,
+ ootype.UnsignedLongLong])
+
+def is_primitive(TYPE):
+ return TYPE in PRIMITIVE_TYPES
+
+def push_constant(db, TYPE, value, gen):
+ """ Class method that pushes the value of the specified
+ constant onto the stack. May or may not create an abstract constant
+ object.
+
+ db --- a Database
+ TYPE --- the ootype of the constant
+ value --- the ootype instance
+ gen --- a metavm.Generator
+ """
+ if is_primitive(TYPE):
+ return gen.push_primitive_constant(TYPE, value)
+
+ const = db.record_const(value)
+ if const.is_null():
+ gen.push_null(TYPE)
+ else:
+ const.push(gen)
+
+# ______________________________________________________________________
+# Constant generator
+
+class ConstantGenerator(object):
+ pass
+
+# ______________________________________________________________________
+# Constant base class
+
+class AbstractConst(object):
+ PRIORITY = 0
+
+ # ____________________________________________________________
+ # Hashing, equality comparison, and repr()
+ #
+ # Overloaded so that two AbstactConst objects representing
+ # the same OOValue are equal. Provide a sensible repr()
+
+ def __hash__(self):
+ return hash(self.value)
+
+ def __eq__(self, other):
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __repr__(self):
+ return '<Const %s %s>' % (self.name, self.value)
+
+ # ____________________________________________________________
+ # Simple query routines
+
+ def get_name(self):
+ pass
+
+ def get_type(self):
+ pass
+
+ def is_null(self):
+ return self.value is ootype.null(self.value._TYPE)
+
+ def is_inline(self):
+ """
+ Inline constants are not stored as static fields in the
+ Constant class, but they are newly created on the stack every
+ time they are used. Classes overriding is_inline should
+ override _load too.
+ """
+ return self.is_null() # by default only null constants are inlined
+
+ # ____________________________________________________________
+ # Loading and storing the constant
+ #
+ # These method are left here as an example. They are commented
+ # out because they must be implemented by the backend as a mix-in,
+ # and this way there is no conflict between the two base classes.
+
+ #def push(self, gen):
+ # """
+ # Pushes the value of this constant onto the stack.
+ # """
+ # raise NotImplementedException
+
+ #def store(self, gen):
+ # """
+ # The value of the constant will be pushed onto the stack;
+ # store places it somewhere so it can later be loaded.
+ # """
+ # raise NotImplementedException
+
+ # ____________________________________________________________
+ # Initializing the constant
+
+ def record_dependencies(self):
+ """
+ Ensures that all dependent objects are added to the database,
+ and any classes that are used are loaded. Called when the
+ constant object is created.
+ """
+ raise NotImplementedException
+
+ def create_pointer(self, gen):
+ """
+ Creates the pointer representing this object, but does not
+ initialize its fields. First phase of initialization.
+ """
+ raise NotImplementedException
+
+ def initialize_opaque(self, gen):
+ """
+ Initializes any constants that only use other constants in an
+ opaque fashion, without relying on them being fully initialized.
+ The big exception are custom dictionaries.
+ """
+ raise NotImplementedException
+
+ def initialize_full(self, gen):
+ """
+ Initializes all remaining constants, such as custom dicts,
+ that inspect the fields of their arguments. If it is ever the
+ case that such constants try to access one another, we'll need
+ to add a dependence graph, but currently the execution order
+ of this function between constants is undefined.
+ """
+ raise NotImplementedException
+
+ # ____________________________________________________________
+ # Internal helpers
+
+ def _record_const_if_complex(self, TYPE, value):
+ if not is_primitive(TYPE):
+ self.db.record_const(value)
+
+
+# ______________________________________________________________________
+# Records
+
+class RecordConst(AbstractConst):
+ def __init__(self, db, record, count):
+ self.db = db
+ self.cts = db.genoo.TypeSystem(db)
+ self.value = record
+ self.name = 'RECORD__%d' % count
+
+ def record_dependencies(self):
+ if self.value is ootype.null(self.value._TYPE):
+ return
+ for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems():
+ value = self.value._items[f_name]
+ self._record_const_if_complex(FIELD_TYPE, value)
+
+ def create_pointer(self, gen):
+ assert not self.is_null()
+ gen.new(self.value._TYPE)
+ self.store(gen)
+
+ def initialize_opaque(self, gen):
+ assert not self.is_null()
+ self.push(gen)
+ SELFTYPE = self.value._TYPE
+ for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems():
+ if FIELD_TYPE is not ootype.Void:
+ gen.dup(SELFTYPE)
+ #gen.load(value)
+ load(self.db, FIELD_TYPE, value, gen)
+ gen.set_field(SELFTYPE, f_name)
+ gen.pop(SELFTYPE)
+
+ def initialize_full(self, gen):
+ pass
+
+# ______________________________________________________________________
+# Instances
+
+class InstanceConst(AbstractConst):
+ def __init__(self, db, obj, static_type, count):
+ self.db = db
+ self.value = obj
+ self.cts = db.genoo.TypeSystem(db)
+ if static_type is None:
+ self.static_type = obj._TYPE
+ else:
+ self.static_type = static_type
+ db.genoo.TypeSystem(db).lltype_to_cts(
+ obj._TYPE) # force scheduling of obj's class
+ class_name = db.class_name(obj._TYPE).replace('.', '_')
+ self.name = '%s__%d' % (class_name, count)
+
+ def record_dependencies(self):
+ if not self.value:
+ return
+
+ INSTANCE = self.value._TYPE
+ while INSTANCE is not None:
+ for name, (TYPE, default) in INSTANCE._fields.iteritems():
+ if TYPE is ootype.Void:
+ continue
+ type_ = self.cts.lltype_to_cts(TYPE) # record type
+ value = getattr(self.value, name) # record value
+ self._record_const_if_complex(TYPE, value)
+ INSTANCE = INSTANCE._superclass
+
+ def is_null(self):
+ return not self.value
+
+ def create_pointer(self, gen):
+ assert not self.is_null()
+ gen.new(self.value._TYPE)
+ self.store(gen)
+
+ def _sorted_const_list(self):
+ # XXX, horrible hack: first collect all consts, then render
+ # CustomDicts at last because their ll_set could need other
+ # fields already initialized. We should really think a more
+ # general way to handle such things.
+ const_list = []
+ INSTANCE = self.value._TYPE
+ while INSTANCE is not None:
+ for name, (TYPE, default) in INSTANCE._fields.iteritems():
+ if TYPE is ootype.Void:
+ continue
+ value = getattr(self.value, name)
+ const_list.append((TYPE, INSTANCE, name, value))
+ INSTANCE = INSTANCE._superclass
+
+ def mycmp(x, y):
+ if isinstance(x[0], ootype.CustomDict) and not isinstance(y[0], ootype.CustomDict):
+ return 1 # a CustomDict is always greater than non-CustomDicts
+ elif isinstance(y[0], ootype.CustomDict) and not isinstance(x[0], ootype.CustomDict):
+ return -1 # a non-CustomDict is always less than CustomDicts
+ else:
+ return cmp(x, y)
+ const_list.sort(mycmp)
+
+ return const_list
+
+ def initialize_opaque(self, gen):
+ assert not self.is_null()
+
+ # Get a list of all the constants we'll need to initialize.
+ # I am not clear on why this needs to be sorted, actually,
+ # but we sort it.
+ const_list = self._sorted_const_list()
+
+ # Push ourself on the stack, and cast to our actual type if it
+ # is not the same as our static type
+ SELFTYPE = self.value._TYPE
+ self.push(gen)
+ if SELFTYPE is not self.static_type:
+ gen.downcast(SELFTYPE)
+
+ # Store each of our fields in the sorted order
+ for FIELD_TYPE, INSTANCE, name, value in const_list:
+ gen.dup(SELFTYPE)
+ push_constant(self.db, FIELD_TYPE, value, gen)
+ gen.set_field(INSTANCE, name)
+
+ # Pop selves from stack when done.
+ gen.pop(SELFTYPE)
+
+ def initialize_full(self, gen):
+ pass
+
+# ______________________________________________________________________
+# Class constants
+
+class ClassConst(AbstractConst):
+ def __init__(self, db, class_, count):
+ self.db = db
+ self.cts = db.genoo.TypeSystem(db)
+ self.value = class_
+ self.name = 'CLASS__%d' % count
+
+ def record_dependencies(self):
+ INSTANCE = self.value._INSTANCE
+ if INSTANCE is not None:
+ self.cts.lltype_to_cts(INSTANCE) # force scheduling class generation
+
+ def is_null(self):
+ return self.value._INSTANCE is None
+
+ def is_inline(self):
+ return True
+
+ def create_pointer(self, gen):
+ assert not self.is_null()
+ INSTANCE = self.value._INSTANCE
+ gen.getclassobject(INSTANCE)
+ self.store(gen)
+
+ def initialize_opaque(self, gen):
+ pass
+
+ def initialize_full(self, gen):
+ pass
Added: pypy/dist/pypy/translator/oosupport/database.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/oosupport/database.py Sun Nov 5 15:55:06 2006
@@ -0,0 +1,158 @@
+from pypy.translator.oosupport.constant import is_primitive
+from pypy.rpython.ootypesystem import ootype
+
+class Database(object):
+
+ def __init__(self, genoo):
+ self.genoo = genoo
+ self.cts = genoo.TypeSystem(self)
+ self._pending_nodes = set()
+ self._rendered_nodes = set()
+ self._const_cache = {}
+ self._unique_counter = 0
+
+ # ____________________________________________________________
+ # Miscellaneous
+
+ def unique(self):
+ """ Every time it is called, returns a unique integer. Used in
+ various places. """
+ self._unique_counter+=1
+ return self._unique_counter-1
+
+ def class_name(self, OOINSTANCE):
+ """ Returns the backend class name of the type corresponding
+ to OOINSTANCE"""
+ raise NotImplementedError
+
+ # ____________________________________________________________
+ # Generation phases
+
+ def gen_constants(self, ilasm):
+ """ Renders the constants uncovered during the graph walk"""
+
+ # Now, emit the initialization code:
+ all_constants = self._const_cache.values()
+ gen = self._begin_gen_constants(ilasm, all_constants)
+ gen.add_section("Create Pointer Phase")
+ ctr = 0
+ for const in all_constants:
+ gen.add_comment("Constant: %s" % const.name)
+ const.create_pointer(gen)
+ ctr = self._consider_interrupt(gen, ctr)
+ gen.add_section("Initialize Opaque Phase")
+ for const in all_constants:
+ gen.add_comment("Constant: %s" % const.name)
+ const.initialize_opaque(gen)
+ ctr = self._consider_interrupt(gen, ctr)
+ gen.add_section("Initialize Full Phase")
+ for const in all_constants:
+ gen.add_comment("Constant: %s" % const.name)
+ const.initialize_full(gen)
+ ctr = self._consider_interrupt(gen, ctr)
+ self._end_gen_constants(gen)
+
+ def _consider_interrupt(self, gen, ctr):
+ ctr += 1
+ if (ctr % 100) == 0: self._interrupt_gen_constants(gen)
+ return ctr
+
+ def _begin_gen_constants(self):
+ # returns a generator
+ raise NotImplementedError
+
+ def _interrupt_gen_constants(self):
+ # invoked every so often so as to break up the generated
+ # code and not create one massive function
+ pass
+
+ def _end_gen_constants(self, gen):
+ raise NotImplementedError
+
+ # ____________________________________________________________
+ # Node creation
+ #
+ # Creates nodes for various kinds of things.
+
+ def pending_class(self, INSTANCE):
+ """ Returns a Node representing the ootype.Instance provided """
+ raise NotImplementedError
+
+ def pending_function(self, graph):
+ """ Returns a Node representing the graph, which is being used as
+ a static function """
+ raise NotImplementedError
+
+ # ____________________________________________________________
+ # Basic Worklist Manipulation
+
+ def pending_node(self, node):
+ """ Adds a node to the worklist, so long as it is not already there
+ and has not already been rendered. """
+ if node not in self._rendered_nodes:
+ self._pending_nodes.add(node)
+
+ def len_pending(self):
+ return len(self._pending_nodes)
+
+ def pop(self):
+ return self._pending_nodes.pop()
+
+ # ____________________________________________________________
+ # Constants
+
+ # Defines the subclasses used to represent complex constants by
+ # _create_complex_const:
+
+ InstanceConst = None
+ RecordConst = None
+ ClassConst = None
+
+ def record_const(self, value):
+ """ Returns an object representing the constant, remembering also
+ any details needed to initialize the constant. value should be an
+ ootype constant value """
+ assert not is_primitive(value)
+ if value in self._const_cache:
+ return self._const_cache[value]
+ const = self._create_complex_const(value)
+ self._const_cache[value] = const
+ const.record_dependencies()
+ return const
+
+ def push_primitive_const(self, gen, value):
+ """ Helper which pushes a primitive constant onto the stack """
+ raise NotImplementedException
+
+ def _create_complex_const(self, value):
+
+ """ A helper method which creates a Constant wrapper object for
+ the given value. Uses the types defined in the sub-class. """
+
+ # Determine if the static type differs from the dynamic type.
+ if isinstance(value, ootype._view):
+ static_type = value._TYPE
+ value = value._inst
+ else:
+ static_type = None
+
+ # Find the appropriate kind of Const object.
+ if isinstance(value, ootype._instance):
+ return self.InstanceConst(self, value, static_type, self.unique())
+ elif isinstance(value, ootype._record):
+ return self.RecordConst(self, value, self.unique())
+ elif isinstance(value, ootype._class):
+ return self.ClassConst(self, value, self.unique())
+ #elif isinstance(value, ootype._list):
+ # return ListConst(db, value, count)
+ #elif isinstance(value, ootype._static_meth):
+ # return StaticMethodConst(db, value, count)
+ #elif isinstance(value, ootype._custom_dict):
+ # return CustomDictConst(db, value, count)
+ #elif isinstance(value, ootype._dict):
+ # return DictConst(db, value, count)
+ #elif isinstance(value, llmemory.fakeweakaddress):
+ # return WeakRefConst(db, value, count)
+ else:
+ assert False, 'Unknown constant: %s' % value
+
Modified: pypy/dist/pypy/translator/oosupport/metavm.py
==============================================================================
--- pypy/dist/pypy/translator/oosupport/metavm.py (original)
+++ pypy/dist/pypy/translator/oosupport/metavm.py Sun Nov 5 15:55:06 2006
@@ -23,6 +23,20 @@
"""
pass
+ def add_section(self, text):
+ """
+ Prints a distinguished comment
+ """
+ self.add_comment("_" * 70)
+ self.add_comment(text)
+
+ def pop(self, TYPE):
+ """ Pops a value off the top of the stack, which is of the
+ given TYPE.
+
+ Stack: val, ... -> ..."""
+ raise NotImplementedError
+
def dup(self, TYPE):
""" Duplicates the top of the stack, which is of the given TYPE.
@@ -83,7 +97,14 @@
Stack: obj, ... -> obj, ...
"""
raise NotImplementedError
-
+
+ def getclassobject(self, OOINSTANCE):
+ """
+ Gets the class object for the OOINSTANCE. The type of the class
+ object will depend on the backend, of course; for example in JVM
+ it is java.lang.Class.
+ """
+ raise NotImplementedError
def instantiate(self):
"""
@@ -146,9 +167,18 @@
Stack: ... -> newobj, ... """
raise NotImplementedError
- def push_null(self):
+ def push_null(self, TYPE):
+ """ Push a NULL value onto the stack (the NULL value represents
+ a pointer to an instance of OOType TYPE, if it matters to you). """
raise NotImplementedError
+ def push_primitive_constant(self, TYPE, value):
+ """ Push an instance of TYPE onto the stack with the given
+ value. TYPE will be one of the types enumerated in
+ oosupport.constant.PRIMITIVE_TYPES. value will be its
+ corresponding ootype implementation. """
+ raise NotImplementedError
+
class InstructionList(list):
def render(self, generator, op):
for instr in self:
More information about the Pypy-commit
mailing list