]> git.cworth.org Git - apitrace/blob - wrappers/trace.py
d3d1x: Rename d3d10shader -> d3dcommonshader.
[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             for arg in function.args:
498                 if arg.output:
499                     self.serializeArg(function, arg)
500                     self.wrapArg(function, arg)
501             if function.type is not stdapi.Void:
502                 self.serializeRet(function, "_result")
503             print '    trace::localWriter.endLeave();'
504             if function.type is not stdapi.Void:
505                 self.wrapRet(function, "_result")
506
507     def invokeFunction(self, function, prefix='_', suffix=''):
508         if function.type is stdapi.Void:
509             result = ''
510         else:
511             result = '_result = '
512         dispatch = prefix + function.name + suffix
513         print '    %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
514
515     def serializeArg(self, function, arg):
516         print '    trace::localWriter.beginArg(%u);' % (arg.index,)
517         self.serializeArgValue(function, arg)
518         print '    trace::localWriter.endArg();'
519
520     def serializeArgValue(self, function, arg):
521         self.serializeValue(arg.type, arg.name)
522
523     def wrapArg(self, function, arg):
524         assert not isinstance(arg.type, stdapi.ObjPointer)
525
526         from specs.winapi import REFIID
527         riid = None
528         for other_arg in function.args:
529             if not other_arg.output and other_arg.type is REFIID:
530                 riid = other_arg
531         if riid is not None \
532            and isinstance(arg.type, stdapi.Pointer) \
533            and isinstance(arg.type.type, stdapi.ObjPointer):
534             self.wrapIid(function, riid, arg)
535             return
536
537         self.wrapValue(arg.type, arg.name)
538
539     def unwrapArg(self, function, arg):
540         self.unwrapValue(arg.type, arg.name)
541
542     def serializeRet(self, function, instance):
543         print '    trace::localWriter.beginReturn();'
544         self.serializeValue(function.type, instance)
545         print '    trace::localWriter.endReturn();'
546
547     def serializeValue(self, type, instance):
548         serializer = self.serializerFactory()
549         serializer.visit(type, instance)
550
551     def wrapRet(self, function, instance):
552         self.wrapValue(function.type, instance)
553
554     def unwrapRet(self, function, instance):
555         self.unwrapValue(function.type, instance)
556
557     def needsWrapping(self, type):
558         visitor = WrapDecider()
559         visitor.visit(type)
560         return visitor.needsWrapping
561
562     def wrapValue(self, type, instance):
563         if self.needsWrapping(type):
564             visitor = ValueWrapper()
565             visitor.visit(type, instance)
566
567     def unwrapValue(self, type, instance):
568         if self.needsWrapping(type):
569             visitor = ValueUnwrapper()
570             visitor.visit(type, instance)
571
572     def traceInterfaces(self, api):
573         interfaces = api.getAllInterfaces()
574         if not interfaces:
575             return
576         map(self.declareWrapperInterface, interfaces)
577         self.implementIidWrapper(api)
578         map(self.implementWrapperInterface, interfaces)
579         print
580
581     def declareWrapperInterface(self, interface):
582         print "class %s : public %s " % (getWrapperInterfaceName(interface), interface.name)
583         print "{"
584         print "public:"
585         print "    %s(%s * pInstance);" % (getWrapperInterfaceName(interface), interface.name)
586         print "    virtual ~%s();" % getWrapperInterfaceName(interface)
587         print
588         for method in interface.iterMethods():
589             print "    " + method.prototype() + ";"
590         print
591         #print "private:"
592         for type, name, value in self.enumWrapperInterfaceVariables(interface):
593             print '    %s %s;' % (type, name)
594         print "};"
595         print
596
597     def enumWrapperInterfaceVariables(self, interface):
598         return [
599             ("DWORD", "m_dwMagic", "0xd8365d6c"),
600             ("%s *" % interface.name, "m_pInstance", "pInstance"),
601         ] 
602
603     def implementWrapperInterface(self, interface):
604         self.interface = interface
605
606         print '%s::%s(%s * pInstance) {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), interface.name)
607         for type, name, value in self.enumWrapperInterfaceVariables(interface):
608             print '    %s = %s;' % (name, value)
609         print '}'
610         print
611         print '%s::~%s() {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface))
612         print '}'
613         print
614         
615         for base, method in interface.iterBaseMethods():
616             self.base = base
617             self.implementWrapperInterfaceMethod(interface, base, method)
618
619         print
620
621     def implementWrapperInterfaceMethod(self, interface, base, method):
622         print method.prototype(getWrapperInterfaceName(interface) + '::' + method.name) + ' {'
623         if method.type is not stdapi.Void:
624             print '    %s _result;' % method.type
625     
626         self.implementWrapperInterfaceMethodBody(interface, base, method)
627     
628         if method.type is not stdapi.Void:
629             print '    return _result;'
630         print '}'
631         print
632
633     def implementWrapperInterfaceMethodBody(self, interface, base, method):
634         assert not method.internal
635
636         print '    static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args]))
637         print '    static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (method.id, interface.name + '::' + method.name, len(method.args) + 1)
638
639         print '    %s *_this = static_cast<%s *>(m_pInstance);' % (base, base)
640
641         print '    unsigned _call = trace::localWriter.beginEnter(&_sig);'
642         print '    trace::localWriter.beginArg(0);'
643         print '    trace::localWriter.writePointer((uintptr_t)m_pInstance);'
644         print '    trace::localWriter.endArg();'
645         for arg in method.args:
646             if not arg.output:
647                 self.unwrapArg(method, arg)
648                 self.serializeArg(method, arg)
649         print '    trace::localWriter.endEnter();'
650         
651         self.invokeMethod(interface, base, method)
652
653         print '    trace::localWriter.beginLeave(_call);'
654         for arg in method.args:
655             if arg.output:
656                 self.serializeArg(method, arg)
657                 self.wrapArg(method, arg)
658
659         if method.type is not stdapi.Void:
660             self.serializeRet(method, '_result')
661         print '    trace::localWriter.endLeave();'
662         if method.type is not stdapi.Void:
663             self.wrapRet(method, '_result')
664
665         if method.name == 'Release':
666             assert method.type is not stdapi.Void
667             print '    if (!_result)'
668             print '        delete this;'
669
670     def implementIidWrapper(self, api):
671         print r'static void'
672         print r'warnIID(const char *functionName, REFIID riid, const char *reason) {'
673         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",'
674         print r'            functionName, reason,'
675         print r'            riid.Data1, riid.Data2, riid.Data3,'
676         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]);'
677         print r'}'
678         print 
679         print r'static void'
680         print r'wrapIID(const char *functionName, REFIID riid, void * * ppvObj) {'
681         print r'    if (!ppvObj || !*ppvObj) {'
682         print r'        return;'
683         print r'    }'
684         else_ = ''
685         for iface in api.getAllInterfaces():
686             print r'    %sif (riid == IID_%s) {' % (else_, iface.name)
687             print r'        *ppvObj = new Wrap%s((%s *) *ppvObj);' % (iface.name, iface.name)
688             print r'    }'
689             else_ = 'else '
690         print r'    %s{' % else_
691         print r'        warnIID(functionName, riid, "unknown");'
692         print r'    }'
693         print r'}'
694         print
695
696     def wrapIid(self, function, riid, out):
697         # Cast output arg to `void **` if necessary
698         out_name = out.name
699         obj_type = out.type.type.type
700         if not obj_type is stdapi.Void:
701             assert isinstance(obj_type, stdapi.Interface)
702             out_name = 'reinterpret_cast<void * *>(%s)' % out_name
703
704         print r'    if (%s && *%s) {' % (out.name, out.name)
705         functionName = function.name
706         else_ = ''
707         if self.interface is not None:
708             functionName = self.interface.name + '::' + functionName
709             print r'        if (*%s == m_pInstance &&' % (out_name,)
710             print r'            (%s)) {' % ' || '.join('%s == IID_%s' % (riid.name, iface.name) for iface in self.interface.iterBases())
711             print r'            *%s = this;' % (out_name,)
712             print r'        }'
713             else_ = 'else '
714         print r'        %s{' % else_
715         print r'             wrapIID("%s", %s, %s);' % (functionName, riid.name, out_name)
716         print r'        }'
717         print r'    }'
718
719     def invokeMethod(self, interface, base, method):
720         if method.type is stdapi.Void:
721             result = ''
722         else:
723             result = '_result = '
724         print '    %s_this->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args]))
725     
726     def emit_memcpy(self, dest, src, length):
727         print '        unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
728         print '        trace::localWriter.beginArg(0);'
729         print '        trace::localWriter.writePointer((uintptr_t)%s);' % dest
730         print '        trace::localWriter.endArg();'
731         print '        trace::localWriter.beginArg(1);'
732         print '        trace::localWriter.writeBlob(%s, %s);' % (src, length)
733         print '        trace::localWriter.endArg();'
734         print '        trace::localWriter.beginArg(2);'
735         print '        trace::localWriter.writeUInt(%s);' % length
736         print '        trace::localWriter.endArg();'
737         print '        trace::localWriter.endEnter();'
738         print '        trace::localWriter.beginLeave(_call);'
739         print '        trace::localWriter.endLeave();'
740     
741     def fake_call(self, function, args):
742         print '            unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
743         for arg, instance in zip(function.args, args):
744             assert not arg.output
745             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
746             self.serializeValue(arg.type, instance)
747             print '            trace::localWriter.endArg();'
748         print '            trace::localWriter.endEnter();'
749         print '            trace::localWriter.beginLeave(_fake_call);'
750         print '            trace::localWriter.endLeave();'
751