1 ##########################################################################
3 # Copyright 2008-2010 VMware, Inc.
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:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
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
24 ##########################################################################/
26 """Common trace code generation."""
32 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
35 import specs.stdapi as stdapi
38 def getWrapperInterfaceName(interface):
39 return "Wrap" + interface.expr
44 '''Mixin class that provides a bunch of methods to expand C expressions
45 from the specifications.'''
50 def expand(self, expr):
51 # Expand a C expression, replacing certain variables
52 if not isinstance(expr, basestring):
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]
61 expandedExpr = expr.format(**variables)
62 if expandedExpr != expr and 0:
63 sys.stderr.write(" %r -> %r\n" % (expr, expandedExpr))
66 def visitMember(self, structInstance, member_type, *args, **kwargs):
67 self.__structs = (structInstance, self.__structs)
69 return self.visit(member_type, *args, **kwargs)
71 _, self.__structs = self.__structs
73 def visitElement(self, element_index, element_type, *args, **kwargs):
74 self.__indices = (element_index, self.__indices)
76 return self.visit(element_type, *args, **kwargs)
78 _, self.__indices = self.__indices
81 class ComplexValueSerializer(stdapi.OnceVisitor):
82 '''Type visitors which generates serialization functions for
85 Simple types are serialized inline.
88 def __init__(self, serializer):
89 stdapi.OnceVisitor.__init__(self)
90 self.serializer = serializer
92 def visitVoid(self, literal):
95 def visitLiteral(self, literal):
98 def visitString(self, string):
101 def visitConst(self, const):
102 self.visit(const.type)
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:
110 print ' "%s",' % (name,)
112 print 'static const trace::StructSig _struct%s_sig = {' % (struct.tag,)
113 if struct.name is None:
116 structName = '"%s"' % struct.name
117 print ' %u, %s, %u, _struct%s_members' % (struct.id, structName, len(struct.members), struct.tag)
121 def visitArray(self, array):
122 self.visit(array.type)
124 def visitBlob(self, array):
127 def visitEnum(self, enum):
128 print 'static const trace::EnumValue _enum%s_values[] = {' % (enum.tag)
129 for value in enum.values:
130 print ' {"%s", %s},' % (value, value)
133 print 'static const trace::EnumSig _enum%s_sig = {' % (enum.tag)
134 print ' %u, %u, _enum%s_values' % (enum.id, len(enum.values), enum.tag)
138 def visitBitmask(self, bitmask):
139 print 'static const trace::BitmaskFlag _bitmask%s_flags[] = {' % (bitmask.tag)
140 for value in bitmask.values:
141 print ' {"%s", %s},' % (value, value)
144 print 'static const trace::BitmaskSig _bitmask%s_sig = {' % (bitmask.tag)
145 print ' %u, %u, _bitmask%s_flags' % (bitmask.id, len(bitmask.values), bitmask.tag)
149 def visitPointer(self, pointer):
150 self.visit(pointer.type)
152 def visitIntPointer(self, pointer):
155 def visitObjPointer(self, pointer):
156 self.visit(pointer.type)
158 def visitLinearPointer(self, pointer):
159 self.visit(pointer.type)
161 def visitHandle(self, handle):
162 self.visit(handle.type)
164 def visitReference(self, reference):
165 self.visit(reference.type)
167 def visitAlias(self, alias):
168 self.visit(alias.type)
170 def visitOpaque(self, opaque):
173 def visitInterface(self, interface):
176 def visitPolymorphic(self, polymorphic):
177 if not polymorphic.contextLess:
179 print 'static void _write__%s(int selector, const %s & value) {' % (polymorphic.tag, polymorphic.expr)
180 print ' switch (selector) {'
181 for cases, type in polymorphic.iterSwitch():
184 self.serializer.visit(type, 'static_cast<%s>(value)' % (type,))
191 class ValueSerializer(stdapi.Visitor, ExpanderMixin):
192 '''Visitor which generates code to serialize any type.
194 Simple types are serialized inline here, whereas the serialization of
195 complex types is dispatched to the serialization functions generated by
196 ComplexValueSerializer visitor above.
199 def visitLiteral(self, literal, instance):
200 print ' trace::localWriter.write%s(%s);' % (literal.kind, instance)
202 def visitString(self, string, instance):
204 cast = 'const char *'
207 cast = 'const wchar_t *'
209 if cast != string.expr:
210 # reinterpret_cast is necessary for GLubyte * <=> char *
211 instance = 'reinterpret_cast<%s>(%s)' % (cast, instance)
212 if string.length is not None:
213 length = ', %s' % self.expand(string.length)
216 print ' trace::localWriter.write%s(%s%s);' % (suffix, instance, length)
218 def visitConst(self, const, instance):
219 self.visit(const.type, instance)
221 def visitStruct(self, struct, instance):
222 print ' trace::localWriter.beginStruct(&_struct%s_sig);' % (struct.tag,)
223 for type, name in struct.members:
225 # Anonymous structure/union member
226 memberInstance = instance
228 memberInstance = '(%s).%s' % (instance, name)
229 self.visitMember(instance, type, memberInstance)
230 print ' trace::localWriter.endStruct();'
232 def visitArray(self, array, instance):
233 length = '_c' + array.type.tag
234 index = '_i' + array.type.tag
235 array_length = self.expand(array.length)
236 print ' if (%s) {' % instance
237 print ' size_t %s = %s > 0 ? %s : 0;' % (length, array_length, array_length)
238 print ' trace::localWriter.beginArray(%s);' % length
239 print ' for (size_t %s = 0; %s < %s; ++%s) {' % (index, index, length, index)
240 print ' trace::localWriter.beginElement();'
241 self.visitElement(index, array.type, '(%s)[%s]' % (instance, index))
242 print ' trace::localWriter.endElement();'
244 print ' trace::localWriter.endArray();'
246 print ' trace::localWriter.writeNull();'
249 def visitBlob(self, blob, instance):
250 print ' trace::localWriter.writeBlob(%s, %s);' % (instance, self.expand(blob.size))
252 def visitEnum(self, enum, instance):
253 print ' trace::localWriter.writeEnum(&_enum%s_sig, %s);' % (enum.tag, instance)
255 def visitBitmask(self, bitmask, instance):
256 print ' trace::localWriter.writeBitmask(&_bitmask%s_sig, %s);' % (bitmask.tag, instance)
258 def visitPointer(self, pointer, instance):
259 print ' if (%s) {' % instance
260 print ' trace::localWriter.beginArray(1);'
261 print ' trace::localWriter.beginElement();'
262 self.visit(pointer.type, "*" + instance)
263 print ' trace::localWriter.endElement();'
264 print ' trace::localWriter.endArray();'
266 print ' trace::localWriter.writeNull();'
269 def visitIntPointer(self, pointer, instance):
270 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
272 def visitObjPointer(self, pointer, instance):
273 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
275 def visitLinearPointer(self, pointer, instance):
276 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
278 def visitReference(self, reference, instance):
279 self.visit(reference.type, instance)
281 def visitHandle(self, handle, instance):
282 self.visit(handle.type, instance)
284 def visitAlias(self, alias, instance):
285 self.visit(alias.type, instance)
287 def visitOpaque(self, opaque, instance):
288 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
290 def visitInterface(self, interface, instance):
293 def visitPolymorphic(self, polymorphic, instance):
294 if polymorphic.contextLess:
295 print ' _write__%s(%s, %s);' % (polymorphic.tag, polymorphic.switchExpr, instance)
297 print ' switch (%s) {' % self.expand(polymorphic.switchExpr)
298 for cases, type in polymorphic.iterSwitch():
301 caseInstance = instance
302 if type.expr is not None:
303 caseInstance = 'static_cast<%s>(%s)' % (type, caseInstance)
304 self.visit(type, caseInstance)
309 class WrapDecider(stdapi.Traverser):
310 '''Type visitor which will decide wheter this type will need wrapping or not.
312 For complex types (arrays, structures), we need to know this before hand.
316 self.needsWrapping = False
318 def visitLinearPointer(self, void):
321 def visitInterface(self, interface):
322 self.needsWrapping = True
325 class ValueWrapper(stdapi.Traverser, ExpanderMixin):
326 '''Type visitor which will generate the code to wrap an instance.
328 Wrapping is necessary mostly for interfaces, however interface pointers can
329 appear anywhere inside complex types.
332 def visitStruct(self, struct, instance):
333 for type, name in struct.members:
335 # Anonymous structure/union member
336 memberInstance = instance
338 memberInstance = '(%s).%s' % (instance, name)
339 self.visitMember(instance, type, memberInstance)
341 def visitArray(self, array, instance):
342 array_length = self.expand(array.length)
343 print " if (%s) {" % instance
344 print " for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array_length
345 self.visitElement('_i', array.type, instance + "[_i]")
349 def visitPointer(self, pointer, instance):
350 print " if (%s) {" % instance
351 self.visit(pointer.type, "*" + instance)
354 def visitObjPointer(self, pointer, instance):
355 elem_type = pointer.type.mutable()
356 if isinstance(elem_type, stdapi.Interface):
357 self.visitInterfacePointer(elem_type, instance)
358 elif isinstance(elem_type, stdapi.Alias) and isinstance(elem_type.type, stdapi.Interface):
359 self.visitInterfacePointer(elem_type.type, instance)
361 self.visitPointer(pointer, instance)
363 def visitInterface(self, interface, instance):
364 raise NotImplementedError
366 def visitInterfacePointer(self, interface, instance):
367 print " if (%s) {" % instance
368 print " %s = new %s(%s);" % (instance, getWrapperInterfaceName(interface), instance)
371 def visitPolymorphic(self, type, instance):
372 # XXX: There might be polymorphic values that need wrapping in the future
373 raise NotImplementedError
376 class ValueUnwrapper(ValueWrapper):
377 '''Reverse of ValueWrapper.'''
381 def visitStruct(self, struct, instance):
382 if not self.allocated:
383 # Argument is constant. We need to create a non const
385 print " %s * _t = static_cast<%s *>(alloca(sizeof *_t));" % (struct, struct)
386 print ' *_t = %s;' % (instance,)
387 assert instance.startswith('*')
388 print ' %s = _t;' % (instance[1:],)
390 self.allocated = True
392 return ValueWrapper.visitStruct(self, struct, instance)
396 return ValueWrapper.visitStruct(self, struct, instance)
398 def visitArray(self, array, instance):
399 if self.allocated or isinstance(instance, stdapi.Interface):
400 return ValueWrapper.visitArray(self, array, instance)
401 array_length = self.expand(array.length)
402 elem_type = array.type.mutable()
403 print " if (%s && %s) {" % (instance, array_length)
404 print " %s * _t = static_cast<%s *>(alloca(%s * sizeof *_t));" % (elem_type, elem_type, array_length)
405 print " for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array_length
406 print " _t[_i] = %s[_i];" % instance
407 self.allocated = True
408 self.visit(array.type, "_t[_i]")
410 print " %s = _t;" % instance
413 def visitInterfacePointer(self, interface, instance):
414 print r' if (%s) {' % instance
415 print r' const %s *pWrapper = static_cast<const %s*>(%s);' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), instance)
416 print r' if (pWrapper && pWrapper->m_dwMagic == 0xd8365d6c) {'
417 print r' %s = pWrapper->m_pInstance;' % (instance,)
419 print r' os::log("apitrace: warning: %%s: unexpected %%s pointer\n", __FUNCTION__, "%s");' % interface.name
425 '''Base class to orchestrate the code generation of API tracing.'''
430 def serializerFactory(self):
431 '''Create a serializer.
433 Can be overriden by derived classes to inject their own serialzer.
436 return ValueSerializer()
438 def traceApi(self, api):
444 for module in api.modules:
445 for header in module.headers:
449 # Generate the serializer functions
450 types = api.getAllTypes()
451 visitor = ComplexValueSerializer(self.serializerFactory())
452 map(visitor.visit, types)
456 self.traceInterfaces(api)
459 self.interface = None
461 for function in api.getAllFunctions():
462 self.traceFunctionDecl(function)
463 for function in api.getAllFunctions():
464 self.traceFunctionImpl(function)
469 def header(self, api):
470 print '#ifdef _WIN32'
471 print '# include <malloc.h> // alloca'
472 print '# ifndef alloca'
473 print '# define alloca _alloca'
476 print '# include <alloca.h> // alloca'
479 print '#include "trace.hpp"'
482 def footer(self, api):
485 def traceFunctionDecl(self, function):
486 # Per-function declarations
488 if not function.internal:
490 print 'static const char * _%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args]))
492 print 'static const char ** _%s_args = NULL;' % (function.name,)
493 print 'static const trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, function.id, function.name, len(function.args), function.name)
496 def isFunctionPublic(self, function):
499 def traceFunctionImpl(self, function):
500 if self.isFunctionPublic(function):
501 print 'extern "C" PUBLIC'
503 print 'extern "C" PRIVATE'
504 print function.prototype() + ' {'
505 if function.type is not stdapi.Void:
506 print ' %s _result;' % function.type
508 # No-op if tracing is disabled
509 print ' if (!trace::isTracingEnabled()) {'
510 Tracer.invokeFunction(self, function)
511 if function.type is not stdapi.Void:
512 print ' return _result;'
517 self.traceFunctionImplBody(function)
518 if function.type is not stdapi.Void:
519 print ' return _result;'
523 def traceFunctionImplBody(self, function):
524 if not function.internal:
525 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
526 for arg in function.args:
528 self.unwrapArg(function, arg)
529 self.serializeArg(function, arg)
530 print ' trace::localWriter.endEnter();'
531 self.invokeFunction(function)
532 if not function.internal:
533 print ' trace::localWriter.beginLeave(_call);'
534 print ' if (%s) {' % self.wasFunctionSuccessful(function)
535 for arg in function.args:
537 self.serializeArg(function, arg)
538 self.wrapArg(function, arg)
540 if function.type is not stdapi.Void:
541 self.serializeRet(function, "_result")
542 print ' trace::localWriter.endLeave();'
543 if function.type is not stdapi.Void:
544 self.wrapRet(function, "_result")
546 def invokeFunction(self, function, prefix='_', suffix=''):
547 if function.type is stdapi.Void:
550 result = '_result = '
551 dispatch = prefix + function.name + suffix
552 print ' %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
554 def wasFunctionSuccessful(self, function):
555 if function.type is stdapi.Void:
557 if str(function.type) == 'HRESULT':
558 return 'SUCCEEDED(_result)'
561 def serializeArg(self, function, arg):
562 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
563 self.serializeArgValue(function, arg)
564 print ' trace::localWriter.endArg();'
566 def serializeArgValue(self, function, arg):
567 self.serializeValue(arg.type, arg.name)
569 def wrapArg(self, function, arg):
570 assert not isinstance(arg.type, stdapi.ObjPointer)
572 from specs.winapi import REFIID
574 for other_arg in function.args:
575 if not other_arg.output and other_arg.type is REFIID:
577 if riid is not None \
578 and isinstance(arg.type, stdapi.Pointer) \
579 and isinstance(arg.type.type, stdapi.ObjPointer):
580 self.wrapIid(function, riid, arg)
583 self.wrapValue(arg.type, arg.name)
585 def unwrapArg(self, function, arg):
586 self.unwrapValue(arg.type, arg.name)
588 def serializeRet(self, function, instance):
589 print ' trace::localWriter.beginReturn();'
590 self.serializeValue(function.type, instance)
591 print ' trace::localWriter.endReturn();'
593 def serializeValue(self, type, instance):
594 serializer = self.serializerFactory()
595 serializer.visit(type, instance)
597 def wrapRet(self, function, instance):
598 self.wrapValue(function.type, instance)
600 def unwrapRet(self, function, instance):
601 self.unwrapValue(function.type, instance)
603 def needsWrapping(self, type):
604 visitor = WrapDecider()
606 return visitor.needsWrapping
608 def wrapValue(self, type, instance):
609 if self.needsWrapping(type):
610 visitor = ValueWrapper()
611 visitor.visit(type, instance)
613 def unwrapValue(self, type, instance):
614 if self.needsWrapping(type):
615 visitor = ValueUnwrapper()
616 visitor.visit(type, instance)
618 def traceInterfaces(self, api):
619 interfaces = api.getAllInterfaces()
622 map(self.declareWrapperInterface, interfaces)
623 self.implementIidWrapper(api)
624 map(self.implementWrapperInterface, interfaces)
627 def declareWrapperInterface(self, interface):
628 print "class %s : public %s " % (getWrapperInterfaceName(interface), interface.name)
631 print " %s(%s * pInstance);" % (getWrapperInterfaceName(interface), interface.name)
632 print " virtual ~%s();" % getWrapperInterfaceName(interface)
634 for method in interface.iterMethods():
635 print " " + method.prototype() + ";"
638 for type, name, value in self.enumWrapperInterfaceVariables(interface):
639 print ' %s %s;' % (type, name)
643 def enumWrapperInterfaceVariables(self, interface):
645 ("DWORD", "m_dwMagic", "0xd8365d6c"),
646 ("%s *" % interface.name, "m_pInstance", "pInstance"),
649 def implementWrapperInterface(self, interface):
650 self.interface = interface
652 print '%s::%s(%s * pInstance) {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), interface.name)
653 for type, name, value in self.enumWrapperInterfaceVariables(interface):
654 print ' %s = %s;' % (name, value)
657 print '%s::~%s() {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface))
661 for base, method in interface.iterBaseMethods():
663 self.implementWrapperInterfaceMethod(interface, base, method)
667 def implementWrapperInterfaceMethod(self, interface, base, method):
668 print method.prototype(getWrapperInterfaceName(interface) + '::' + method.name) + ' {'
669 if method.type is not stdapi.Void:
670 print ' %s _result;' % method.type
672 self.implementWrapperInterfaceMethodBody(interface, base, method)
674 if method.type is not stdapi.Void:
675 print ' return _result;'
679 def implementWrapperInterfaceMethodBody(self, interface, base, method):
680 assert not method.internal
682 print ' static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args]))
683 print ' static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (method.id, interface.name + '::' + method.name, len(method.args) + 1)
685 print ' %s *_this = static_cast<%s *>(m_pInstance);' % (base, base)
687 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
688 print ' trace::localWriter.beginArg(0);'
689 print ' trace::localWriter.writePointer((uintptr_t)m_pInstance);'
690 print ' trace::localWriter.endArg();'
691 for arg in method.args:
693 self.unwrapArg(method, arg)
694 self.serializeArg(method, arg)
695 print ' trace::localWriter.endEnter();'
697 self.invokeMethod(interface, base, method)
699 print ' trace::localWriter.beginLeave(_call);'
701 print ' if (%s) {' % self.wasFunctionSuccessful(method)
702 for arg in method.args:
704 self.serializeArg(method, arg)
705 self.wrapArg(method, arg)
708 if method.type is not stdapi.Void:
709 self.serializeRet(method, '_result')
710 print ' trace::localWriter.endLeave();'
711 if method.type is not stdapi.Void:
712 self.wrapRet(method, '_result')
714 if method.name == 'Release':
715 assert method.type is not stdapi.Void
716 print ' if (!_result)'
717 print ' delete this;'
719 def implementIidWrapper(self, api):
721 print r'warnIID(const char *functionName, REFIID riid, const char *reason) {'
722 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",'
723 print r' functionName, reason,'
724 print r' riid.Data1, riid.Data2, riid.Data3,'
725 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]);'
729 print r'wrapIID(const char *functionName, REFIID riid, void * * ppvObj) {'
730 print r' if (!ppvObj || !*ppvObj) {'
734 for iface in api.getAllInterfaces():
735 print r' %sif (riid == IID_%s) {' % (else_, iface.name)
736 print r' *ppvObj = new Wrap%s((%s *) *ppvObj);' % (iface.name, iface.name)
739 print r' %s{' % else_
740 print r' warnIID(functionName, riid, "unknown");'
745 def wrapIid(self, function, riid, out):
746 # Cast output arg to `void **` if necessary
748 obj_type = out.type.type.type
749 if not obj_type is stdapi.Void:
750 assert isinstance(obj_type, stdapi.Interface)
751 out_name = 'reinterpret_cast<void * *>(%s)' % out_name
753 print r' if (%s && *%s) {' % (out.name, out.name)
754 functionName = function.name
756 if self.interface is not None:
757 functionName = self.interface.name + '::' + functionName
758 print r' if (*%s == m_pInstance &&' % (out_name,)
759 print r' (%s)) {' % ' || '.join('%s == IID_%s' % (riid.name, iface.name) for iface in self.interface.iterBases())
760 print r' *%s = this;' % (out_name,)
763 print r' %s{' % else_
764 print r' wrapIID("%s", %s, %s);' % (functionName, riid.name, out_name)
768 def invokeMethod(self, interface, base, method):
769 if method.type is stdapi.Void:
772 result = '_result = '
773 print ' %s_this->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args]))
775 def emit_memcpy(self, dest, src, length):
776 print ' unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
777 print ' trace::localWriter.beginArg(0);'
778 print ' trace::localWriter.writePointer((uintptr_t)%s);' % dest
779 print ' trace::localWriter.endArg();'
780 print ' trace::localWriter.beginArg(1);'
781 print ' trace::localWriter.writeBlob(%s, %s);' % (src, length)
782 print ' trace::localWriter.endArg();'
783 print ' trace::localWriter.beginArg(2);'
784 print ' trace::localWriter.writeUInt(%s);' % length
785 print ' trace::localWriter.endArg();'
786 print ' trace::localWriter.endEnter();'
787 print ' trace::localWriter.beginLeave(_call);'
788 print ' trace::localWriter.endLeave();'
790 def fake_call(self, function, args):
791 print ' unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
792 for arg, instance in zip(function.args, args):
793 assert not arg.output
794 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
795 self.serializeValue(arg.type, instance)
796 print ' trace::localWriter.endArg();'
797 print ' trace::localWriter.endEnter();'
798 print ' trace::localWriter.beginLeave(_fake_call);'
799 print ' trace::localWriter.endLeave();'