pypy / pypy / translator / jvm / genjvm.py

nikomatsakis d5f5094 



Philip Jenvey af4f8fd 
Philip Jenvey 16e5d86 


Amaury Forgeot d… d20ebe7 
nikomatsakis 81e6e18 



nikomatsakis 7d326ae 
Antonio Cuni 121bb55 

nikomatsakis 81e6e18 




nikomatsakis 7d326ae 

nikomatsakis 3611521 
nikomatsakis 5ca27a8 
nikomatsakis a401478 

nikomatsakis 9051760 
nikomatsakis 81e6e18 
Philip Jenvey 16e5d86 

nikomatsakis 81e6e18 
nikomatsakis cc5a4df 























nikomatsakis 81e6e18 









nikomatsakis 79bc8a0 






nikomatsakis 81e6e18 
Armin Rigo 85714aa 
nikomatsakis 81e6e18 





nikomatsakis 12fabb8 
nikomatsakis 81e6e18 


nikomatsakis 79bc8a0 
nikomatsakis 12fabb8 
nikomatsakis 589f38e 

Jean-Philippe St… c775f9d 
nikomatsakis 589f38e 



nikomatsakis 81e6e18 
nikomatsakis 12fabb8 
nikomatsakis 81e6e18 

nikomatsakis 79bc8a0 
nikomatsakis 81e6e18 



nikomatsakis 12fabb8 


nikomatsakis cc5a4df 
Maciej Fijalkows… 07af0e8 




nikomatsakis cc5a4df 
Amaury Forgeot d… f8a8ef4 
Maciej Fijalkows… 07af0e8 
nikomatsakis cc5a4df 



Toby Watson 2087798 
nikomatsakis cc5a4df 
nikomatsakis e34347c 

nikomatsakis 1bc2fd8 
Armin Rigo 85714aa 


nikomatsakis 589f38e 
Armin Rigo 85714aa 









nikomatsakis 1bc2fd8 
nikomatsakis 81e6e18 



nikomatsakis 589f38e 





nikomatsakis aec443b 
Amaury Forgeot d… f8a8ef4 






















nikomatsakis 96833bf 
Amaury Forgeot d… f8a8ef4 
nikomatsakis 96833bf 
nikomatsakis cc5a4df 

nikomatsakis e34347c 
nikomatsakis 81e6e18 
nikomatsakis 3611521 




nikomatsakis 81e6e18 





nikomatsakis 79bc8a0 
nikomatsakis 3611521 
nikomatsakis cc5a4df 
Toby Watson 2087798 
nikomatsakis cc5a4df 
Benjamin Peterso… d4e14ee 
nikomatsakis cc5a4df 
nikomatsakis 3611521 
Toby Watson 2087798 
nikomatsakis 3611521 
nikomatsakis d35fb4f 
Toby Watson 2087798 

Antonio Cuni 121bb55 
nikomatsakis 81e6e18 


nikomatsakis cc5a4df 

nikomatsakis 81e6e18 






nikomatsakis 79bc8a0 
Antonio Cuni 121bb55 


nikomatsakis 81e6e18 

Armin Rigo 743195d 

nikomatsakis cc5a4df 
nikomatsakis 81e6e18 

Philip Jenvey 16e5d86 

nikomatsakis 24c59d2 
Philip Jenvey 16e5d86 

























nikomatsakis 24c59d2 
nikomatsakis 7d326ae 
nikomatsakis 81e6e18 




nikomatsakis 7d326ae 





nikomatsakis 3cf40d8 
nikomatsakis 01b847f 
nikomatsakis fb770cd 
nikomatsakis 5ca27a8 
nikomatsakis a401478 
nikomatsakis 81e6e18 
nikomatsakis 7d326ae 
nikomatsakis 81e6e18 





nikomatsakis 7d326ae 
Antonio Cuni 5a53b85 


nikomatsakis 9051760 
Antonio Cuni 5a53b85 
nikomatsakis 81e6e18 


nikomatsakis 7d326ae 
nikomatsakis 12fabb8 
nikomatsakis 81e6e18 

nikomatsakis 7d326ae 
nikomatsakis 81e6e18 


nikomatsakis 40ad8e3 
nikomatsakis d5f5094 
nikomatsakis 81e6e18 
"""
Backend for the JVM.
"""

from __future__ import with_statement
import os
import re
import subprocess
import sys

import py
from pypy.tool.udir import udir
from pypy.translator.translator import TranslationContext
from pypy.translator.oosupport.genoo import GenOO
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.backendopt.checkvirtual import check_virtual_methods

from pypy.translator.jvm.generator import JasminGenerator
from pypy.translator.jvm.option import getoption
from pypy.translator.jvm.database import Database
from pypy.translator.jvm.log import log
from pypy.translator.jvm.node import EntryPoint, Function
from pypy.translator.jvm.opcodes import opcodes
from pypy.rpython.ootypesystem import ootype
from pypy.translator.jvm.constant import \
     JVMConstantGenerator, JVMStaticMethodConst, JVMCustomDictConst, \
     JVMWeakRefConst
from pypy.translator.jvm.prebuiltnodes import create_interlink_node

MIN_JAVA_VERSION = '1.6.0'

class JvmError(Exception):
    """ Indicates an error occurred in JVM backend """

    def pretty_print(self):
        print str(self)
    pass

class JvmSubprogramError(JvmError):
    """ Indicates an error occurred running some program """
    def __init__(self, res, args, stdout, stderr):
        self.res = res
        self.args = args
        self.stdout = stdout
        self.stderr = stderr

    def __str__(self):
        return "Error code %d running %s" % (self.res, repr(self.args))
        
    def pretty_print(self):
        JvmError.pretty_print(self)
        print "vvv Stdout vvv\n"
        print self.stdout
        print "vvv Stderr vvv\n"
        print self.stderr
        

class JvmGeneratedSource(object):
    
    """
    An object which represents the generated sources. Contains methods
    to find out where they are located, to compile them, and to execute
    them.

    For those interested in the location of the files, the following
    attributes exist:
    tmpdir --- root directory from which all files can be found (py.path obj)
    javadir --- the directory containing *.java (py.path obj)
    classdir --- the directory where *.class will be generated (py.path obj)
    package --- a string with the name of the package (i.e., 'java.util')

    The following attributes also exist to find the state of the sources:
    compiled --- True once the sources have been compiled successfully
    """
    _cached = None

    def __init__(self, tmpdir, package):
        """
        'tmpdir' --- the base directory where the sources are located
        'package' --- the package the sources are in; if package is pypy.jvm,
        then we expect to find the sources in $tmpdir/pypy/jvm
        'jfiles' --- list of files we need to run jasmin on
        """
        self.tmpdir = tmpdir
        self.package = package
        self.compiled = False
        self.jasmin_files = None
        
        # Determine various paths:
        self.thisdir = py.path.local(__file__).dirpath()
        self.rootdir = self.thisdir.join('src')
        self.srcdir = self.rootdir.join('pypy')
        self.jnajar = self.rootdir.join('jna.jar')
        self.jasminjar = self.rootdir.join('jasmin.jar')        

        # Compute directory where .j files are
        self.javadir = self.tmpdir
        for subpkg in package.split('.'):
            self.javadir = self.javadir.join(subpkg)

        # Compute directory where .class files should go
        self.classdir = self.javadir

    def set_jasmin_files(self, jfiles):
        self.jasmin_files = jfiles

    def _invoke(self, args, allow_stderr):
        import sys
        if sys.platform == 'nt':
            shell = True
        else:
            shell = False
        subp = subprocess.Popen(
            args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            shell=shell, universal_newlines=True)
        stdout, stderr = subp.communicate()
        res = subp.wait()
        if res or (not allow_stderr and stderr):
            raise JvmSubprogramError(res, args, stdout, stderr)
        return stdout, stderr, res

    def _compile_helper(self):
        # HACK: compile the Java helper classes.  Should eventually
        # use rte.py
        if JvmGeneratedSource._cached == self.classdir:
           return
        log.red('Compiling java classes')
        javafiles = self.srcdir.listdir('*.java')
        javasrcs = [str(jf) for jf in javafiles]
        self._invoke([getoption('javac'),
                      '-nowarn',
                      '-d', str(self.classdir),
                      '-classpath', str(self.jnajar),
                      ] + javasrcs,
                     True)
        # NOTE if you are trying to add more caching: some .java files
        # compile to several .class files of various names.
        JvmGeneratedSource._cached = self.classdir

    def compile(self):
        """
        Compiles the .java sources into .class files, ready for execution.
        """
        jascmd = [
            getoption('java'), 
            '-jar', str(self.jasminjar),
            '-g', 
            '-d', 
            str(self.javadir)]

        def split_list(files):
            "Split the files list into manageable pieces"

            # - On Windows 2000, commands in .bat are limited to 2047 chars.
            # - But the 'jasmin' script contains a line like
            #     path_to_jre/java -jar path_to_jasmin/jasmin.jar $*
            # So we limit the length of arguments files to:
            MAXLINE = 1500
    
            chunk = []
            chunklen = 0
            for f in files:
                # Account for the space between items
                chunklen += len(f) + 1
                if chunklen > MAXLINE:
                    yield chunk
                    chunk = []
                    chunklen = len(f)
                chunk.append(f)
            if chunk:
                yield chunk

        for files in split_list(self.jasmin_files):
            #print "Invoking jasmin on %s" % files
            self._invoke(jascmd + files, False)
            #print "... completed!"
                           
        self.compiled = True
        self._compile_helper()

    def _make_str(self, a):
        if isinstance(a, ootype._string):
            return a._str
        return str(a)

    def execute(self, args):
        """
        Executes the compiled sources in a separate process.  Returns the
        output as a string.  The 'args' are provided as arguments,
        and will be converted to strings.
        """
        assert self.compiled
        strargs = [self._make_str(a) for a in args]
        cmd = [getoption('java'),
               '-Xmx256M', # increase the heapsize so the microbenchmarks run
               '-cp',
               str(self.javadir)+os.pathsep+str(self.jnajar),
               self.package+".Main"] + strargs
        print "Invoking java to run the code"
        stdout, stderr, retval = self._invoke(cmd, True)
        print "...done!"
        sys.stderr.write(stderr)
        return stdout, stderr, retval

def generate_source_for_function(func, annotation, backendopt=False):
    
    """
    Given a Python function and some hints about its argument types,
    generates JVM sources that call it and print the result.  Returns
    the JvmGeneratedSource object.
    """
    
    if hasattr(func, 'im_func'):
        func = func.im_func
    t = TranslationContext()
    ann = t.buildannotator()
    ann.build_types(func, annotation)
    t.buildrtyper(type_system="ootype").specialize()
    if backendopt:
        check_virtual_methods(ootype.ROOT)
        backend_optimizations(t)
    main_graph = t.graphs[0]
    if getoption('view'): t.view()
    if getoption('wd'): tmpdir = py.path.local('.')
    else: tmpdir = udir
    jvm = GenJvm(tmpdir, t, EntryPoint(main_graph, True, True))
    return jvm.generate_source()

_missing_support_programs = None

def detect_missing_support_programs():
    global _missing_support_programs
    if _missing_support_programs is not None:
        if _missing_support_programs:
            py.test.skip(_missing_support_programs)
        return

    def missing(msg):
        global _missing_support_programs
        _missing_support_programs = msg
        py.test.skip(msg)

    for cmd in 'javac', 'java':
        if py.path.local.sysfind(getoption(cmd)) is None:
            missing("%s is not on your path" % cmd)
    if not _check_java_version(MIN_JAVA_VERSION):
        missing('Minimum of Java %s required' % MIN_JAVA_VERSION)
    _missing_support_programs = False

def _check_java_version(version):
    """Determine if java meets the specified version"""
    cmd = [getoption('java'), '-version']
    with open(os.devnull, 'w') as devnull:
        stderr = subprocess.Popen(cmd, stdout=devnull,
                                  stderr=subprocess.PIPE).communicate()[1]
    search = re.search('[\.0-9]+', stderr)
    return search and search.group() >= version

class GenJvm(GenOO):

    """ Master object which guides the JVM backend along.  To use,
    create with appropriate parameters and then invoke
    generate_source().  *You can not use one of these objects more than
    once.* """

    TypeSystem = lambda X, db: db # TypeSystem and Database are the same object 
    Function = Function
    Database = Database
    opcodes = opcodes
    log = log

    ConstantGenerator = JVMConstantGenerator
    CustomDictConst   = JVMCustomDictConst
    StaticMethodConst = JVMStaticMethodConst
    WeakRefConst = JVMWeakRefConst
    
    def __init__(self, tmpdir, translator, entrypoint):
        """
        'tmpdir' --- where the generated files will go.  In fact, we will
        put our binaries into the directory pypy/jvm
        'translator' --- a TranslationContext object
        'entrypoint' --- if supplied, an object with a render method
        """
        GenOO.__init__(self, tmpdir, translator, entrypoint)
        self.jvmsrc = JvmGeneratedSource(tmpdir, getoption('package'))

    def append_prebuilt_nodes(self):
        create_interlink_node(self.db)

    def generate_source(self):
        """ Creates the sources, and returns a JvmGeneratedSource object
        for manipulating them """
        GenOO.generate_source(self)
        self.jvmsrc.set_jasmin_files(self.db.jasmin_files())
        return self.jvmsrc

    def create_assembler(self):
        """ Creates and returns a Generator object according to the
        configuration.  Right now, however, there is only one kind of
        generator: JasminGenerator """
        return JasminGenerator(self.db, self.jvmsrc.javadir)
        
        
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.