]> git.cworth.org Git - apitrace/blob - wrappers/trace.py
Don't defer arguments when functions fail.
[apitrace] / wrappers / trace.py
1 ##########################################################################
2 #
3 # Copyright 2008-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 """Common trace code generation."""
27
28
29 # Adjust path
30 import os.path
31 import sys
32 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
33
34
35 import specs.stdapi as stdapi
36
37
38 def getWrapperInterfaceName(interface):
39     return "Wrap" + interface.expr
40
41
42
43 class ExpanderMixin:
44     '''Mixin class that provides a bunch of methods to expand C expressions
45     from the specifications.'''
46
47     __structs = None
48     __indices = None
49
50     def expand(self, expr):
51         # Expand a C expression, replacing certain variables
52         if not isinstance(expr, basestring):
53             return expr
54         variables = {}
55
56         if self.__structs is not None:
57             variables['self'] = '(%s)' % self.__structs[0]
58         if self.__indices is not None:
59             variables['i'] = self.__indices[0]
60
61         expandedExpr = expr.format(**variables)
62         if expandedExpr != expr and 0:
63             sys.stderr.write("  %r -> %r\n" % (expr, expandedExpr))
64         return expandedExpr
65
66     def visitMember(self, structInstance, member_type, *args, **kwargs):
67         self.__structs = (structInstance, self.__structs)
68         try:
69             return self.visit(member_type, *args, **kwargs)
70         finally:
71             _, self.__structs = self.__structs
72
73     def visitElement(self, element_index, element_type, *args, **kwargs):
74         self.__indices = (element_index, self.__indices)
75         try:
76             return self.visit(element_type, *args, **kwargs)
77         finally:
78             _, self.__indices = self.__indices
79
80
81 class ComplexValueSerializer(stdapi.OnceVisitor):
82     '''Type visitors which generates serialization functions for
83     complex types.
84     
85     Simple types are serialized inline.
86     '''
87
88     def __init__(self, serializer):
89         stdapi.OnceVisitor.__init__(self)
90         self.serializer = serializer
91
92     def visitVoid(self, literal):
93         pass
94
95     def visitLiteral(self, literal):
96         pass
97
98     def visitString(self, string):
99         pass
100
101     def visitConst(self, const):
102         self.visit(const.type)
103
104     def visitStruct(self, struct):
105         print 'static const char * _struct%s_members[%u] = {' % (struct.tag, len(struct.members))
106         for type, name,  in struct.members:
107             print '    "%s",' % (name,)
108         print '};'
109         print 'static const trace::StructSig _struct%s_sig = {' % (struct.tag,)
110         print '   %u, "%s", %u, _struct%s_members' % (struct.id, struct.name, len(struct.members), struct.tag)
111         print '};'
112         print
113
114     def visitArray(self, array):
115         self.visit(array.type)
116
117     def visitBlob(self, array):
118         pass
119
120     def visitEnum(self, enum):
121         print 'static const trace::EnumValue _enum%s_values[] = {' % (enum.tag)
122         for value in enum.values:
123             print '   {"%s", %s},' % (value, value)
124         print '};'
125         print
126         print 'static const trace::EnumSig _enum%s_sig = {' % (enum.tag)
127         print '   %u, %u, _enum%s_values' % (enum.id, len(enum.values), enum.tag)
128         print '};'
129         print
130
131     def visitBitmask(self, bitmask):
132         print 'static const trace::BitmaskFlag _bitmask%s_flags[] = {' % (bitmask.tag)
133         for value in bitmask.values:
134             print '   {"%s", %s},' % (value, value)
135         print '};'
136         print
137         print 'static const trace::BitmaskSig _bitmask%s_sig = {' % (bitmask.tag)
138         print '   %u, %u, _bitmask%s_flags' % (bitmask.id, len(bitmask.values), bitmask.tag)
139         print '};'
140         print
141
142     def visitPointer(self, pointer):
143         self.visit(pointer.type)
144
145     def visitIntPointer(self, pointer):
146         pass
147
148     def visitObjPointer(self, pointer):
149         self.visit(pointer.type)
150
151     def visitLinearPointer(self, pointer):
152         self.visit(pointer.type)
153
154     def visitHandle(self, handle):
155         self.visit(handle.type)
156
157     def visitReference(self, reference):
158         self.visit(reference.type)
159
160     def visitAlias(self, alias):
161         self.visit(alias.type)
162
163     def visitOpaque(self, opaque):
164         pass
165
166     def visitInterface(self, interface):
167         pass
168
169     def visitPolymorphic(self, polymorphic):
170         if not polymorphic.contextLess:
171             return
172         print 'static void _write__%s(int selector, const %s & value) {' % (polymorphic.tag, polymorphic.expr)
173         print '    switch (selector) {'
174         for cases, type in polymorphic.iterSwitch():
175             for case in cases:
176                 print '    %s:' % case
177             self.serializer.visit(type, 'static_cast<%s>(value)' % (type,))
178             print '        break;'
179         print '    }'
180         print '}'
181         print
182
183
184 class ValueSerializer(stdapi.Visitor, ExpanderMixin):
185     '''Visitor which generates code to serialize any type.
186     
187     Simple types are serialized inline here, whereas the serialization of
188     complex types is dispatched to the serialization functions generated by
189     ComplexValueSerializer visitor above.
190     '''
191
192     def __init__(self):
193         #stdapi.Visitor.__init__(self)
194         self.indices = []
195         self.instances = []
196
197     def visitLiteral(self, literal, instance):
198         print '    trace::localWriter.write%s(%s);' % (literal.kind, instance)
199
200     def visitString(self, string, instance):
201         if not string.wide:
202             cast = 'const char *'
203             suffix = 'String'
204         else:
205             cast = 'const wchar_t *'
206             suffix = 'WString'
207         if cast != string.expr:
208             # reinterpret_cast is necessary for GLubyte * <=> char *
209             instance = 'reinterpret_cast<%s>(%s)' % (cast, instance)
210         if string.length is not None:
211             length = ', %s' % string.length
212         else:
213             length = ''
214         print '    trace::localWriter.write%s(%s%s);' % (suffix, instance, length)
215
216     def visitConst(self, const, instance):
217         self.visit(const.type, instance)
218
219     def visitStruct(self, struct, instance):
220         print '    trace::localWriter.beginStruct(&_struct%s_sig);' % (struct.tag,)
221         for type, name in struct.members:
222             self.visitMember(instance, type, '(%s).%s' % (instance, name,))
223         print '    trace::localWriter.endStruct();'
224
225     def visitArray(self, array, instance):
226         length = '_c' + array.type.tag
227         index = '_i' + array.type.tag
228         array_length = self.expand(array.length)
229         print '    if (%s) {' % instance
230         print '        size_t %s = %s > 0 ? %s : 0;' % (length, array_length, array_length)
231         print '        trace::localWriter.beginArray(%s);' % length
232         print '        for (size_t %s = 0; %s < %s; ++%s) {' % (index, index, length, index)
233         print '            trace::localWriter.beginElement();'
234         self.visitElement(index, array.type, '(%s)[%s]' % (instance, index))
235         print '            trace::localWriter.endElement();'
236         print '        }'
237         print '        trace::localWriter.endArray();'
238         print '    } else {'
239         print '        trace::localWriter.writeNull();'
240         print '    }'
241
242     def visitBlob(self, blob, instance):
243         print '    trace::localWriter.writeBlob(%s, %s);' % (instance, self.expand(blob.size))
244
245     def visitEnum(self, enum, instance):
246         print '    trace::localWriter.writeEnum(&_enum%s_sig, %s);' % (enum.tag, instance)
247
248     def visitBitmask(self, bitmask, instance):
249         print '    trace::localWriter.writeBitmask(&_bitmask%s_sig, %s);' % (bitmask.tag, instance)
250
251     def visitPointer(self, pointer, instance):
252         print '    if (%s) {' % instance
253         print '        trace::localWriter.beginArray(1);'
254         print '        trace::localWriter.beginElement();'
255         self.visit(pointer.type, "*" + instance)
256         print '        trace::localWriter.endElement();'
257         print '        trace::localWriter.endArray();'
258         print '    } else {'
259         print '        trace::localWriter.writeNull();'
260         print '    }'
261
262     def visitIntPointer(self, pointer, instance):
263         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
264
265     def visitObjPointer(self, pointer, instance):
266         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
267
268     def visitLinearPointer(self, pointer, instance):
269         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
270
271     def visitReference(self, reference, instance):
272         self.visit(reference.type, instance)
273
274     def visitHandle(self, handle, instance):
275         self.visit(handle.type, instance)
276
277     def visitAlias(self, alias, instance):
278         self.visit(alias.type, instance)
279
280     def visitOpaque(self, opaque, instance):
281         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
282
283     def visitInterface(self, interface, instance):
284         assert False
285
286     def visitPolymorphic(self, polymorphic, instance):
287         if polymorphic.contextLess:
288             print '    _write__%s(%s, %s);' % (polymorphic.tag, polymorphic.switchExpr, instance)
289         else:
290             print '    switch (%s) {' % polymorphic.switchExpr
291             for cases, type in polymorphic.iterSwitch():
292                 for case in cases:
293                     print '    %s:' % case
294                 self.visit(type, 'static_cast<%s>(%s)' % (type, instance))
295                 print '        break;'
296             print '    }'
297
298
299 class WrapDecider(stdapi.Traverser):
300     '''Type visitor which will decide wheter this type will need wrapping or not.
301     
302     For complex types (arrays, structures), we need to know this before hand.
303     '''
304
305     def __init__(self):
306         self.needsWrapping = False
307
308     def visitLinearPointer(self, void):
309         pass
310
311     def visitInterface(self, interface):
312         self.needsWrapping = True
313
314
315 class ValueWrapper(stdapi.Traverser, ExpanderMixin):
316     '''Type visitor which will generate the code to wrap an instance.
317     
318     Wrapping is necessary mostly for interfaces, however interface pointers can
319     appear anywhere inside complex types.
320     '''
321
322     def visitStruct(self, struct, instance):
323         for type, name in struct.members:
324             self.visitMember(instance, type, "(%s).%s" % (instance, name))
325
326     def visitArray(self, array, instance):
327         array_length = self.expand(array.length)
328         print "    if (%s) {" % instance
329         print "        for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array_length
330         self.visitElement('_i', array.type, instance + "[_i]")
331         print "        }"
332         print "    }"
333
334     def visitPointer(self, pointer, instance):
335         print "    if (%s) {" % instance
336         self.visit(pointer.type, "*" + instance)
337         print "    }"
338     
339     def visitObjPointer(self, pointer, instance):
340         elem_type = pointer.type.mutable()
341         if isinstance(elem_type, stdapi.Interface):
342             self.visitInterfacePointer(elem_type, instance)
343         else:
344             self.visitPointer(pointer, instance)
345     
346     def visitInterface(self, interface, instance):
347         raise NotImplementedError
348
349     def visitInterfacePointer(self, interface, instance):
350         print "    if (%s) {" % instance
351         print "        %s = new %s(%s);" % (instance, getWrapperInterfaceName(interface), instance)
352         print "    }"
353     
354     def visitPolymorphic(self, type, instance):
355         # XXX: There might be polymorphic values that need wrapping in the future
356         raise NotImplementedError
357
358
359 class ValueUnwrapper(ValueWrapper):
360     '''Reverse of ValueWrapper.'''
361
362     allocated = False
363
364     def visitArray(self, array, instance):
365         if self.allocated or isinstance(instance, stdapi.Interface):
366             return ValueWrapper.visitArray(self, array, instance)
367         array_length = self.expand(array.length)
368         elem_type = array.type.mutable()
369         print "    if (%s && %s) {" % (instance, array_length)
370         print "        %s * _t = static_cast<%s *>(alloca(%s * sizeof *_t));" % (elem_type, elem_type, array_length)
371         print "        for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array_length
372         print "            _t[_i] = %s[_i];" % instance 
373         self.allocated = True
374         self.visit(array.type, "_t[_i]")
375         print "        }"
376         print "        %s = _t;" % instance
377         print "    }"
378
379     def visitInterfacePointer(self, interface, instance):
380         print r'    if (%s) {' % instance
381         print r'        const %s *pWrapper = static_cast<const %s*>(%s);' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), instance)
382         print r'        if (pWrapper && pWrapper->m_dwMagic == 0xd8365d6c) {'
383         print r'            %s = pWrapper->m_pInstance;' % (instance,)
384         print r'        } else {'
385         print r'            os::log("apitrace: warning: %%s: unexpected %%s pointer\n", __FUNCTION__, "%s");' % interface.name
386         print r'        }'
387         print r'    }'
388
389
390 class Tracer:
391     '''Base class to orchestrate the code generation of API tracing.'''
392
393     def __init__(self):
394         self.api = None
395
396     def serializerFactory(self):
397         '''Create a serializer.
398         
399         Can be overriden by derived classes to inject their own serialzer.
400         '''
401
402         return ValueSerializer()
403
404     def traceApi(self, api):
405         self.api = api
406
407         self.header(api)
408
409         # Includes
410         for header in api.headers:
411             print header
412         print
413
414         # Generate the serializer functions
415         types = api.getAllTypes()
416         visitor = ComplexValueSerializer(self.serializerFactory())
417         map(visitor.visit, types)
418         print
419
420         # Interfaces wrapers
421         self.traceInterfaces(api)
422
423         # Function wrappers
424         self.interface = None
425         self.base = None
426         map(self.traceFunctionDecl, api.functions)
427         map(self.traceFunctionImpl, api.functions)
428         print
429
430         self.footer(api)
431
432     def header(self, api):
433         print '#ifdef _WIN32'
434         print '#  include <malloc.h> // alloca'
435         print '#  ifndef alloca'
436         print '#    define alloca _alloca'
437         print '#  endif'
438         print '#else'
439         print '#  include <alloca.h> // alloca'
440         print '#endif'
441         print
442         print '#include "trace.hpp"'
443         print
444
445     def footer(self, api):
446         pass
447
448     def traceFunctionDecl(self, function):
449         # Per-function declarations
450
451         if not function.internal:
452             if function.args:
453                 print 'static const char * _%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args]))
454             else:
455                 print 'static const char ** _%s_args = NULL;' % (function.name,)
456             print 'static const trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, function.id, function.name, len(function.args), function.name)
457             print
458
459     def isFunctionPublic(self, function):
460         return True
461
462     def traceFunctionImpl(self, function):
463         if self.isFunctionPublic(function):
464             print 'extern "C" PUBLIC'
465         else:
466             print 'extern "C" PRIVATE'
467         print function.prototype() + ' {'
468         if function.type is not stdapi.Void:
469             print '    %s _result;' % function.type
470
471         # No-op if tracing is disabled
472         print '    if (!trace::isTracingEnabled()) {'
473         Tracer.invokeFunction(self, function)
474         if function.type is not stdapi.Void:
475             print '        return _result;'
476         else:
477             print '        return;'
478         print '    }'
479
480         self.traceFunctionImplBody(function)
481         if function.type is not stdapi.Void:
482             print '    return _result;'
483         print '}'
484         print
485
486     def traceFunctionImplBody(self, function):
487         if not function.internal:
488             print '    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
489             for arg in function.args:
490                 if not arg.output:
491                     self.unwrapArg(function, arg)
492                     self.serializeArg(function, arg)
493             print '    trace::localWriter.endEnter();'
494         self.invokeFunction(function)
495         if not function.internal:
496             print '    trace::localWriter.beginLeave(_call);'
497             print '    if (%s) {' % self.wasFunctionSuccessful(function)
498             for arg in function.args:
499                 if arg.output:
500                     self.serializeArg(function, arg)
501                     self.wrapArg(function, arg)
502             print '    }'
503             if function.type is not stdapi.Void:
504                 self.serializeRet(function, "_result")
505             print '    trace::localWriter.endLeave();'
506             if function.type is not stdapi.Void:
507                 self.wrapRet(function, "_result")
508
509     def invokeFunction(self, function, prefix='_', suffix=''):
510         if function.type is stdapi.Void:
511             result = ''
512         else:
513             result = '_result = '
514         dispatch = prefix + function.name + suffix
515         print '    %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
516
517     def wasFunctionSuccessful(self, function):
518         if function.type is stdapi.Void:
519             return 'true'
520         if str(function.type) == 'HRESULT':
521             return 'SUCCEEDED(_result)'
522         return 'false'
523
524     def serializeArg(self, function, arg):
525         print '    trace::localWriter.beginArg(%u);' % (arg.index,)
526         self.serializeArgValue(function, arg)
527         print '    trace::localWriter.endArg();'
528
529     def serializeArgValue(self, function, arg):
530         self.serializeValue(arg.type, arg.name)
531
532     def wrapArg(self, function, arg):
533         assert not isinstance(arg.type, stdapi.ObjPointer)
534
535         from specs.winapi import REFIID
536         riid = None
537         for other_arg in function.args:
538             if not other_arg.output and other_arg.type is REFIID:
539                 riid = other_arg
540         if riid is not None \
541            and isinstance(arg.type, stdapi.Pointer) \
542            and isinstance(arg.type.type, stdapi.ObjPointer):
543             self.wrapIid(function, riid, arg)
544             return
545
546         self.wrapValue(arg.type, arg.name)
547
548     def unwrapArg(self, function, arg):
549         self.unwrapValue(arg.type, arg.name)
550
551     def serializeRet(self, function, instance):
552         print '    trace::localWriter.beginReturn();'
553         self.serializeValue(function.type, instance)
554         print '    trace::localWriter.endReturn();'
555
556     def serializeValue(self, type, instance):
557         serializer = self.serializerFactory()
558         serializer.visit(type, instance)
559
560     def wrapRet(self, function, instance):
561         self.wrapValue(function.type, instance)
562
563     def unwrapRet(self, function, instance):
564         self.unwrapValue(function.type, instance)
565
566     def needsWrapping(self, type):
567         visitor = WrapDecider()
568         visitor.visit(type)
569         return visitor.needsWrapping
570
571     def wrapValue(self, type, instance):
572         if self.needsWrapping(type):
573             visitor = ValueWrapper()
574             visitor.visit(type, instance)
575
576     def unwrapValue(self, type, instance):
577         if self.needsWrapping(type):
578             visitor = ValueUnwrapper()
579             visitor.visit(type, instance)
580
581     def traceInterfaces(self, api):
582         interfaces = api.getAllInterfaces()
583         if not interfaces:
584             return
585         map(self.declareWrapperInterface, interfaces)
586         self.implementIidWrapper(api)
587         map(self.implementWrapperInterface, interfaces)
588         print
589
590     def declareWrapperInterface(self, interface):
591         print "class %s : public %s " % (getWrapperInterfaceName(interface), interface.name)
592         print "{"
593         print "public:"
594         print "    %s(%s * pInstance);" % (getWrapperInterfaceName(interface), interface.name)
595         print "    virtual ~%s();" % getWrapperInterfaceName(interface)
596         print
597         for method in interface.iterMethods():
598             print "    " + method.prototype() + ";"
599         print
600         #print "private:"
601         for type, name, value in self.enumWrapperInterfaceVariables(interface):
602             print '    %s %s;' % (type, name)
603         print "};"
604         print
605
606     def enumWrapperInterfaceVariables(self, interface):
607         return [
608             ("DWORD", "m_dwMagic", "0xd8365d6c"),
609             ("%s *" % interface.name, "m_pInstance", "pInstance"),
610         ] 
611
612     def implementWrapperInterface(self, interface):
613         self.interface = interface
614
615         print '%s::%s(%s * pInstance) {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), interface.name)
616         for type, name, value in self.enumWrapperInterfaceVariables(interface):
617             print '    %s = %s;' % (name, value)
618         print '}'
619         print
620         print '%s::~%s() {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface))
621         print '}'
622         print
623         
624         for base, method in interface.iterBaseMethods():
625             self.base = base
626             self.implementWrapperInterfaceMethod(interface, base, method)
627
628         print
629
630     def implementWrapperInterfaceMethod(self, interface, base, method):
631         print method.prototype(getWrapperInterfaceName(interface) + '::' + method.name) + ' {'
632         if method.type is not stdapi.Void:
633             print '    %s _result;' % method.type
634     
635         self.implementWrapperInterfaceMethodBody(interface, base, method)
636     
637         if method.type is not stdapi.Void:
638             print '    return _result;'
639         print '}'
640         print
641
642     def implementWrapperInterfaceMethodBody(self, interface, base, method):
643         assert not method.internal
644
645         print '    static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args]))
646         print '    static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (method.id, interface.name + '::' + method.name, len(method.args) + 1)
647
648         print '    %s *_this = static_cast<%s *>(m_pInstance);' % (base, base)
649
650         print '    unsigned _call = trace::localWriter.beginEnter(&_sig);'
651         print '    trace::localWriter.beginArg(0);'
652         print '    trace::localWriter.writePointer((uintptr_t)m_pInstance);'
653         print '    trace::localWriter.endArg();'
654         for arg in method.args:
655             if not arg.output:
656                 self.unwrapArg(method, arg)
657                 self.serializeArg(method, arg)
658         print '    trace::localWriter.endEnter();'
659         
660         self.invokeMethod(interface, base, method)
661
662         print '    trace::localWriter.beginLeave(_call);'
663
664         print '    if (%s) {' % self.wasFunctionSuccessful(method)
665         for arg in method.args:
666             if arg.output:
667                 self.serializeArg(method, arg)
668                 self.wrapArg(method, arg)
669         print '    }'
670
671         if method.type is not stdapi.Void:
672             self.serializeRet(method, '_result')
673         print '    trace::localWriter.endLeave();'
674         if method.type is not stdapi.Void:
675             self.wrapRet(method, '_result')
676
677         if method.name == 'Release':
678             assert method.type is not stdapi.Void
679             print '    if (!_result)'
680             print '        delete this;'
681
682     def implementIidWrapper(self, api):
683         print r'static void'
684         print r'warnIID(const char *functionName, REFIID riid, const char *reason) {'
685         print r'    os::log("apitrace: warning: %s: %s IID {0x%08lX,0x%04X,0x%04X,{0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X}}\n",'
686         print r'            functionName, reason,'
687         print r'            riid.Data1, riid.Data2, riid.Data3,'
688         print r'            riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);'
689         print r'}'
690         print 
691         print r'static void'
692         print r'wrapIID(const char *functionName, REFIID riid, void * * ppvObj) {'
693         print r'    if (!ppvObj || !*ppvObj) {'
694         print r'        return;'
695         print r'    }'
696         else_ = ''
697         for iface in api.getAllInterfaces():
698             print r'    %sif (riid == IID_%s) {' % (else_, iface.name)
699             print r'        *ppvObj = new Wrap%s((%s *) *ppvObj);' % (iface.name, iface.name)
700             print r'    }'
701             else_ = 'else '
702         print r'    %s{' % else_
703         print r'        warnIID(functionName, riid, "unknown");'
704         print r'    }'
705         print r'}'
706         print
707
708     def wrapIid(self, function, riid, out):
709         # Cast output arg to `void **` if necessary
710         out_name = out.name
711         obj_type = out.type.type.type
712         if not obj_type is stdapi.Void:
713             assert isinstance(obj_type, stdapi.Interface)
714             out_name = 'reinterpret_cast<void * *>(%s)' % out_name
715
716         print r'    if (%s && *%s) {' % (out.name, out.name)
717         functionName = function.name
718         else_ = ''
719         if self.interface is not None:
720             functionName = self.interface.name + '::' + functionName
721             print r'        if (*%s == m_pInstance &&' % (out_name,)
722             print r'            (%s)) {' % ' || '.join('%s == IID_%s' % (riid.name, iface.name) for iface in self.interface.iterBases())
723             print r'            *%s = this;' % (out_name,)
724             print r'        }'
725             else_ = 'else '
726         print r'        %s{' % else_
727         print r'             wrapIID("%s", %s, %s);' % (functionName, riid.name, out_name)
728         print r'        }'
729         print r'    }'
730
731     def invokeMethod(self, interface, base, method):
732         if method.type is stdapi.Void:
733             result = ''
734         else:
735             result = '_result = '
736         print '    %s_this->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args]))
737     
738     def emit_memcpy(self, dest, src, length):
739         print '        unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
740         print '        trace::localWriter.beginArg(0);'
741         print '        trace::localWriter.writePointer((uintptr_t)%s);' % dest
742         print '        trace::localWriter.endArg();'
743         print '        trace::localWriter.beginArg(1);'
744         print '        trace::localWriter.writeBlob(%s, %s);' % (src, length)
745         print '        trace::localWriter.endArg();'
746         print '        trace::localWriter.beginArg(2);'
747         print '        trace::localWriter.writeUInt(%s);' % length
748         print '        trace::localWriter.endArg();'
749         print '        trace::localWriter.endEnter();'
750         print '        trace::localWriter.beginLeave(_call);'
751         print '        trace::localWriter.endLeave();'
752     
753     def fake_call(self, function, args):
754         print '            unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
755         for arg, instance in zip(function.args, args):
756             assert not arg.output
757             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
758             self.serializeValue(arg.type, instance)
759             print '            trace::localWriter.endArg();'
760         print '            trace::localWriter.endEnter();'
761         print '            trace::localWriter.beginLeave(_fake_call);'
762         print '            trace::localWriter.endLeave();'
763