Author: Armin Rigo <[email protected]>
Branch: cffi-1.0
Changeset: r1993:06675c9b1ad6
Date: 2015-05-12 16:01 +0200
http://bitbucket.org/cffi/cffi/changeset/06675c9b1ad6/
Log: in-progress
diff --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
--- a/cffi/cffi_opcode.py
+++ b/cffi/cffi_opcode.py
@@ -1,4 +1,3 @@
-import struct
class CffiOp(object):
def __init__(self, op, arg):
@@ -14,12 +13,19 @@
def as_bytes(self):
assert self.op is not None
- return struct.pack(">i", (self.arg << 8) | self.op)
+ return format_four_bytes((self.arg << 8) | self.op)
def __str__(self):
classname = CLASS_NAME.get(self.op, self.op)
return '(%s %s)' % (classname, self.arg)
+def format_four_bytes(num):
+ return '\\x%02X\\x%02X\\x%02X\\x%02X' % (
+ (num >> 24) & 0xFF,
+ (num >> 16) & 0xFF,
+ (num >> 8) & 0xFF,
+ (num ) & 0xFF)
+
OP_PRIMITIVE = 1
OP_POINTER = 3
OP_ARRAY = 5
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -3,12 +3,40 @@
from .cffi_opcode import *
+class GlobalExpr:
+ def __init__(self, name, address, type_op, size=0, check_value=0):
+ self.name = name
+ self.address = address
+ self.type_op = type_op
+ self.size = size
+ self.check_value = check_value
+
+ def as_c_expr(self):
+ return ' { "%s", %s, %s, %s },' % (
+ self.name, self.address, self.type_op.as_c_expr(), self.size)
+
+ def as_python_expr(self):
+ return "b'%s%s',%d" % (self.type_op.as_bytes(), self.name,
+ self.check_value)
+
+class TypenameExpr:
+ def __init__(self, name, type_index):
+ self.name = name
+ self.type_index = type_index
+
+ def as_c_expr(self):
+ return ' { "%s", %d },' % (self.name, self.type_index)
+
+ def as_python_expr(self):
+ return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)
+
+
class Recompiler:
- def __init__(self, ffi, module_name):
- assert isinstance(module_name, bytes)
+ def __init__(self, ffi, module_name, target_is_python=False):
self.ffi = ffi
self.module_name = module_name
+ self.target_is_python = target_is_python
def collect_type_table(self):
self._typesdict = {}
@@ -66,6 +94,7 @@
# consistency check
for op in self.cffi_types:
assert isinstance(op, CffiOp)
+ self.cffi_types = tuple(self.cffi_types) # don't change any more
def _do_collect_type(self, tp):
if not isinstance(tp, model.BaseTypeByIdentity):
@@ -106,12 +135,48 @@
# ----------
+ ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"]
+
+ def collect_step_tables(self):
+ # collect the declarations for '_cffi_globals', '_cffi_typenames', etc.
+ self._lsts = {}
+ for step_name in self.ALL_STEPS:
+ self._lsts[step_name] = []
+ self._seen_struct_unions = set()
+ self._generate("ctx")
+ self._add_missing_struct_unions()
+ #
+ for step_name in self.ALL_STEPS:
+ lst = self._lsts[step_name]
+ lst.sort(key=lambda entry: entry.name)
+ self._lsts[step_name] = tuple(lst) # don't change any more
+ #
+ # check for a possible internal inconsistency: _cffi_struct_unions
+ # should have been generated with exactly self._struct_unions
+ lst = self._lsts["struct_union"]
+ for tp, i in self._struct_unions.items():
+ assert i < len(lst)
+ assert lst[i].startswith(' { "%s"' % tp.name)
+ assert len(lst) == len(self._struct_unions)
+ # same with enums
+ lst = self._lsts["enum"]
+ for tp, i in self._enums.items():
+ assert i < len(lst)
+ assert lst[i].startswith(' { "%s"' % tp.name)
+ assert len(lst) == len(self._enums)
+
+ # ----------
+
def _prnt(self, what=''):
self._f.write(what + '\n')
- def _gettypenum(self, type):
- # a KeyError here is a bug. please report it! :-)
- return self._typesdict[type]
+ def write_source_to_f(self, f, preamble):
+ if self.target_is_python:
+ assert preamble is None
+ self.write_py_source_to_f(f)
+ else:
+ assert preamble is not None
+ self.write_c_source_to_f(f)
def _rel_readlines(self, filename):
g = open(os.path.join(os.path.dirname(__file__), filename), 'r')
@@ -139,7 +204,6 @@
#
# the declaration of '_cffi_types'
prnt('static void *_cffi_types[] = {')
- self.cffi_types = tuple(self.cffi_types) # don't change any more
typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
for i, op in enumerate(self.cffi_types):
comment = ''
@@ -157,44 +221,21 @@
self._generate("decl")
#
# the declaration of '_cffi_globals' and '_cffi_typenames'
- ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"]
nums = {}
- self._lsts = {}
- for step_name in ALL_STEPS:
- self._lsts[step_name] = []
- self._seen_struct_unions = set()
- self._generate("ctx")
- self._add_missing_struct_unions()
- for step_name in ALL_STEPS:
+ for step_name in self.ALL_STEPS:
lst = self._lsts[step_name]
nums[step_name] = len(lst)
if nums[step_name] > 0:
- lst.sort() # sort by name, which is at the start of each line
prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
step_name, step_name))
if step_name == 'field':
- self._fix_final_field_list(lst)
- for line in lst:
- prnt(line)
- if all(line.startswith('#') for line in lst):
- prnt(' { 0 }')
+ XXXX
+ lst = list(self._fix_final_field_list(lst))
+ for entry in lst:
+ prnt(entry.as_c_expr())
prnt('};')
prnt()
#
- # check for a possible internal inconsistency: _cffi_struct_unions
- # should have been generated with exactly self._struct_unions
- lst = self._lsts["struct_union"]
- for tp, i in self._struct_unions.items():
- assert i < len(lst)
- assert lst[i].startswith(' { "%s"' % tp.name)
- assert len(lst) == len(self._struct_unions)
- # same with enums
- lst = self._lsts["enum"]
- for tp, i in self._enums.items():
- assert i < len(lst)
- assert lst[i].startswith(' { "%s"' % tp.name)
- assert len(lst) == len(self._enums)
- #
# the declaration of '_cffi_includes'
if self.ffi._included_ffis:
prnt('static const char * const _cffi_includes[] = {')
@@ -211,12 +252,12 @@
# the declaration of '_cffi_type_context'
prnt('static const struct _cffi_type_context_s _cffi_type_context = {')
prnt(' _cffi_types,')
- for step_name in ALL_STEPS:
+ for step_name in self.ALL_STEPS:
if nums[step_name] > 0:
prnt(' _cffi_%ss,' % step_name)
else:
prnt(' NULL, /* no %ss */' % step_name)
- for step_name in ALL_STEPS:
+ for step_name in self.ALL_STEPS:
if step_name != "field":
prnt(' %d, /* num_%ss */' % (nums[step_name], step_name))
if self.ffi._included_ffis:
@@ -266,12 +307,16 @@
self.ffi._recompiler_module_name = self.module_name
def _to_py(self, x):
+ if isinstance(x, str):
+ x = x.encode('ascii')
if isinstance(x, bytes):
- r = repr(x)
- if not r.startswith('b'):
- r = 'b' + r
- return r
- raise TypeError(type(x).__name__)
+ return "b'%s'" % (x,)
+ if isinstance(x, (list, tuple)):
+ rep = [self._to_py(item) for item in x]
+ if len(rep) == 1:
+ rep.append('')
+ return "(%s)" % (','.join(rep),)
+ return x.as_python_expr()
def write_py_source_to_f(self, f):
self._f = f
@@ -289,13 +334,20 @@
prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),))
typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
#
- #.......
+ for step_name in self.ALL_STEPS:
+ lst = self._lsts[step_name]
+ if len(lst) > 0:
+ prnt(' _%ss = %s,' % (step_name, self._to_py(lst)))
#
# the footer
prnt(')')
# ----------
+ def _gettypenum(self, type):
+ # a KeyError here is a bug. please report it! :-)
+ return self._typesdict[type]
+
def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
extraarg = ''
if isinstance(tp, model.PrimitiveType):
@@ -389,8 +441,7 @@
def _typedef_ctx(self, tp, name):
type_index = self._typesdict[tp]
- self._lsts["typename"].append(
- ' { "%s", %d },' % (name, type_index))
+ self._lsts["typename"].append(TypenameExpr(name, type_index))
def _generate_cpy_typedef_ctx(self, tp, name):
self._typedef_ctx(tp, name)
@@ -531,15 +582,17 @@
return
type_index = self._typesdict[tp.as_raw_function()]
numargs = len(tp.args)
- if numargs == 0:
- meth_kind = 'N' # 'METH_NOARGS'
+ if self.target_is_python:
+ meth_kind = OP_DLOPEN
+ elif numargs == 0:
+ meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS'
elif numargs == 1:
- meth_kind = 'O' # 'METH_O'
+ meth_kind = OP_CPYTHON_BLTN_O # 'METH_O'
else:
- meth_kind = 'V' # 'METH_VARARGS'
+ meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS'
self._lsts["global"].append(
- ' { "%s", _cffi_f_%s, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_%s, %d), 0
},'
- % (name, name, meth_kind, type_index))
+ GlobalExpr(name, '_cffi_f_%s' % name,
+ CffiOp(meth_kind, type_index)))
# ----------
# named structs or unions
@@ -685,12 +738,12 @@
def _fix_final_field_list(self, lst):
count = 0
- for i in range(len(lst)):
- struct_fields = lst[i]
+ for struct_fields in lst:
pname = struct_fields.split('\n')[0]
define_macro = '#define _cffi_FIELDS_FOR_%s %d' % (pname, count)
- lst[i] = define_macro + struct_fields[len(pname):]
- count += lst[i].count('\n { "')
+ result = define_macro + struct_fields[len(pname):]
+ count += result.count('\n { "')
+ yield result
def _generate_cpy_struct_collecttype(self, tp, name):
self._struct_collecttype(tp)
@@ -777,12 +830,12 @@
def _generate_cpy_constant_ctx(self, tp, name):
if isinstance(tp, model.PrimitiveType) and tp.is_integer_type():
- type_op = '_CFFI_OP(_CFFI_OP_CONSTANT_INT, -1)'
+ type_op = CffiOp(OP_CONSTANT_INT, -1)
else:
type_index = self._typesdict[tp]
- type_op = '_CFFI_OP(_CFFI_OP_CONSTANT, %d)' % type_index
+ type_op = CffiOp(OP_CONSTANT, type_index)
self._lsts["global"].append(
- ' { "%s", _cffi_const_%s, %s, 0 },' % (name, name, type_op))
+ GlobalExpr(name, '_cffi_const_%s' % name, type_op))
# ----------
# enums
@@ -796,11 +849,10 @@
def _enum_ctx(self, tp, cname):
type_index = self._typesdict[tp]
- type_op = '_CFFI_OP(_CFFI_OP_ENUM, -1)'
+ type_op = CffiOp(OP_ENUM, -1)
for enumerator in tp.enumerators:
self._lsts["global"].append(
- ' { "%s", _cffi_const_%s, %s, 0 },' %
- (enumerator, enumerator, type_op))
+ GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op))
#
if cname is not None and '$' not in cname:
size = "sizeof(%s)" % cname
@@ -831,9 +883,10 @@
self._generate_cpy_const(True, name, check_value=check_value)
def _generate_cpy_macro_ctx(self, tp, name):
+ type_op = CffiOp(OP_CONSTANT_INT, -1)
self._lsts["global"].append(
- ' { "%s", _cffi_const_%s,'
- ' _CFFI_OP(_CFFI_OP_CONSTANT_INT, -1), 0 },' % (name, name))
+ GlobalExpr(name, '_cffi_const_%s' % name, type_op,
+ check_value=tp))
# ----------
# global variables
@@ -853,13 +906,13 @@
def _generate_cpy_variable_ctx(self, tp, name):
tp = self._global_type(tp, name)
type_index = self._typesdict[tp]
+ type_op = CffiOp(OP_GLOBAL_VAR, type_index)
if tp.sizeof_enabled():
size = "sizeof(%s)" % (name,)
else:
- size = "0"
+ size = 0
self._lsts["global"].append(
- ' { "%s", &%s, _CFFI_OP(_CFFI_OP_GLOBAL_VAR, %d), %s },'
- % (name, name, type_index, size))
+ GlobalExpr(name, '&%s' % name, type_op, size))
# ----------
# emitting the opcodes for individual types
@@ -928,13 +981,12 @@
super(NativeIO, self).write(s)
def _make_c_or_py_source(ffi, module_name, preamble, target_file):
- recompiler = Recompiler(ffi, module_name)
+ recompiler = Recompiler(ffi, module_name,
+ target_is_python=(preamble is None))
recompiler.collect_type_table()
+ recompiler.collect_step_tables()
f = NativeIO()
- if preamble is not None:
- recompiler.write_c_source_to_f(f, preamble)
- else:
- recompiler.write_py_source_to_f(f)
+ recompiler.write_source_to_f(f, preamble)
output = f.getvalue()
try:
with open(target_file, 'r') as f1:
diff --git a/testing/cffi1/test_dlopen.py b/testing/cffi1/test_dlopen.py
--- a/testing/cffi1/test_dlopen.py
+++ b/testing/cffi1/test_dlopen.py
@@ -13,6 +13,7 @@
import _cffi_backend
ffi = _cffi_backend.FFI(b'test_simple',
- _types = b'\x00\x00\x01\r\x00\x00\x07\x01\x00\x00\x00\x0f',
+ _types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F',
+ _globals = (b'\xFF\xFF\xFF\x1FBB',42,b'\x00\x00\x00\x23close',0),
)
"""
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit