]> git.cworth.org Git - apitrace/blob - retrace.py
Implement context sharing.
[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 import stdapi
30 import glapi
31 from codegen import *
32
33
34 class ConstRemover(stdapi.Rebuilder):
35
36     def visit_const(self, const):
37         return const.type
38
39     def visit_opaque(self, opaque):
40         return opaque
41
42
43 def handle_entry(handle, value):
44     if handle.key is None:
45         return "__%s_map[%s]" % (handle.name, value)
46     else:
47         key_name, key_type = handle.key
48         return "__%s_map[%s][%s]" % (handle.name, key_name, value)
49
50
51 class ValueExtractor(stdapi.Visitor):
52
53     def visit_literal(self, literal, lvalue, rvalue):
54         #if literal.format in ('Bool', 'UInt'):
55         print '    %s = (%s).to%s();' % (lvalue, rvalue, literal.format)
56
57     def visit_const(self, const, lvalue, rvalue):
58         self.visit(const.type, lvalue, rvalue)
59
60     def visit_alias(self, alias, lvalue, rvalue):
61         self.visit(alias.type, lvalue, rvalue)
62     
63     def visit_enum(self, enum, lvalue, rvalue):
64         print '    %s = (%s).toSInt();' % (lvalue, rvalue)
65
66     def visit_bitmask(self, bitmask, lvalue, rvalue):
67         self.visit(bitmask.type, lvalue, rvalue)
68
69     def visit_array(self, array, lvalue, rvalue):
70         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
71         print '    if (__a%s) {' % (array.id)
72         length = '__a%s->values.size()' % array.id
73         print '        %s = new %s[%s];' % (lvalue, array.type, length)
74         index = '__j' + array.id
75         print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
76         try:
77             self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
78         finally:
79             print '        }'
80             print '    } else {'
81             print '        %s = NULL;' % lvalue
82             print '    }'
83     
84     def visit_pointer(self, pointer, lvalue, rvalue):
85         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
86         print '    if (__a%s) {' % (pointer.id)
87         print '        %s = new %s;' % (lvalue, pointer.type)
88         try:
89             self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
90         finally:
91             print '    } else {'
92             print '        %s = NULL;' % lvalue
93             print '    }'
94
95     def visit_handle(self, handle, lvalue, rvalue):
96         OpaqueValueExtractor().visit(handle.type, lvalue, rvalue);
97         new_lvalue = handle_entry(handle, lvalue)
98         print '    if (retrace::verbosity >= 2)'
99         print '        std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
100         print '    %s = %s;' % (lvalue, new_lvalue)
101     
102     def visit_blob(self, blob, lvalue, rvalue):
103         print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
104     
105     def visit_string(self, string, lvalue, rvalue):
106         print '    %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
107
108
109 class OpaqueValueExtractor(ValueExtractor):
110     '''Value extractor that also understands opaque values.
111
112     Normally opaque values can't be retraced, unless they are being extracted
113     in the context of handles.'''
114
115     def visit_opaque(self, opaque, lvalue, rvalue):
116         print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, opaque, rvalue)
117
118
119 class ValueWrapper(stdapi.Visitor):
120
121     def visit_literal(self, literal, lvalue, rvalue):
122         pass
123
124     def visit_alias(self, alias, lvalue, rvalue):
125         self.visit(alias.type, lvalue, rvalue)
126     
127     def visit_enum(self, enum, lvalue, rvalue):
128         pass
129
130     def visit_bitmask(self, bitmask, lvalue, rvalue):
131         pass
132
133     def visit_array(self, array, lvalue, rvalue):
134         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
135         print '    if (__a%s) {' % (array.id)
136         length = '__a%s->values.size()' % array.id
137         index = '__j' + array.id
138         print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
139         try:
140             self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
141         finally:
142             print '        }'
143             print '    }'
144     
145     def visit_pointer(self, pointer, lvalue, rvalue):
146         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
147         print '    if (__a%s) {' % (pointer.id)
148         try:
149             self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
150         finally:
151             print '    }'
152     
153     def visit_handle(self, handle, lvalue, rvalue):
154         print '    %s __orig_result;' % handle.type
155         OpaqueValueExtractor().visit(handle.type, '__orig_result', rvalue);
156         if handle.range is None:
157             rvalue = "__orig_result"
158             entry = handle_entry(handle, rvalue) 
159             print "    %s = %s;" % (entry, lvalue)
160             print '    if (retrace::verbosity >= 2)'
161             print '        std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
162         else:
163             i = '__h' + handle.id
164             lvalue = "%s + %s" % (lvalue, i)
165             rvalue = "__orig_result + %s" % (i,)
166             entry = handle_entry(handle, rvalue) 
167             print '    for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
168             print '        {entry} = {lvalue};'.format(**locals())
169             print '        if (retrace::verbosity >= 2)'
170             print '            std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
171             print '    }'
172     
173     def visit_blob(self, blob, lvalue, rvalue):
174         pass
175     
176     def visit_string(self, string, lvalue, rvalue):
177         pass
178
179
180 class Retracer:
181
182     def retrace_function(self, function):
183         print 'static void retrace_%s(Trace::Call &call) {' % function.name
184         self.retrace_function_body(function)
185         print '}'
186         print
187
188     def retrace_function_body(self, function):
189         success = True
190         for arg in function.args:
191             arg_type = ConstRemover().visit(arg.type)
192             #print '    // %s ->  %s' % (arg.type, arg_type)
193             print '    %s %s;' % (arg_type, arg.name)
194             rvalue = 'call.arg(%u)' % (arg.index,)
195             lvalue = arg.name
196             try:
197                 self.extract_arg(function, arg, arg_type, lvalue, rvalue)
198             except NotImplementedError:
199                 success = False
200                 print '    %s = 0; // FIXME' % arg.name
201         if not success:
202             self.fail_function(function)
203         self.call_function(function)
204         for arg in function.args:
205             if arg.output:
206                 arg_type = ConstRemover().visit(arg.type)
207                 rvalue = 'call.arg(%u)' % (arg.index,)
208                 lvalue = arg.name
209                 try:
210                     ValueWrapper().visit(arg_type, lvalue, rvalue)
211                 except NotImplementedError:
212                     print '   // FIXME: %s' % arg.name
213         if function.type is not stdapi.Void:
214             rvalue = '*call.ret'
215             lvalue = '__result'
216             try:
217                 ValueWrapper().visit(function.type, lvalue, rvalue)
218             except NotImplementedError:
219                 print '   // FIXME: result'
220
221     def fail_function(self, function):
222         print '    if (retrace::verbosity >= 0)'
223         print '        std::cerr << "warning: unsupported call %s\\n";' % function.name
224         print '    return;'
225
226     def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
227         ValueExtractor().visit(arg_type, lvalue, rvalue)
228
229     def call_function(self, function):
230         arg_names = ", ".join([arg.name for arg in function.args])
231         if function.type is not stdapi.Void:
232             print '    %s __result;' % (function.type)
233             print '    __result = %s(%s);' % (function.name, arg_names)
234         else:
235             print '    %s(%s);' % (function.name, arg_names)
236
237     def filter_function(self, function):
238         return True
239
240     def retrace_functions(self, functions):
241         functions = filter(self.filter_function, functions)
242
243         for function in functions:
244             if function.sideeffects:
245                 self.retrace_function(function)
246
247         print 'void retrace::retrace_call(Trace::Call &call) {'
248         print '    const char *name = call.name().c_str();'
249         print
250
251         func_dict = dict([(function.name, function) for function in functions])
252
253         def handle_case(function_name):
254             function = func_dict[function_name]
255             if function.sideeffects:
256                 print '        retrace_%s(call);' % function.name
257             print '        return;'
258     
259         string_switch('name', func_dict.keys(), handle_case)
260
261         print '    retrace_unknown(call);'
262         print '}'
263         print
264
265
266     def retrace_api(self, api):
267
268         print '#include "trace_parser.hpp"'
269         print '#include "retrace.hpp"'
270         print
271
272         types = api.all_types()
273         handles = [type for type in types if isinstance(type, stdapi.Handle)]
274         handle_names = set()
275         for handle in handles:
276             if handle.name not in handle_names:
277                 if handle.key is None:
278                     print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
279                 else:
280                     key_name, key_type = handle.key
281                     print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
282                 handle_names.add(handle.name)
283         print
284
285         self.retrace_functions(api.functions)
286