]> git.cworth.org Git - apitrace/blob - retrace.py
More D2D spec tweaks.
[apitrace] / retrace.py
1 ##########################################################################
2 #
3 # Copyright 2010 VMware, Inc.
4 # All Rights Reserved.
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 # THE SOFTWARE.
23 #
24 ##########################################################################/
25
26
27 """Generic retracing code generator."""
28
29
30 import sys
31
32 import specs.stdapi as stdapi
33 import specs.glapi as glapi
34
35
36 class ConstRemover(stdapi.Rebuilder):
37
38     def visit_const(self, const):
39         return const.type
40
41     def visit_opaque(self, opaque):
42         return opaque
43
44
45 def handle_entry(handle, value):
46     if handle.key is None:
47         return "__%s_map[%s]" % (handle.name, value)
48     else:
49         key_name, key_type = handle.key
50         return "__%s_map[%s][%s]" % (handle.name, key_name, value)
51
52
53 class ValueExtractor(stdapi.Visitor):
54
55     def visit_literal(self, literal, lvalue, rvalue):
56         #if literal.format in ('Bool', 'UInt'):
57         print '    %s = (%s).to%s();' % (lvalue, rvalue, literal.format)
58
59     def visit_const(self, const, lvalue, rvalue):
60         self.visit(const.type, lvalue, rvalue)
61
62     def visit_alias(self, alias, lvalue, rvalue):
63         self.visit(alias.type, lvalue, rvalue)
64     
65     def visit_enum(self, enum, lvalue, rvalue):
66         print '    %s = (%s).toSInt();' % (lvalue, rvalue)
67
68     def visit_bitmask(self, bitmask, lvalue, rvalue):
69         self.visit(bitmask.type, lvalue, rvalue)
70
71     def visit_array(self, array, lvalue, rvalue):
72         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
73         print '    if (__a%s) {' % (array.id)
74         length = '__a%s->values.size()' % array.id
75         print '        %s = new %s[%s];' % (lvalue, array.type, length)
76         index = '__j' + array.id
77         print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
78         try:
79             self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
80         finally:
81             print '        }'
82             print '    } else {'
83             print '        %s = NULL;' % lvalue
84             print '    }'
85     
86     def visit_pointer(self, pointer, lvalue, rvalue):
87         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
88         print '    if (__a%s) {' % (pointer.id)
89         print '        %s = new %s;' % (lvalue, pointer.type)
90         try:
91             self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
92         finally:
93             print '    } else {'
94             print '        %s = NULL;' % lvalue
95             print '    }'
96
97     def visit_handle(self, handle, lvalue, rvalue):
98         OpaqueValueExtractor().visit(handle.type, lvalue, rvalue);
99         new_lvalue = handle_entry(handle, lvalue)
100         print '    if (retrace::verbosity >= 2) {'
101         print '        std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
102         print '    }'
103         print '    %s = %s;' % (lvalue, new_lvalue)
104     
105     def visit_blob(self, blob, lvalue, rvalue):
106         print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
107     
108     def visit_string(self, string, lvalue, rvalue):
109         print '    %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
110
111
112 class OpaqueValueExtractor(ValueExtractor):
113     '''Value extractor that also understands opaque values.
114
115     Normally opaque values can't be retraced, unless they are being extracted
116     in the context of handles.'''
117
118     def visit_opaque(self, opaque, lvalue, rvalue):
119         print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, opaque, rvalue)
120
121
122 class ValueWrapper(stdapi.Visitor):
123
124     def visit_literal(self, literal, lvalue, rvalue):
125         pass
126
127     def visit_alias(self, alias, lvalue, rvalue):
128         self.visit(alias.type, lvalue, rvalue)
129     
130     def visit_enum(self, enum, lvalue, rvalue):
131         pass
132
133     def visit_bitmask(self, bitmask, lvalue, rvalue):
134         pass
135
136     def visit_array(self, array, lvalue, rvalue):
137         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
138         print '    if (__a%s) {' % (array.id)
139         length = '__a%s->values.size()' % array.id
140         index = '__j' + array.id
141         print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
142         try:
143             self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
144         finally:
145             print '        }'
146             print '    }'
147     
148     def visit_pointer(self, pointer, lvalue, rvalue):
149         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
150         print '    if (__a%s) {' % (pointer.id)
151         try:
152             self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
153         finally:
154             print '    }'
155     
156     def visit_handle(self, handle, lvalue, rvalue):
157         print '    %s __orig_result;' % handle.type
158         OpaqueValueExtractor().visit(handle.type, '__orig_result', rvalue);
159         if handle.range is None:
160             rvalue = "__orig_result"
161             entry = handle_entry(handle, rvalue) 
162             print "    %s = %s;" % (entry, lvalue)
163             print '    if (retrace::verbosity >= 2) {'
164             print '        std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
165             print '    }'
166         else:
167             i = '__h' + handle.id
168             lvalue = "%s + %s" % (lvalue, i)
169             rvalue = "__orig_result + %s" % (i,)
170             entry = handle_entry(handle, rvalue) 
171             print '    for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
172             print '        {entry} = {lvalue};'.format(**locals())
173             print '        if (retrace::verbosity >= 2) {'
174             print '            std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
175             print '        }'
176             print '    }'
177     
178     def visit_blob(self, blob, lvalue, rvalue):
179         pass
180     
181     def visit_string(self, string, lvalue, rvalue):
182         pass
183
184
185 class Retracer:
186
187     def retrace_function(self, function):
188         print 'static void retrace_%s(Trace::Call &call) {' % function.name
189         self.retrace_function_body(function)
190         print '}'
191         print
192
193     def retrace_function_body(self, function):
194         if not function.sideeffects:
195             print '    (void)call;'
196             return
197
198         success = True
199         for arg in function.args:
200             arg_type = ConstRemover().visit(arg.type)
201             #print '    // %s ->  %s' % (arg.type, arg_type)
202             print '    %s %s;' % (arg_type, arg.name)
203             rvalue = 'call.arg(%u)' % (arg.index,)
204             lvalue = arg.name
205             try:
206                 self.extract_arg(function, arg, arg_type, lvalue, rvalue)
207             except NotImplementedError:
208                 success = False
209                 print '    %s = 0; // FIXME' % arg.name
210         if not success:
211             print '    if (1) {'
212             self.fail_function(function)
213             print '    }'
214         self.call_function(function)
215         for arg in function.args:
216             if arg.output:
217                 arg_type = ConstRemover().visit(arg.type)
218                 rvalue = 'call.arg(%u)' % (arg.index,)
219                 lvalue = arg.name
220                 try:
221                     ValueWrapper().visit(arg_type, lvalue, rvalue)
222                 except NotImplementedError:
223                     print '    // XXX: %s' % arg.name
224         if function.type is not stdapi.Void:
225             rvalue = '*call.ret'
226             lvalue = '__result'
227             try:
228                 ValueWrapper().visit(function.type, lvalue, rvalue)
229             except NotImplementedError:
230                 success = False
231                 print '    // FIXME: result'
232         if not success:
233             if function.name[-1].islower():
234                 sys.stderr.write('warning: unsupported %s call\n' % function.name)
235
236     def fail_function(self, function):
237         print '    if (retrace::verbosity >= 0) {'
238         print '        retrace::unsupported(call);'
239         print '    }'
240         print '    return;'
241
242     def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
243         ValueExtractor().visit(arg_type, lvalue, rvalue)
244     
245     def extract_opaque_arg(self, function, arg, arg_type, lvalue, rvalue):
246         OpaqueValueExtractor().visit(arg_type, lvalue, rvalue)
247
248     def call_function(self, function):
249         arg_names = ", ".join([arg.name for arg in function.args])
250         if function.type is not stdapi.Void:
251             print '    %s __result;' % (function.type)
252             print '    __result = %s(%s);' % (function.name, arg_names)
253             print '    (void)__result;'
254         else:
255             print '    %s(%s);' % (function.name, arg_names)
256
257     def filter_function(self, function):
258         return True
259
260     table_name = 'retrace::callbacks'
261
262     def retrace_functions(self, functions):
263         functions = filter(self.filter_function, functions)
264
265         for function in functions:
266             self.retrace_function(function)
267
268         print 'const retrace::Entry %s[] = {' % self.table_name
269         for function in functions:
270             print '    {"%s", &retrace_%s},' % (function.name, function.name)
271         print '    {NULL, NULL}'
272         print '};'
273         print
274
275
276     def retrace_api(self, api):
277
278         print '#include "trace_parser.hpp"'
279         print '#include "retrace.hpp"'
280         print
281
282         types = api.all_types()
283         handles = [type for type in types if isinstance(type, stdapi.Handle)]
284         handle_names = set()
285         for handle in handles:
286             if handle.name not in handle_names:
287                 if handle.key is None:
288                     print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
289                 else:
290                     key_name, key_type = handle.key
291                     print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
292                 handle_names.add(handle.name)
293         print
294
295         self.retrace_functions(api.functions)
296