blob: 4c3d5530b683f3464efde8a00ac79dc40ee3a5ae [file] [log] [blame]
José Fonsecae0e61402010-11-25 15:03:23 +00001##########################################################################
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
José Fonseca4a826ed2010-11-30 16:58:22 +000027"""Generic retracing code generator."""
28
José Fonseca0a37edf2011-10-09 09:45:22 +010029
José Fonseca9d27a542012-04-14 17:22:57 +010030# Adjust path
31import os.path
José Fonseca0a37edf2011-10-09 09:45:22 +010032import sys
José Fonseca9d27a542012-04-14 17:22:57 +010033sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
34
José Fonseca0a37edf2011-10-09 09:45:22 +010035
José Fonsecabd86a222011-09-27 09:21:38 +010036import specs.stdapi as stdapi
José Fonsecae0e61402010-11-25 15:03:23 +000037
38
José Fonseca2672a7d2012-04-14 15:17:12 +010039class UnsupportedType(Exception):
40 pass
41
42
Cass Everitt3b595cb2013-06-19 19:30:32 -050043def lookupHandle(handle, value, lval=False):
José Fonseca8a844ae2010-12-06 18:50:52 +000044 if handle.key is None:
José Fonseca632a78d2012-04-19 07:18:59 +010045 return "_%s_map[%s]" % (handle.name, value)
José Fonseca8a844ae2010-12-06 18:50:52 +000046 else:
47 key_name, key_type = handle.key
Cass Everitt3b595cb2013-06-19 19:30:32 -050048 if handle.name == "location" and lval == False:
49 return "_location_map[%s].lookupUniformLocation(%s)" % (key_name, value)
50 else:
51 return "_%s_map[%s][%s]" % (handle.name, key_name, value)
José Fonseca8a844ae2010-12-06 18:50:52 +000052
53
José Fonseca4a2c57b2012-04-07 10:50:53 +010054class ValueAllocator(stdapi.Visitor):
55
56 def visitLiteral(self, literal, lvalue, rvalue):
57 pass
58
59 def visitConst(self, const, lvalue, rvalue):
60 self.visit(const.type, lvalue, rvalue)
61
62 def visitAlias(self, alias, lvalue, rvalue):
63 self.visit(alias.type, lvalue, rvalue)
64
65 def visitEnum(self, enum, lvalue, rvalue):
66 pass
67
68 def visitBitmask(self, bitmask, lvalue, rvalue):
69 pass
70
71 def visitArray(self, array, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +010072 print ' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, array.type, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +010073
74 def visitPointer(self, pointer, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +010075 print ' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, pointer.type, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +010076
77 def visitIntPointer(self, pointer, lvalue, rvalue):
78 pass
79
80 def visitObjPointer(self, pointer, lvalue, rvalue):
81 pass
82
83 def visitLinearPointer(self, pointer, lvalue, rvalue):
84 pass
85
86 def visitReference(self, reference, lvalue, rvalue):
87 self.visit(reference.type, lvalue, rvalue);
88
89 def visitHandle(self, handle, lvalue, rvalue):
90 pass
91
92 def visitBlob(self, blob, lvalue, rvalue):
93 pass
94
95 def visitString(self, string, lvalue, rvalue):
96 pass
97
98 def visitStruct(self, struct, lvalue, rvalue):
99 pass
100
101 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecadbf714b2012-11-20 17:03:43 +0000102 assert polymorphic.defaultType is not None
José Fonseca4a2c57b2012-04-07 10:50:53 +0100103 self.visit(polymorphic.defaultType, lvalue, rvalue)
104
José Fonseca2672a7d2012-04-14 15:17:12 +0100105 def visitOpaque(self, opaque, lvalue, rvalue):
106 pass
107
José Fonseca4a2c57b2012-04-07 10:50:53 +0100108
José Fonsecadbf714b2012-11-20 17:03:43 +0000109class ValueDeserializer(stdapi.Visitor, stdapi.ExpanderMixin):
José Fonsecae0e61402010-11-25 15:03:23 +0000110
José Fonseca54f304a2012-01-14 19:33:08 +0000111 def visitLiteral(self, literal, lvalue, rvalue):
José Fonseca2f2ea482011-10-15 15:10:06 +0100112 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
José Fonsecae0e61402010-11-25 15:03:23 +0000113
José Fonseca54f304a2012-01-14 19:33:08 +0000114 def visitConst(self, const, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000115 self.visit(const.type, lvalue, rvalue)
116
José Fonseca54f304a2012-01-14 19:33:08 +0000117 def visitAlias(self, alias, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000118 self.visit(alias.type, lvalue, rvalue)
119
José Fonseca54f304a2012-01-14 19:33:08 +0000120 def visitEnum(self, enum, lvalue, rvalue):
José Fonseca96ce6002012-04-02 08:10:48 +0200121 print ' %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000122
José Fonseca54f304a2012-01-14 19:33:08 +0000123 def visitBitmask(self, bitmask, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000124 self.visit(bitmask.type, lvalue, rvalue)
125
José Fonseca54f304a2012-01-14 19:33:08 +0000126 def visitArray(self, array, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100127 tmp = '_a_' + array.tag + '_' + str(self.seq)
José Fonseca68013c92012-04-05 19:58:38 +0100128 self.seq += 1
129
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100130 print ' const trace::Array *%s = (%s).toArray();' % (tmp, rvalue)
131 print ' if (%s) {' % (tmp,)
Jose Fonseca41efd942015-06-10 22:54:18 +0100132
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100133 length = '%s->values.size()' % (tmp,)
Jose Fonseca41efd942015-06-10 22:54:18 +0100134 if self.insideStruct:
135 if isinstance(array.length, int):
136 # Member is an array
137 print r' static_assert( std::is_array< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be an array" );' % lvalue
138 print r' static_assert( std::extent< std::remove_reference< decltype( %s ) >::type >::value == %s, "array size mismatch" );' % (lvalue, array.length)
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100139 print r' assert( %s );' % (tmp,)
140 print r' assert( %s->size() == %s );' % (tmp, array.length)
141 length = str(array.length)
Jose Fonseca41efd942015-06-10 22:54:18 +0100142 else:
143 # Member is a pointer to an array, hence must be allocated
144 print r' static_assert( std::is_pointer< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be a pointer" );' % lvalue
145 print r' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, array.type, rvalue)
146
José Fonseca632a78d2012-04-19 07:18:59 +0100147 index = '_j' + array.tag
José Fonsecadbaae492011-04-21 09:28:10 +0100148 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000149 try:
José Fonseca68013c92012-04-05 19:58:38 +0100150 self.visit(array.type, '%s[%s]' % (lvalue, index), '*%s->values[%s]' % (tmp, index))
José Fonsecae0e61402010-11-25 15:03:23 +0000151 finally:
152 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000153 print ' }'
154
José Fonseca54f304a2012-01-14 19:33:08 +0000155 def visitPointer(self, pointer, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100156 tmp = '_a_' + pointer.tag + '_' + str(self.seq)
José Fonseca68013c92012-04-05 19:58:38 +0100157 self.seq += 1
158
José Fonseca4a2c57b2012-04-07 10:50:53 +0100159 print ' if (%s) {' % (lvalue,)
Nigel Stewartabaef292013-07-10 09:01:01 -0500160 print ' const trace::Array *%s = (%s).toArray();' % (tmp, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000161 try:
José Fonseca68013c92012-04-05 19:58:38 +0100162 self.visit(pointer.type, '%s[0]' % (lvalue,), '*%s->values[0]' % (tmp,))
José Fonsecae0e61402010-11-25 15:03:23 +0000163 finally:
José Fonsecae0e61402010-11-25 15:03:23 +0000164 print ' }'
165
José Fonseca59ee88e2012-01-15 14:24:10 +0000166 def visitIntPointer(self, pointer, lvalue, rvalue):
167 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
168
José Fonsecafbcf6832012-04-05 07:10:30 +0100169 def visitObjPointer(self, pointer, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +0100170 print ' %s = retrace::asObjPointer<%s>(call, %s);' % (lvalue, pointer.type, rvalue)
José Fonsecafbcf6832012-04-05 07:10:30 +0100171
José Fonseca59ee88e2012-01-15 14:24:10 +0000172 def visitLinearPointer(self, pointer, lvalue, rvalue):
173 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
174
José Fonsecab89c5932012-04-01 22:47:11 +0200175 def visitReference(self, reference, lvalue, rvalue):
176 self.visit(reference.type, lvalue, rvalue);
177
José Fonseca54f304a2012-01-14 19:33:08 +0000178 def visitHandle(self, handle, lvalue, rvalue):
José Fonseca59ee88e2012-01-15 14:24:10 +0000179 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
180 self.visit(handle.type, lvalue, rvalue);
José Fonseca54f304a2012-01-14 19:33:08 +0000181 new_lvalue = lookupHandle(handle, lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100182 print ' if (retrace::verbosity >= 2) {'
José Fonsecaa10af892011-04-11 09:10:55 +0100183 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100184 print ' }'
Carl Worth37007772012-08-28 11:45:52 -0700185 if (new_lvalue.startswith('_program_map') or new_lvalue.startswith('_shader_map')):
186 print 'if (glretrace::supportsARBShaderObjects) {'
187 print ' %s = _handleARB_map[%s];' % (lvalue, lvalue)
188 print '} else {'
189 print ' %s = %s;' % (lvalue, new_lvalue)
190 print '}'
191 else:
192 print ' %s = %s;' % (lvalue, new_lvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000193
José Fonseca54f304a2012-01-14 19:33:08 +0000194 def visitBlob(self, blob, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100195 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000196
José Fonseca54f304a2012-01-14 19:33:08 +0000197 def visitString(self, string, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100198 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000199
José Fonsecaa65a23a2012-04-02 08:10:06 +0200200 seq = 0
201
Jose Fonseca41efd942015-06-10 22:54:18 +0100202 insideStruct = 0
203
José Fonsecaa65a23a2012-04-02 08:10:06 +0200204 def visitStruct(self, struct, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100205 tmp = '_s_' + struct.tag + '_' + str(self.seq)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200206 self.seq += 1
207
Jose Fonseca41efd942015-06-10 22:54:18 +0100208 self.insideStruct += 1
209
Nigel Stewartabaef292013-07-10 09:01:01 -0500210 print ' const trace::Struct *%s = (%s).toStruct();' % (tmp, rvalue)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200211 print ' assert(%s);' % (tmp)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200212 for i in range(len(struct.members)):
José Fonsecadbf714b2012-11-20 17:03:43 +0000213 member = struct.members[i]
214 self.visitMember(member, lvalue, '*%s->members[%s]' % (tmp, i))
José Fonsecaa65a23a2012-04-02 08:10:06 +0200215
Jose Fonseca41efd942015-06-10 22:54:18 +0100216 self.insideStruct -= 1
217
José Fonseca4a2c57b2012-04-07 10:50:53 +0100218 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecaeb216e62012-11-20 11:08:08 +0000219 if polymorphic.defaultType is None:
José Fonsecadbf714b2012-11-20 17:03:43 +0000220 switchExpr = self.expand(polymorphic.switchExpr)
221 print r' switch (%s) {' % switchExpr
222 for cases, type in polymorphic.iterSwitch():
223 for case in cases:
224 print r' %s:' % case
225 caseLvalue = lvalue
226 if type.expr is not None:
227 caseLvalue = 'static_cast<%s>(%s)' % (type, caseLvalue)
228 print r' {'
229 try:
230 self.visit(type, caseLvalue, rvalue)
231 finally:
232 print r' }'
233 print r' break;'
234 if polymorphic.defaultType is None:
235 print r' default:'
236 print r' retrace::warning(call) << "unexpected polymorphic case" << %s << "\n";' % (switchExpr,)
237 print r' break;'
238 print r' }'
239 else:
240 self.visit(polymorphic.defaultType, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100241
242 def visitOpaque(self, opaque, lvalue, rvalue):
243 raise UnsupportedType
José Fonseca4a2c57b2012-04-07 10:50:53 +0100244
José Fonsecae0e61402010-11-25 15:03:23 +0000245
José Fonseca54f304a2012-01-14 19:33:08 +0000246class OpaqueValueDeserializer(ValueDeserializer):
José Fonsecaa10af892011-04-11 09:10:55 +0100247 '''Value extractor that also understands opaque values.
248
249 Normally opaque values can't be retraced, unless they are being extracted
250 in the context of handles.'''
251
José Fonseca54f304a2012-01-14 19:33:08 +0000252 def visitOpaque(self, opaque, lvalue, rvalue):
José Fonseca46a48392011-10-14 11:34:27 +0100253 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
José Fonsecaa10af892011-04-11 09:10:55 +0100254
José Fonsecae0e61402010-11-25 15:03:23 +0000255
José Fonsecadbf714b2012-11-20 17:03:43 +0000256class SwizzledValueRegistrator(stdapi.Visitor, stdapi.ExpanderMixin):
José Fonseca54f304a2012-01-14 19:33:08 +0000257 '''Type visitor which will register (un)swizzled value pairs, to later be
258 swizzled.'''
José Fonsecae0e61402010-11-25 15:03:23 +0000259
José Fonseca54f304a2012-01-14 19:33:08 +0000260 def visitLiteral(self, literal, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000261 pass
262
José Fonseca54f304a2012-01-14 19:33:08 +0000263 def visitAlias(self, alias, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000264 self.visit(alias.type, lvalue, rvalue)
265
José Fonseca54f304a2012-01-14 19:33:08 +0000266 def visitEnum(self, enum, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000267 pass
268
José Fonseca54f304a2012-01-14 19:33:08 +0000269 def visitBitmask(self, bitmask, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000270 pass
271
José Fonseca54f304a2012-01-14 19:33:08 +0000272 def visitArray(self, array, lvalue, rvalue):
Nigel Stewartabaef292013-07-10 09:01:01 -0500273 print ' const trace::Array *_a%s = (%s).toArray();' % (array.tag, rvalue)
José Fonseca632a78d2012-04-19 07:18:59 +0100274 print ' if (_a%s) {' % (array.tag)
275 length = '_a%s->values.size()' % array.tag
276 index = '_j' + array.tag
José Fonsecadbaae492011-04-21 09:28:10 +0100277 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000278 try:
José Fonseca632a78d2012-04-19 07:18:59 +0100279 self.visit(array.type, '%s[%s]' % (lvalue, index), '*_a%s->values[%s]' % (array.tag, index))
José Fonsecae0e61402010-11-25 15:03:23 +0000280 finally:
281 print ' }'
282 print ' }'
283
José Fonseca54f304a2012-01-14 19:33:08 +0000284 def visitPointer(self, pointer, lvalue, rvalue):
Nigel Stewartabaef292013-07-10 09:01:01 -0500285 print ' const trace::Array *_a%s = (%s).toArray();' % (pointer.tag, rvalue)
José Fonseca632a78d2012-04-19 07:18:59 +0100286 print ' if (_a%s) {' % (pointer.tag)
José Fonsecae0e61402010-11-25 15:03:23 +0000287 try:
José Fonseca632a78d2012-04-19 07:18:59 +0100288 self.visit(pointer.type, '%s[0]' % (lvalue,), '*_a%s->values[0]' % (pointer.tag,))
José Fonsecae0e61402010-11-25 15:03:23 +0000289 finally:
290 print ' }'
291
José Fonseca59ee88e2012-01-15 14:24:10 +0000292 def visitIntPointer(self, pointer, lvalue, rvalue):
293 pass
294
José Fonsecafbcf6832012-04-05 07:10:30 +0100295 def visitObjPointer(self, pointer, lvalue, rvalue):
José Fonsecad8068b32012-11-13 21:37:42 +0000296 print r' retrace::addObj(call, %s, %s);' % (rvalue, lvalue)
José Fonsecafbcf6832012-04-05 07:10:30 +0100297
José Fonseca59ee88e2012-01-15 14:24:10 +0000298 def visitLinearPointer(self, pointer, lvalue, rvalue):
299 assert pointer.size is not None
300 if pointer.size is not None:
Jose Fonsecae05718d2015-05-20 10:22:56 +0100301 print r' retrace::addRegion(call, (%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
José Fonseca59ee88e2012-01-15 14:24:10 +0000302
José Fonsecab89c5932012-04-01 22:47:11 +0200303 def visitReference(self, reference, lvalue, rvalue):
304 pass
305
José Fonseca54f304a2012-01-14 19:33:08 +0000306 def visitHandle(self, handle, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100307 print ' %s _origResult;' % handle.type
308 OpaqueValueDeserializer().visit(handle.type, '_origResult', rvalue);
José Fonsecad922e1d2010-11-25 17:14:02 +0000309 if handle.range is None:
José Fonseca632a78d2012-04-19 07:18:59 +0100310 rvalue = "_origResult"
Cass Everitt3b595cb2013-06-19 19:30:32 -0500311 entry = lookupHandle(handle, rvalue, True)
Carl Worth37007772012-08-28 11:45:52 -0700312 if (entry.startswith('_program_map') or entry.startswith('_shader_map')):
313 print 'if (glretrace::supportsARBShaderObjects) {'
314 print ' _handleARB_map[%s] = %s;' % (rvalue, lvalue)
315 print '} else {'
316 print ' %s = %s;' % (entry, lvalue)
317 print '}'
318 else:
319 print " %s = %s;" % (entry, lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100320 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000321 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100322 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000323 else:
José Fonseca632a78d2012-04-19 07:18:59 +0100324 i = '_h' + handle.tag
José Fonseca8a844ae2010-12-06 18:50:52 +0000325 lvalue = "%s + %s" % (lvalue, i)
José Fonseca632a78d2012-04-19 07:18:59 +0100326 rvalue = "_origResult + %s" % (i,)
José Fonseca54f304a2012-01-14 19:33:08 +0000327 entry = lookupHandle(handle, rvalue)
José Fonsecadbaae492011-04-21 09:28:10 +0100328 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
José Fonseca8a844ae2010-12-06 18:50:52 +0000329 print ' {entry} = {lvalue};'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100330 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000331 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100332 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000333 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000334
José Fonseca54f304a2012-01-14 19:33:08 +0000335 def visitBlob(self, blob, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000336 pass
337
José Fonseca54f304a2012-01-14 19:33:08 +0000338 def visitString(self, string, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000339 pass
340
José Fonseca4a2c57b2012-04-07 10:50:53 +0100341 seq = 0
342
343 def visitStruct(self, struct, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100344 tmp = '_s_' + struct.tag + '_' + str(self.seq)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100345 self.seq += 1
346
Nigel Stewartabaef292013-07-10 09:01:01 -0500347 print ' const trace::Struct *%s = (%s).toStruct();' % (tmp, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100348 print ' assert(%s);' % (tmp,)
349 print ' (void)%s;' % (tmp,)
350 for i in range(len(struct.members)):
José Fonsecadbf714b2012-11-20 17:03:43 +0000351 member = struct.members[i]
352 self.visitMember(member, lvalue, '*%s->members[%s]' % (tmp, i))
José Fonseca4a2c57b2012-04-07 10:50:53 +0100353
354 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecadbf714b2012-11-20 17:03:43 +0000355 assert polymorphic.defaultType is not None
José Fonseca4a2c57b2012-04-07 10:50:53 +0100356 self.visit(polymorphic.defaultType, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100357
358 def visitOpaque(self, opaque, lvalue, rvalue):
359 pass
José Fonseca4a2c57b2012-04-07 10:50:53 +0100360
José Fonsecae0e61402010-11-25 15:03:23 +0000361
José Fonsecae0e61402010-11-25 15:03:23 +0000362class Retracer:
363
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000364 def makeFunctionId(self, function):
365 name = function.name
366 if function.overloaded:
367 # TODO: Use a sequence number
368 name += '__%08x' % (hash(function) & 0xffffffff)
369 return name
370
José Fonseca54f304a2012-01-14 19:33:08 +0000371 def retraceFunction(self, function):
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000372 print 'static void retrace_%s(trace::Call &call) {' % self.makeFunctionId(function)
José Fonseca54f304a2012-01-14 19:33:08 +0000373 self.retraceFunctionBody(function)
José Fonseca62212972011-03-23 13:22:55 +0000374 print '}'
375 print
376
José Fonseca8e3c2c02012-01-23 00:30:35 +0000377 def retraceInterfaceMethod(self, interface, method):
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000378 print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, self.makeFunctionId(method))
José Fonseca8e3c2c02012-01-23 00:30:35 +0000379 self.retraceInterfaceMethodBody(interface, method)
380 print '}'
381 print
382
José Fonseca54f304a2012-01-14 19:33:08 +0000383 def retraceFunctionBody(self, function):
José Fonsecadd27f9f2012-04-13 13:57:23 +0100384 assert function.sideeffects
José Fonseca4d7f1fe2011-05-09 20:54:31 +0100385
José Fonseca7c7c9062012-04-27 13:02:08 +0100386 if function.type is not stdapi.Void:
387 self.checkOrigResult(function)
388
José Fonseca8e3c2c02012-01-23 00:30:35 +0000389 self.deserializeArgs(function)
390
José Fonseca3db3b2f2012-05-11 14:55:50 +0100391 self.declareRet(function)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000392 self.invokeFunction(function)
393
394 self.swizzleValues(function)
395
396 def retraceInterfaceMethodBody(self, interface, method):
José Fonseca1da480d2012-04-13 17:36:19 +0100397 assert method.sideeffects
José Fonseca8e3c2c02012-01-23 00:30:35 +0000398
José Fonseca7c7c9062012-04-27 13:02:08 +0100399 if method.type is not stdapi.Void:
400 self.checkOrigResult(method)
401
José Fonseca8e3c2c02012-01-23 00:30:35 +0000402 self.deserializeThisPointer(interface)
403
404 self.deserializeArgs(method)
405
José Fonseca3db3b2f2012-05-11 14:55:50 +0100406 self.declareRet(method)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000407 self.invokeInterfaceMethod(interface, method)
408
409 self.swizzleValues(method)
410
José Fonseca7c7c9062012-04-27 13:02:08 +0100411 def checkOrigResult(self, function):
412 '''Hook for checking the original result, to prevent succeeding now
413 where the original did not, which would cause diversion and potentially
414 unpredictable results.'''
415
416 assert function.type is not stdapi.Void
417
418 if str(function.type) == 'HRESULT':
419 print r' if (call.ret && FAILED(call.ret->toSInt())) {'
420 print r' return;'
421 print r' }'
422
José Fonseca8e3c2c02012-01-23 00:30:35 +0000423 def deserializeThisPointer(self, interface):
José Fonsecadc279372012-04-05 19:58:20 +0100424 print r' %s *_this;' % (interface.name,)
José Fonseca915d4da2014-09-05 11:55:17 +0100425 print r' _this = retrace::asObjPointer<%s>(call, call.arg(0));' % (interface.name,)
José Fonsecadc279372012-04-05 19:58:20 +0100426 print r' if (!_this) {'
José Fonsecadc279372012-04-05 19:58:20 +0100427 print r' return;'
428 print r' }'
José Fonseca8e3c2c02012-01-23 00:30:35 +0000429
430 def deserializeArgs(self, function):
José Fonsecad994cf02011-11-03 19:35:53 +0000431 print ' retrace::ScopedAllocator _allocator;'
432 print ' (void)_allocator;'
José Fonsecae0e61402010-11-25 15:03:23 +0000433 success = True
434 for arg in function.args:
José Fonseca0075f152012-04-14 20:25:52 +0100435 arg_type = arg.type.mutable()
José Fonsecae0e61402010-11-25 15:03:23 +0000436 print ' %s %s;' % (arg_type, arg.name)
437 rvalue = 'call.arg(%u)' % (arg.index,)
438 lvalue = arg.name
439 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000440 self.extractArg(function, arg, arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100441 except UnsupportedType:
José Fonseca8e3c2c02012-01-23 00:30:35 +0000442 success = False
José Fonseca2d216ae2012-04-01 22:48:24 +0200443 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100444 print
José Fonseca8e3c2c02012-01-23 00:30:35 +0000445
José Fonsecae0e61402010-11-25 15:03:23 +0000446 if not success:
José Fonseca9109c3a2011-05-24 19:31:26 +0100447 print ' if (1) {'
José Fonseca54f304a2012-01-14 19:33:08 +0000448 self.failFunction(function)
José Fonsecaeb216e62012-11-20 11:08:08 +0000449 sys.stderr.write('warning: unsupported %s call\n' % function.name)
José Fonseca9109c3a2011-05-24 19:31:26 +0100450 print ' }'
José Fonseca8e3c2c02012-01-23 00:30:35 +0000451
452 def swizzleValues(self, function):
José Fonsecae0e61402010-11-25 15:03:23 +0000453 for arg in function.args:
454 if arg.output:
José Fonseca0075f152012-04-14 20:25:52 +0100455 arg_type = arg.type.mutable()
José Fonsecae0e61402010-11-25 15:03:23 +0000456 rvalue = 'call.arg(%u)' % (arg.index,)
457 lvalue = arg.name
458 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000459 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100460 except UnsupportedType:
José Fonseca0a37edf2011-10-09 09:45:22 +0100461 print ' // XXX: %s' % arg.name
José Fonsecae0e61402010-11-25 15:03:23 +0000462 if function.type is not stdapi.Void:
463 rvalue = '*call.ret'
José Fonseca632a78d2012-04-19 07:18:59 +0100464 lvalue = '_result'
José Fonsecae0e61402010-11-25 15:03:23 +0000465 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000466 self.regiterSwizzledValue(function.type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100467 except UnsupportedType:
José Fonsecafbcf6832012-04-05 07:10:30 +0100468 raise
José Fonseca46a48392011-10-14 11:34:27 +0100469 print ' // XXX: result'
José Fonsecae0e61402010-11-25 15:03:23 +0000470
José Fonseca54f304a2012-01-14 19:33:08 +0000471 def failFunction(self, function):
José Fonsecab1bb3c22011-10-08 20:23:18 +0100472 print ' if (retrace::verbosity >= 0) {'
José Fonsecaf5cda412011-10-09 17:27:23 +0100473 print ' retrace::unsupported(call);'
José Fonsecab1bb3c22011-10-08 20:23:18 +0100474 print ' }'
José Fonsecafa15d332010-11-25 20:22:39 +0000475 print ' return;'
476
José Fonseca54f304a2012-01-14 19:33:08 +0000477 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
José Fonseca4a2c57b2012-04-07 10:50:53 +0100478 ValueAllocator().visit(arg_type, lvalue, rvalue)
479 if arg.input:
480 ValueDeserializer().visit(arg_type, lvalue, rvalue)
José Fonsecafd34e4e2011-06-03 19:34:29 +0100481
José Fonseca54f304a2012-01-14 19:33:08 +0000482 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
José Fonseca4a2c57b2012-04-07 10:50:53 +0100483 try:
484 ValueAllocator().visit(arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100485 except UnsupportedType:
José Fonseca4a2c57b2012-04-07 10:50:53 +0100486 pass
José Fonseca54f304a2012-01-14 19:33:08 +0000487 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000488
José Fonseca54f304a2012-01-14 19:33:08 +0000489 def regiterSwizzledValue(self, type, lvalue, rvalue):
490 visitor = SwizzledValueRegistrator()
491 visitor.visit(type, lvalue, rvalue)
492
José Fonseca3db3b2f2012-05-11 14:55:50 +0100493 def declareRet(self, function):
494 if function.type is not stdapi.Void:
495 print ' %s _result;' % (function.type)
496
José Fonseca54f304a2012-01-14 19:33:08 +0000497 def invokeFunction(self, function):
José Fonseca59ee88e2012-01-15 14:24:10 +0000498 arg_names = ", ".join(function.argNames())
José Fonsecafa15d332010-11-25 20:22:39 +0000499 if function.type is not stdapi.Void:
José Fonseca632a78d2012-04-19 07:18:59 +0100500 print ' _result = %s(%s);' % (function.name, arg_names)
Jose Fonseca5c487ec2015-06-02 22:16:52 +0100501 self.checkResult(None, function)
José Fonsecafa15d332010-11-25 20:22:39 +0000502 else:
503 print ' %s(%s);' % (function.name, arg_names)
504
José Fonseca8e3c2c02012-01-23 00:30:35 +0000505 def invokeInterfaceMethod(self, interface, method):
506 arg_names = ", ".join(method.argNames())
507 if method.type is not stdapi.Void:
José Fonseca632a78d2012-04-19 07:18:59 +0100508 print ' _result = _this->%s(%s);' % (method.name, arg_names)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000509 else:
510 print ' _this->%s(%s);' % (method.name, arg_names)
511
José Fonsecada777082015-02-09 11:18:36 +0000512 # Adjust reference count when QueryInterface fails. This is
513 # particularly useful when replaying traces on older Direct3D runtimes
514 # which might miss newer versions of interfaces, yet none of those
515 # methods are actually used.
516 #
517 # TODO: Generalize to other methods that return interfaces
518 if method.name == 'QueryInterface':
519 print r' if (FAILED(_result)) {'
520 print r' IUnknown *pObj = retrace::asObjPointer<IUnknown>(call, *call.arg(2).toArray()->values[0]);'
521 print r' if (pObj) {'
522 print r' pObj->AddRef();'
523 print r' }'
524 print r' }'
525
526 if method.type is not stdapi.Void:
Jose Fonseca5c487ec2015-06-02 22:16:52 +0100527 self.checkResult(interface, method)
José Fonsecada777082015-02-09 11:18:36 +0000528
José Fonseca8a4462e2014-09-23 14:39:01 +0100529 # Debug COM reference counting. Disabled by default as reported
530 # reference counts depend on internal implementation details.
531 if method.name in ('AddRef', 'Release'):
532 print r' if (0) retrace::checkMismatch(call, "cRef", call.ret, _result);'
533
534 # On release our reference when we reach Release() == 0 call in the
535 # trace.
536 if method.name == 'Release':
537 print r' ULONG _orig_result = call.ret->toUInt();'
538 print r' if (_orig_result == 0 || _result == 0) {'
539 print r' if (_orig_result != 0) {'
540 print r' retrace::warning(call) << "unexpected object destruction\n";'
541 print r' }'
542 print r' retrace::delObj(call.arg(0));'
543 print r' }'
544
Jose Fonseca5c487ec2015-06-02 22:16:52 +0100545 def checkResult(self, interface, methodOrFunction):
546 assert methodOrFunction.type is not stdapi.Void
547 if str(methodOrFunction.type) == 'HRESULT':
José Fonseca4f49d212012-11-14 14:02:35 +0000548 print r' if (FAILED(_result)) {'
José Fonseca64add5f2014-09-05 11:53:11 +0100549 print r' retrace::failed(call, _result);'
José Fonseca3b669fa2015-02-09 11:17:47 +0000550 print r' return;'
José Fonseca4f49d212012-11-14 14:02:35 +0000551 print r' }'
José Fonseca31983872015-02-09 11:16:20 +0000552 else:
553 print r' (void)_result;'
José Fonseca4f49d212012-11-14 14:02:35 +0000554
José Fonsecafacdb352014-09-05 13:22:01 +0100555 def checkPitchMismatch(self, method):
José Fonseca9a3abc72014-09-23 14:39:18 +0100556 # Warn for mismatches in 2D/3D mappings.
557 # FIXME: We should try to swizzle them. It's a bit of work, but possible.
558 for outArg in method.args:
559 if outArg.output \
560 and isinstance(outArg.type, stdapi.Pointer) \
561 and isinstance(outArg.type.type, stdapi.Struct):
562 print r' const trace::Array *_%s = call.arg(%u).toArray();' % (outArg.name, outArg.index)
563 print r' if (%s) {' % outArg.name
564 print r' const trace::Struct *_struct = _%s->values[0]->toStruct();' % (outArg.name)
565 print r' if (_struct) {'
566 struct = outArg.type.type
567 for memberIndex in range(len(struct.members)):
568 memberType, memberName = struct.members[memberIndex]
569 if memberName.endswith('Pitch'):
Jose Fonseca1e3c0f72015-07-20 21:50:42 +0100570 print r' if (%s->%s) {' % (outArg.name, memberName)
571 print r' retrace::checkMismatch(call, "%s", _struct->members[%u], %s->%s);' % (memberName, memberIndex, outArg.name, memberName)
572 print r' }'
José Fonseca9a3abc72014-09-23 14:39:18 +0100573 print r' }'
574 print r' }'
José Fonsecafacdb352014-09-05 13:22:01 +0100575
José Fonseca54f304a2012-01-14 19:33:08 +0000576 def filterFunction(self, function):
José Fonseca4441baf2010-11-25 19:55:27 +0000577 return True
578
José Fonseca2741ed82011-10-07 23:36:39 +0100579 table_name = 'retrace::callbacks'
580
José Fonseca54f304a2012-01-14 19:33:08 +0000581 def retraceApi(self, api):
José Fonsecae0e61402010-11-25 15:03:23 +0000582
José Fonseca412149c2012-04-01 22:47:30 +0200583 print '#include "os_time.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000584 print '#include "trace_parser.hpp"'
José Fonseca91343f52011-04-01 08:37:06 +0100585 print '#include "retrace.hpp"'
José Fonsecaab8142f2012-05-13 10:04:19 +0100586 print '#include "retrace_swizzle.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000587 print
588
José Fonseca44703822012-01-31 10:48:58 +0000589 types = api.getAllTypes()
José Fonsecae0e61402010-11-25 15:03:23 +0000590 handles = [type for type in types if isinstance(type, stdapi.Handle)]
José Fonsecad922e1d2010-11-25 17:14:02 +0000591 handle_names = set()
José Fonsecae0e61402010-11-25 15:03:23 +0000592 for handle in handles:
José Fonsecad922e1d2010-11-25 17:14:02 +0000593 if handle.name not in handle_names:
José Fonseca8a844ae2010-12-06 18:50:52 +0000594 if handle.key is None:
José Fonseca632a78d2012-04-19 07:18:59 +0100595 print 'static retrace::map<%s> _%s_map;' % (handle.type, handle.name)
José Fonseca8a844ae2010-12-06 18:50:52 +0000596 else:
597 key_name, key_type = handle.key
José Fonseca632a78d2012-04-19 07:18:59 +0100598 print 'static std::map<%s, retrace::map<%s> > _%s_map;' % (key_type, handle.type, handle.name)
José Fonsecad922e1d2010-11-25 17:14:02 +0000599 handle_names.add(handle.name)
José Fonsecae0e61402010-11-25 15:03:23 +0000600 print
601
José Fonseca81301932012-11-11 00:10:20 +0000602 functions = filter(self.filterFunction, api.getAllFunctions())
José Fonseca8e3c2c02012-01-23 00:30:35 +0000603 for function in functions:
José Fonseca84cea3b2012-05-09 21:12:30 +0100604 if function.sideeffects and not function.internal:
José Fonseca1da480d2012-04-13 17:36:19 +0100605 self.retraceFunction(function)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000606 interfaces = api.getAllInterfaces()
607 for interface in interfaces:
José Fonseca14aa1712014-08-22 15:36:55 +0100608 for method in interface.methods:
José Fonseca84cea3b2012-05-09 21:12:30 +0100609 if method.sideeffects and not method.internal:
José Fonseca1da480d2012-04-13 17:36:19 +0100610 self.retraceInterfaceMethod(interface, method)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000611
612 print 'const retrace::Entry %s[] = {' % self.table_name
613 for function in functions:
José Fonseca84cea3b2012-05-09 21:12:30 +0100614 if not function.internal:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000615 sigName = function.sigName()
José Fonseca84cea3b2012-05-09 21:12:30 +0100616 if function.sideeffects:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000617 print ' {"%s", &retrace_%s},' % (sigName, self.makeFunctionId(function))
José Fonseca84cea3b2012-05-09 21:12:30 +0100618 else:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000619 print ' {"%s", &retrace::ignore},' % (sigName,)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000620 for interface in interfaces:
José Fonseca14aa1712014-08-22 15:36:55 +0100621 for base, method in interface.iterBaseMethods():
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000622 sigName = method.sigName()
José Fonseca1da480d2012-04-13 17:36:19 +0100623 if method.sideeffects:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000624 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, sigName, base.name, self.makeFunctionId(method))
José Fonseca1da480d2012-04-13 17:36:19 +0100625 else:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000626 print ' {"%s::%s", &retrace::ignore},' % (interface.name, sigName)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000627 print ' {NULL, NULL}'
628 print '};'
629 print
José Fonsecae0e61402010-11-25 15:03:23 +0000630