[pypy-svn] r58000 - in pypy/branch/new-platformcheck/pypy: rpython/tool tool

nshepperd at codespeak.net nshepperd at codespeak.net
Tue Sep 9 13:49:21 CEST 2008


Author: nshepperd
Date: Tue Sep  9 13:49:18 2008
New Revision: 58000

Modified:
   pypy/branch/new-platformcheck/pypy/rpython/tool/rffi_platform.py
   pypy/branch/new-platformcheck/pypy/tool/gcc_cache.py
Log:
Import already-done work. So far all tests in pypy/rpython/tool/ pass, 
at least on my machine.


Modified: pypy/branch/new-platformcheck/pypy/rpython/tool/rffi_platform.py
==============================================================================
--- pypy/branch/new-platformcheck/pypy/rpython/tool/rffi_platform.py	(original)
+++ pypy/branch/new-platformcheck/pypy/rpython/tool/rffi_platform.py	Tue Sep  9 13:49:18 2008
@@ -4,7 +4,7 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem import rffi
 from pypy.rpython.lltypesystem import llmemory
-from pypy.tool.gcc_cache import build_executable_cache, try_compile_cache
+from pypy.tool.gcc_cache import build_executable_cache_read, try_compile_cache
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.translator.tool.cbuild import CompilationError
 from pypy.tool.udir import udir
@@ -83,6 +83,17 @@
     return _memory_alignment
 _memory_alignment = None
 
+def getendianness(eci):
+    if not hasattr(eci, 'endianness'):
+        class CConfig:
+            _compilation_info_ = eci
+            DATA = ConstantString('(unsigned long int)0xFF')
+        if configure(CConfig)['DATA'][0] == '\x00':
+            eci.endianness = 'BE'
+        else:
+            eci.endianness = 'LE'
+    return eci.endianness
+
 # ____________________________________________________________
 #
 # General interface
@@ -98,11 +109,10 @@
         try:
             return self.result[entry]
         except KeyError:
-            pass
-        name = self.entries[entry]
-        info = self.info[name]
-        self.result[entry] = entry.build_result(info, self)
-        return self.result[entry]
+            name = self.entries[entry]
+            info = self.info[name]
+            self.result[entry] = entry.build_result(info, self)
+            return self.result[entry]
 
     def get_result(self):
         return dict([(name, self.result[entry])
@@ -125,19 +135,11 @@
 
     def write_entry(self, key, entry):
         f = self.f
-        print >> f, 'void dump_section_%s(void) {' % (key,)
+        entry.key = key
         for line in entry.prepare_code():
-            if line and line[0] != '#':
-                line = '\t' + line
             print >> f, line
-        print >> f, '}'
         print >> f
 
-    def write_entry_main(self, key):
-        print >> self.f, '\tprintf("-+- %s\\n");' % (key,)
-        print >> self.f, '\tdump_section_%s();' % (key,)
-        print >> self.f, '\tprintf("---\\n");'
-
     def start_main(self):
         print >> self.f, 'int main(int argc, char *argv[]) {'
 
@@ -162,29 +164,31 @@
     """
     for attr in ['_includes_', '_libraries_', '_sources_', '_library_dirs_',
                  '_include_dirs_', '_header_']:
-        assert not hasattr(CConfig, attr), "Found legacy attribut %s on CConfig" % (attr,)
+        assert not hasattr(CConfig, attr), "Found legacy attribute %s on CConfig" % (attr,)
     entries = []
     for key in dir(CConfig):
         value = getattr(CConfig, key)
         if isinstance(value, CConfigEntry):
             entries.append((key, value))            
 
-    if entries:   # can be empty if there are only CConfigSingleEntries
+    if entries: # can be empty if there are only CConfigSingleEntries
+        infolist = []
         writer = _CWriter(CConfig)
         writer.write_header()
         for key, entry in entries:
             writer.write_entry(key, entry)
-
-        f = writer.f
         writer.start_main()
-        for key, entry in entries:
-            writer.write_entry_main(key)
         writer.close()
 
         eci = CConfig._compilation_info_
-        infolist = list(run_example_code(writer.path, eci))
+        info = run_example_code(writer.path, eci)
+        for key, entry in entries:
+            entry.eci = eci
+            if key in info:
+                infolist.append(info[key])
+            else:
+                infolist.append({})
         assert len(infolist) == len(entries)
-
         resultinfo = {}
         resultentries = {}
         for info, (key, entry) in zip(infolist, entries):
@@ -209,9 +213,49 @@
 
 # ____________________________________________________________
 
+def c_safe_string(string):
+    return string.replace('\\', '\\\\').replace('"', '\\"')
 
 class CConfigEntry(object):
     "Abstract base class."
+    def dump(self, name, expr):
+        beginpad = "__START_PLATCHECK_%s\0%s\0" % (
+            c_safe_string(self.key),
+            c_safe_string(name))
+        return '''
+        struct __attribute__((packed)) {
+            char begin_pad[%(sizeof_beginpad)i];
+            typeof(%(expr)s) contents;
+            char end_pad[];
+        } pypy_test_%(id)s = {
+            .begin_pad = "%(beginpad)s",
+            .contents = %(expr)s,
+            .end_pad = "__END_PLATCHECK__"
+        };
+        ''' % {'expr' : expr, 'beginpad' : beginpad.replace('\0', '\\0'),
+                'sizeof_beginpad' : len(beginpad),
+                'id' : filter(str.isalnum, self.key+'PLATCHECK'+name)}
+    def dumpbool(self, name, expr):
+        return self.dump(name, '((char)((%s)?1:0))' % (expr,))
+    def bool(self, data):
+        return data[0] != '\x00'
+    def dump_by_size(self, name, expr):
+        beginpad = "__START_PLATCHECK_%s\0%s\0" % (
+            c_safe_string(self.key),
+            c_safe_string(name))
+        return '''
+        struct {
+            char begin_pad[%(sizeof_beginpad)i];
+            char contents[%(expr)s];
+            char end_pad[];
+        } pypy_test_%(id)s = {
+            .begin_pad = "%(beginpad)s",
+            .contents = {0},
+            .end_pad = "__END_PLATCHECK__"
+        };
+        ''' % {'expr' : expr, 'beginpad' : beginpad.replace('\0', '\\0'),
+                'sizeof_beginpad' : len(beginpad),
+                'id' : filter(str.isalnum, self.key+'PLATCHECK'+name)}
 
 
 class Struct(CConfigEntry):
@@ -226,48 +270,37 @@
     def prepare_code(self):
         if self.ifdef is not None:
             yield '#ifdef %s' % (self.ifdef,)
-        yield 'typedef %s platcheck_t;' % (self.name,)
-        yield 'typedef struct {'
-        yield '    char c;'
-        yield '    platcheck_t s;'
-        yield '} platcheck2_t;'
-        yield ''
-        yield 'platcheck_t s;'
+        platcheck_t = 'struct { char c; %s s; }' % (self.name,)
         if self.ifdef is not None:
-            yield 'dump("defined", 1);'
-        yield 'dump("align", offsetof(platcheck2_t, s));'
-        yield 'dump("size",  sizeof(platcheck_t));'
+            yield self.dumpbool("defined", '1')
+        yield self.dump_by_size("align", 'offsetof(%s, s)' % (platcheck_t,))
+        yield self.dump_by_size("size",  'sizeof(%s)' % (self.name,))
         for fieldname, fieldtype in self.interesting_fields:
-            yield 'dump("fldofs %s", offsetof(platcheck_t, %s));'%(
-                fieldname, fieldname)
-            yield 'dump("fldsize %s",   sizeof(s.%s));' % (
-                fieldname, fieldname)
+            yield self.dump_by_size("fldofs " + fieldname, 'offsetof(%s, %s)' % (self.name, fieldname))
+            yield self.dump_by_size("fldsize " + fieldname, 'sizeof(((%s*)0)->%s)' % (
+                self.name, fieldname))
             if fieldtype in integer_class:
-                yield 's.%s = 0; s.%s = ~s.%s;' % (fieldname,
-                                                   fieldname,
-                                                   fieldname)
-                yield 'dump("fldunsigned %s", s.%s > 0);' % (fieldname,
-                                                             fieldname)
+                yield self.dumpbool("fldunsigned " + fieldname, '((typeof(((%s*)0)->%s))(-1)) > 0' % (self.name, fieldname))
         if self.ifdef is not None:
             yield '#else'
-            yield 'dump("defined", 0);'
+            yield self.dumpbool("defined", '0')
             yield '#endif'
 
     def build_result(self, info, config_result):
         if self.ifdef is not None:
-            if not info['defined']:
+            if not self.bool(info['defined']):
                 return None
-        layout = [None] * info['size']
+        layout = [None] * len(info['size'])
         for fieldname, fieldtype in self.interesting_fields:
             if isinstance(fieldtype, Struct):
-                offset = info['fldofs '  + fieldname]
-                size   = info['fldsize ' + fieldname]
+                offset = len(info['fldofs '  + fieldname])
+                size   = len(info['fldsize ' + fieldname])
                 c_fieldtype = config_result.get_entry_result(fieldtype)
                 layout_addfield(layout, offset, c_fieldtype, fieldname)
             else:
-                offset = info['fldofs '  + fieldname]
-                size   = info['fldsize ' + fieldname]
-                sign   = info.get('fldunsigned ' + fieldname, False)
+                offset = len(info['fldofs '  + fieldname])
+                size   = len(info['fldsize ' + fieldname])
+                sign   = self.bool(info.get('fldunsigned ' + fieldname, '\0'))
                 if (size, sign) != rffi.size_and_sign(fieldtype):
                     fieldtype = fixup_ctype(fieldtype, fieldname, (size, sign))
                 layout_addfield(layout, offset, fieldtype, fieldname)
@@ -294,8 +327,8 @@
             seen[cell] = True
 
         name = self.name
-        hints = {'align': info['align'],
-                 'size': info['size'],
+        hints = {'align': len(info['align']),
+                 'size': len(info['size']),
                  'fieldoffsets': tuple(fieldoffsets),
                  'padding': tuple(padfields)}
         if name.startswith('struct '):
@@ -313,34 +346,41 @@
         self.name = name
         self.ctype_hint = ctype_hint
         self.ifdef = ifdef
-        
+    
     def prepare_code(self):
         if self.ifdef is not None:
             yield '#ifdef %s' % (self.ifdef,)
-        yield 'typedef %s platcheck_t;' % (self.name,)
-        yield ''
-        yield 'platcheck_t x;'
         if self.ifdef is not None:
-            yield 'dump("defined", 1);'
-        yield 'dump("size",  sizeof(platcheck_t));'
+            yield self.dumpbool("defined", '1')
+        yield self.dump("size",  '((%s)0)' % (self.name,))
         if self.ctype_hint in integer_class:
-            yield 'x = 0; x = ~x;'
-            yield 'dump("unsigned", x > 0);'
+            yield self.dumpbool("unsigned", '((%s)(-1)) > 0' % (self.name,))
         if self.ifdef is not None:
             yield '#else'
-            yield 'dump("defined", 0);'
+            yield self.dumpbool("defined", '0')
             yield '#endif'
 
     def build_result(self, info, config_result):
-        if self.ifdef is not None and not info['defined']:
+        if self.ifdef is not None and not self.bool(info['defined']):
             return None
-        size = info['size']
-        sign = info.get('unsigned', False)
+        size = len(info['size'])
+        sign = self.bool(info.get('unsigned', '\0'))
         ctype = self.ctype_hint
         if (size, sign) != rffi.size_and_sign(ctype):
             ctype = fixup_ctype(ctype, self.name, (size, sign))
         return ctype
 
+def _load_int_le(data):
+    result = 0
+    for i in xrange(len(data)):
+        result |= ord(data[i]) << (i*8)
+    return result
+def _load_int_be(data):
+    result = 0
+    for byte in data:
+        result |= ord(byte)
+        result <<= 8
+    return result
 
 class ConstantInteger(CConfigEntry):
     """An entry in a CConfig class that stands for an externally
@@ -350,19 +390,38 @@
         self.name = name
 
     def prepare_code(self):
-        yield 'if ((%s) < 0) {' % (self.name,)
-        yield '    long long x = (long long)(%s);' % (self.name,)
-        yield '    printf("value: %lld\\n", x);'
-        yield '} else {'
-        yield '    unsigned long long x = (unsigned long long)(%s);' % (
-                        self.name,)
-        yield '    printf("value: %llu\\n", x);'
-        yield '}'
+        yield self.dump('value', self.name)
+        yield self.dump('negvalue', '-(%s)' % (self.name,))
+        yield self.dump('positive', '(%s) >= 0' % (self.name,))
+
+    def build_result(self, info, config_result):
+        if self.bool(info['positive']):
+            value = info['value']
+        else:
+            value = info['negvalue']
+        if getendianness(self.eci) is 'BE':
+            magnitude = _load_int_be(value)
+        else:
+            magnitude = _load_int_le(value)
+        if self.bool(info['positive']):
+            return magnitude
+        else:
+            return -magnitude
+
+class ConstantString(CConfigEntry):
+    """An entry in a CConfig class that stands for an externally
+    defined string constant.
+    """
+    def __init__(self, name):
+        self.name = name
+
+    def prepare_code(self):
+        yield self.dump('value', self.name)
 
     def build_result(self, info, config_result):
         return info['value']
 
-class DefinedConstantInteger(CConfigEntry):
+class DefinedConstantInteger(ConstantInteger):
     """An entry in a CConfig class that stands for an externally
     defined integer constant. If not #defined the value will be None.
     """
@@ -371,22 +430,14 @@
 
     def prepare_code(self):
         yield '#ifdef %s' % self.macro
-        yield 'dump("defined", 1);'
-        yield 'if ((%s) < 0) {' % (self.macro,)
-        yield '    long long x = (long long)(%s);' % (self.macro,)
-        yield '    printf("value: %lld\\n", x);'
-        yield '} else {'
-        yield '    unsigned long long x = (unsigned long long)(%s);' % (
-                        self.macro,)
-        yield '    printf("value: %llu\\n", x);'
-        yield '}'
-        yield '#else'
-        yield 'dump("defined", 0);'
+        yield self.dumpbool('defined', '1')
+        for line in ConstantInteger.prepare_code(self):
+            yield line
         yield '#endif'
 
     def build_result(self, info, config_result):
-        if info["defined"]:
-            return info['value']
+        if 'defined' in info:
+            return ConstantInteger.build_result(self, info, config_result)
         return None
 
 class DefinedConstantString(CConfigEntry):
@@ -397,25 +448,13 @@
         self.name = macro
 
     def prepare_code(self):
-        yield '#ifdef %s' % self.macro
-        yield 'int i;'
-        yield 'char *p = %s;' % self.macro
-        yield 'dump("defined", 1);'
-        yield 'for (i = 0; p[i] != 0; i++ ) {'
-        yield '  printf("value_%d: %d\\n", i, (int)(unsigned char)p[i]);'
-        yield '}'
-        yield '#else'
-        yield 'dump("defined", 0);'
+        yield '#ifdef %s' % (self.macro,)
+        yield self.dump('macro', self.macro)
         yield '#endif'
 
     def build_result(self, info, config_result):
-        if info["defined"]:
-            string = ''
-            d = 0
-            while info.has_key('value_%d' % d):
-                string += chr(info['value_%d' % d])
-                d += 1
-            return string
+        if "macro" in info:
+            return info["macro"]
         return None
 
 
@@ -428,13 +467,13 @@
 
     def prepare_code(self):
         yield '#ifdef %s' % (self.macro,)
-        yield 'dump("defined", 1);'
+        yield self.dumpbool("defined", '1')
         yield '#else'
-        yield 'dump("defined", 0);'
+        yield self.dumpbool("defined", '0')
         yield '#endif'
 
     def build_result(self, info, config_result):
-        return bool(info['defined'])
+        return self.bool(info['defined'])
 
 class CConfigSingleEntry(object):
     """ An abstract class of type which requires
@@ -465,10 +504,10 @@
         self.name = name
 
     def prepare_code(self):
-        yield 'dump("size",  sizeof(%s));' % self.name
+        yield self.dump_by_size("size",  'sizeof(%s)' % (self.name,))
 
     def build_result(self, info, config_result):
-        return info['size']
+        return len(info['size'])
 
 # ____________________________________________________________
 #
@@ -528,31 +567,33 @@
 
 
 C_HEADER = """
-#include <stdio.h>
 #include <stddef.h>   /* for offsetof() */
-
-void dump(char* key, int value) {
-    printf("%s: %d\\n", key, value);
-}
 """
 
 def run_example_code(filepath, eci):
     eci = eci.convert_sources_to_files(being_main=True)
     files = [filepath] + [py.path.local(f) for f in eci.separate_module_files]
-    output = build_executable_cache(files, eci)
-    section = None
-    for line in output.splitlines():
-        line = line.strip()
-        if line.startswith('-+- '):      # start of a new section
-            section = {}
-        elif line == '---':              # section end
-            assert section is not None
-            yield section
-            section = None
-        elif line:
-            assert section is not None
-            key, value = line.split(': ')
-            section[key] = int(value)
+    data = build_executable_cache_read(files, eci)
+    
+    end = 0
+    section = {}
+    while True:
+        start = data.find('__START_PLATCHECK_', end)
+        if start >= 0:
+            start += len('__START_PLATCHECK_')
+            keyend = data.find('\0', start)
+            key = data[start:keyend]
+            nameend = data.find('\0', keyend+1)
+            name = data[keyend+1:nameend]
+            start = nameend + 1
+            end = data.find('__END_PLATCHECK__', start)
+            if key in section:
+                section[key][name] = data[start:end]
+            else:
+                section[key] = {name : data[start:end]}
+        else:
+            break
+    return section
 
 # ____________________________________________________________
 

Modified: pypy/branch/new-platformcheck/pypy/tool/gcc_cache.py
==============================================================================
--- pypy/branch/new-platformcheck/pypy/tool/gcc_cache.py	(original)
+++ pypy/branch/new-platformcheck/pypy/tool/gcc_cache.py	Tue Sep  9 13:49:18 2008
@@ -25,6 +25,15 @@
         path.write(result)
         return result
 
+def build_executable_cache_read(c_files, eci):
+    path = cache_file_path(c_files, eci, 'build_executable_cache_read')
+    try:
+        return path.read()
+    except py.error.Error:
+        result = open(build_executable(c_files, eci), 'rb').read()
+        path.write(result)
+        return result
+
 def try_compile_cache(c_files, eci):
     path = cache_file_path(c_files, eci, 'try_compile_cache')
     try:



More information about the Pypy-commit mailing list