• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3#
4# Copyright 2012 the V8 project authors. All rights reserved.
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9#     * Redistributions of source code must retain the above copyright
10#       notice, this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above
12#       copyright notice, this list of conditions and the following
13#       disclaimer in the documentation and/or other materials provided
14#       with the distribution.
15#     * Neither the name of Google Inc. nor the names of its
16#       contributors may be used to endorse or promote products derived
17#       from this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30#
31
32#
33# Emits a C++ file to be compiled and linked into libv8 to support postmortem
34# debugging tools.  Most importantly, this tool emits constants describing V8
35# internals:
36#
37#    v8dbg_type_CLASS__TYPE = VALUE             Describes class type values
38#    v8dbg_class_CLASS__FIELD__TYPE = OFFSET    Describes class fields
39#    v8dbg_parent_CLASS__PARENT                 Describes class hierarchy
40#    v8dbg_frametype_NAME = VALUE               Describes stack frame values
41#    v8dbg_off_fp_NAME = OFFSET                 Frame pointer offsets
42#    v8dbg_prop_NAME = OFFSET                   Object property offsets
43#    v8dbg_NAME = VALUE                         Miscellaneous values
44#
45# These constants are declared as global integers so that they'll be present in
46# the generated libv8 binary.
47#
48
49import re
50import sys
51
52#
53# Miscellaneous constants such as tags and masks used for object identification,
54# enumeration values used as indexes in internal tables, etc..
55#
56consts_misc = [
57    { 'name': 'FirstNonstringType',     'value': 'FIRST_NONSTRING_TYPE' },
58
59    { 'name': 'IsNotStringMask',        'value': 'kIsNotStringMask' },
60    { 'name': 'StringTag',              'value': 'kStringTag' },
61    { 'name': 'NotStringTag',           'value': 'kNotStringTag' },
62
63    { 'name': 'StringEncodingMask',     'value': 'kStringEncodingMask' },
64    { 'name': 'TwoByteStringTag',       'value': 'kTwoByteStringTag' },
65    { 'name': 'OneByteStringTag',       'value': 'kOneByteStringTag' },
66
67    { 'name': 'StringRepresentationMask',
68        'value': 'kStringRepresentationMask' },
69    { 'name': 'SeqStringTag',           'value': 'kSeqStringTag' },
70    { 'name': 'ConsStringTag',          'value': 'kConsStringTag' },
71    { 'name': 'ExternalStringTag',      'value': 'kExternalStringTag' },
72    { 'name': 'SlicedStringTag',        'value': 'kSlicedStringTag' },
73
74    { 'name': 'HeapObjectTag',          'value': 'kHeapObjectTag' },
75    { 'name': 'HeapObjectTagMask',      'value': 'kHeapObjectTagMask' },
76    { 'name': 'SmiTag',                 'value': 'kSmiTag' },
77    { 'name': 'SmiTagMask',             'value': 'kSmiTagMask' },
78    { 'name': 'SmiValueShift',          'value': 'kSmiTagSize' },
79    { 'name': 'SmiShiftSize',           'value': 'kSmiShiftSize' },
80    { 'name': 'PointerSizeLog2',        'value': 'kPointerSizeLog2' },
81
82    { 'name': 'OddballFalse',           'value': 'Oddball::kFalse' },
83    { 'name': 'OddballTrue',            'value': 'Oddball::kTrue' },
84    { 'name': 'OddballTheHole',         'value': 'Oddball::kTheHole' },
85    { 'name': 'OddballNull',            'value': 'Oddball::kNull' },
86    { 'name': 'OddballArgumentsMarker', 'value': 'Oddball::kArgumentsMarker' },
87    { 'name': 'OddballUndefined',       'value': 'Oddball::kUndefined' },
88    { 'name': 'OddballUninitialized',   'value': 'Oddball::kUninitialized' },
89    { 'name': 'OddballOther',           'value': 'Oddball::kOther' },
90    { 'name': 'OddballException',       'value': 'Oddball::kException' },
91
92    { 'name': 'prop_idx_first',
93        'value': 'DescriptorArray::kFirstIndex' },
94    { 'name': 'prop_type_field',
95        'value': 'DATA' },
96    { 'name': 'prop_type_const_field',
97        'value': 'DATA_CONSTANT' },
98    { 'name': 'prop_type_mask',
99        'value': 'PropertyDetails::TypeField::kMask' },
100    { 'name': 'prop_index_mask',
101        'value': 'PropertyDetails::FieldIndexField::kMask' },
102    { 'name': 'prop_index_shift',
103        'value': 'PropertyDetails::FieldIndexField::kShift' },
104    { 'name': 'prop_representation_mask',
105        'value': 'PropertyDetails::RepresentationField::kMask' },
106    { 'name': 'prop_representation_shift',
107        'value': 'PropertyDetails::RepresentationField::kShift' },
108    { 'name': 'prop_representation_integer8',
109        'value': 'Representation::Kind::kInteger8' },
110    { 'name': 'prop_representation_uinteger8',
111        'value': 'Representation::Kind::kUInteger8' },
112    { 'name': 'prop_representation_integer16',
113        'value': 'Representation::Kind::kInteger16' },
114    { 'name': 'prop_representation_uinteger16',
115        'value': 'Representation::Kind::kUInteger16' },
116    { 'name': 'prop_representation_smi',
117        'value': 'Representation::Kind::kSmi' },
118    { 'name': 'prop_representation_integer32',
119        'value': 'Representation::Kind::kInteger32' },
120    { 'name': 'prop_representation_double',
121        'value': 'Representation::Kind::kDouble' },
122    { 'name': 'prop_representation_heapobject',
123        'value': 'Representation::Kind::kHeapObject' },
124    { 'name': 'prop_representation_tagged',
125        'value': 'Representation::Kind::kTagged' },
126    { 'name': 'prop_representation_external',
127        'value': 'Representation::Kind::kExternal' },
128
129    { 'name': 'prop_desc_key',
130        'value': 'DescriptorArray::kDescriptorKey' },
131    { 'name': 'prop_desc_details',
132        'value': 'DescriptorArray::kDescriptorDetails' },
133    { 'name': 'prop_desc_value',
134        'value': 'DescriptorArray::kDescriptorValue' },
135    { 'name': 'prop_desc_size',
136        'value': 'DescriptorArray::kDescriptorSize' },
137
138    { 'name': 'elements_fast_holey_elements',
139        'value': 'FAST_HOLEY_ELEMENTS' },
140    { 'name': 'elements_fast_elements',
141        'value': 'FAST_ELEMENTS' },
142    { 'name': 'elements_dictionary_elements',
143        'value': 'DICTIONARY_ELEMENTS' },
144
145    { 'name': 'bit_field2_elements_kind_mask',
146        'value': 'Map::ElementsKindBits::kMask' },
147    { 'name': 'bit_field2_elements_kind_shift',
148        'value': 'Map::ElementsKindBits::kShift' },
149    { 'name': 'bit_field3_dictionary_map_shift',
150        'value': 'Map::DictionaryMap::kShift' },
151    { 'name': 'bit_field3_number_of_own_descriptors_mask',
152        'value': 'Map::NumberOfOwnDescriptorsBits::kMask' },
153    { 'name': 'bit_field3_number_of_own_descriptors_shift',
154        'value': 'Map::NumberOfOwnDescriptorsBits::kShift' },
155
156    { 'name': 'off_fp_context',
157        'value': 'StandardFrameConstants::kContextOffset' },
158    { 'name': 'off_fp_constant_pool',
159        'value': 'StandardFrameConstants::kConstantPoolOffset' },
160    { 'name': 'off_fp_function',
161        'value': 'JavaScriptFrameConstants::kFunctionOffset' },
162    { 'name': 'off_fp_args',
163        'value': 'JavaScriptFrameConstants::kLastParameterOffset' },
164
165    { 'name': 'scopeinfo_idx_nparams',
166        'value': 'ScopeInfo::kParameterCount' },
167    { 'name': 'scopeinfo_idx_nstacklocals',
168        'value': 'ScopeInfo::kStackLocalCount' },
169    { 'name': 'scopeinfo_idx_ncontextlocals',
170        'value': 'ScopeInfo::kContextLocalCount' },
171    { 'name': 'scopeinfo_idx_ncontextglobals',
172        'value': 'ScopeInfo::kContextGlobalCount' },
173    { 'name': 'scopeinfo_idx_first_vars',
174        'value': 'ScopeInfo::kVariablePartIndex' },
175
176    { 'name': 'sharedfunctioninfo_start_position_mask',
177        'value': 'SharedFunctionInfo::kStartPositionMask' },
178    { 'name': 'sharedfunctioninfo_start_position_shift',
179        'value': 'SharedFunctionInfo::kStartPositionShift' },
180
181    { 'name': 'jsarray_buffer_was_neutered_mask',
182        'value': 'JSArrayBuffer::WasNeutered::kMask' },
183    { 'name': 'jsarray_buffer_was_neutered_shift',
184        'value': 'JSArrayBuffer::WasNeutered::kShift' },
185
186    { 'name': 'context_idx_closure',
187        'value': 'Context::CLOSURE_INDEX' },
188    { 'name': 'context_idx_native',
189        'value': 'Context::NATIVE_CONTEXT_INDEX' },
190    { 'name': 'context_idx_prev',
191        'value': 'Context::PREVIOUS_INDEX' },
192    { 'name': 'context_idx_ext',
193        'value': 'Context::EXTENSION_INDEX' },
194    { 'name': 'context_min_slots',
195        'value': 'Context::MIN_CONTEXT_SLOTS' },
196
197    { 'name': 'namedictionaryshape_prefix_size',
198        'value': 'NameDictionaryShape::kPrefixSize' },
199    { 'name': 'namedictionaryshape_entry_size',
200        'value': 'NameDictionaryShape::kEntrySize' },
201
202    { 'name': 'namedictionary_prefix_start_index',
203        'value': 'NameDictionary::kPrefixStartIndex' },
204
205    { 'name': 'seedednumberdictionaryshape_prefix_size',
206        'value': 'SeededNumberDictionaryShape::kPrefixSize' },
207
208    { 'name': 'unseedednumberdictionaryshape_prefix_size',
209        'value': 'UnseededNumberDictionaryShape::kPrefixSize' },
210
211    { 'name': 'numberdictionaryshape_entry_size',
212        'value': 'NumberDictionaryShape::kEntrySize' }
213];
214
215#
216# The following useful fields are missing accessors, so we define fake ones.
217# Please note that extra accessors should _only_ be added to expose offsets that
218# can be used to access actual V8 objects' properties. They should not be added
219# for exposing other values. For instance, enumeration values or class'
220# constants should be exposed by adding an entry in the "consts_misc" table, not
221# in this "extras_accessors" table.
222#
223extras_accessors = [
224    'JSFunction, context, Context, kContextOffset',
225    'HeapObject, map, Map, kMapOffset',
226    'JSObject, elements, Object, kElementsOffset',
227    'FixedArray, data, uintptr_t, kHeaderSize',
228    'JSArrayBuffer, backing_store, Object, kBackingStoreOffset',
229    'JSArrayBufferView, byte_offset, Object, kByteOffsetOffset',
230    'JSTypedArray, length, Object, kLengthOffset',
231    'Map, instance_attributes, int, kInstanceAttributesOffset',
232    'Map, inobject_properties_or_constructor_function_index, int, kInObjectPropertiesOrConstructorFunctionIndexOffset',
233    'Map, instance_size, int, kInstanceSizeOffset',
234    'Map, bit_field, char, kBitFieldOffset',
235    'Map, bit_field2, char, kBitField2Offset',
236    'Map, bit_field3, int, kBitField3Offset',
237    'Map, prototype, Object, kPrototypeOffset',
238    'Oddball, kind_offset, int, kKindOffset',
239    'HeapNumber, value, double, kValueOffset',
240    'ConsString, first, String, kFirstOffset',
241    'ConsString, second, String, kSecondOffset',
242    'ExternalString, resource, Object, kResourceOffset',
243    'SeqOneByteString, chars, char, kHeaderSize',
244    'SeqTwoByteString, chars, char, kHeaderSize',
245    'SharedFunctionInfo, code, Code, kCodeOffset',
246    'SharedFunctionInfo, scope_info, ScopeInfo, kScopeInfoOffset',
247    'SlicedString, parent, String, kParentOffset',
248    'Code, instruction_start, uintptr_t, kHeaderSize',
249    'Code, instruction_size, int, kInstructionSizeOffset',
250];
251
252#
253# The following is a whitelist of classes we expect to find when scanning the
254# source code. This list is not exhaustive, but it's still useful to identify
255# when this script gets out of sync with the source. See load_objects().
256#
257expected_classes = [
258    'ConsString', 'FixedArray', 'HeapNumber', 'JSArray', 'JSFunction',
259    'JSObject', 'JSRegExp', 'JSValue', 'Map', 'Oddball', 'Script',
260    'SeqOneByteString', 'SharedFunctionInfo'
261];
262
263
264#
265# The following structures store high-level representations of the structures
266# for which we're going to emit descriptive constants.
267#
268types = {};             # set of all type names
269typeclasses = {};       # maps type names to corresponding class names
270klasses = {};           # known classes, including parents
271fields = [];            # field declarations
272
273header = '''
274/*
275 * This file is generated by %s.  Do not edit directly.
276 */
277
278#include "src/v8.h"
279#include "src/frames.h"
280#include "src/frames-inl.h" /* for architecture-specific frame constants */
281#include "src/contexts.h"
282
283using namespace v8::internal;
284
285extern "C" {
286
287/* stack frame constants */
288#define FRAME_CONST(value, klass)       \
289    int v8dbg_frametype_##klass = StackFrame::value;
290
291STACK_FRAME_TYPE_LIST(FRAME_CONST)
292
293#undef FRAME_CONST
294
295''' % sys.argv[0];
296
297footer = '''
298}
299'''
300
301#
302# Get the base class
303#
304def get_base_class(klass):
305        if (klass == 'Object'):
306                return klass;
307
308        if (not (klass in klasses)):
309                return None;
310
311        k = klasses[klass];
312
313        return get_base_class(k['parent']);
314
315#
316# Loads class hierarchy and type information from "objects.h".
317#
318def load_objects():
319        objfilename = sys.argv[2];
320        objfile = open(objfilename, 'r');
321        in_insttype = False;
322
323        typestr = '';
324
325        #
326        # Construct a dictionary for the classes we're sure should be present.
327        #
328        checktypes = {};
329        for klass in expected_classes:
330                checktypes[klass] = True;
331
332        #
333        # Iterate objects.h line-by-line to collect type and class information.
334        # For types, we accumulate a string representing the entire InstanceType
335        # enum definition and parse it later because it's easier to do so
336        # without the embedded newlines.
337        #
338        for line in objfile:
339                if (line.startswith('enum InstanceType {')):
340                        in_insttype = True;
341                        continue;
342
343                if (in_insttype and line.startswith('};')):
344                        in_insttype = False;
345                        continue;
346
347                line = re.sub('//.*', '', line.strip());
348
349                if (in_insttype):
350                        typestr += line;
351                        continue;
352
353                match = re.match('class (\w[^:]*)(: public (\w[^{]*))?\s*{\s*',
354                    line);
355
356                if (match):
357                        klass = match.group(1).strip();
358                        pklass = match.group(3);
359                        if (pklass):
360                                pklass = pklass.strip();
361                        klasses[klass] = { 'parent': pklass };
362
363        #
364        # Process the instance type declaration.
365        #
366        entries = typestr.split(',');
367        for entry in entries:
368                types[re.sub('\s*=.*', '', entry).lstrip()] = True;
369
370        #
371        # Infer class names for each type based on a systematic transformation.
372        # For example, "JS_FUNCTION_TYPE" becomes "JSFunction".  We find the
373        # class for each type rather than the other way around because there are
374        # fewer cases where one type maps to more than one class than the other
375        # way around.
376        #
377        for type in types:
378                #
379                # Symbols and Strings are implemented using the same classes.
380                #
381                usetype = re.sub('SYMBOL_', 'STRING_', type);
382
383                #
384                # REGEXP behaves like REG_EXP, as in JS_REGEXP_TYPE => JSRegExp.
385                #
386                usetype = re.sub('_REGEXP_', '_REG_EXP_', usetype);
387
388                #
389                # Remove the "_TYPE" suffix and then convert to camel case,
390                # except that a "JS" prefix remains uppercase (as in
391                # "JS_FUNCTION_TYPE" => "JSFunction").
392                #
393                if (not usetype.endswith('_TYPE')):
394                        continue;
395
396                usetype = usetype[0:len(usetype) - len('_TYPE')];
397                parts = usetype.split('_');
398                cctype = '';
399
400                if (parts[0] == 'JS'):
401                        cctype = 'JS';
402                        start = 1;
403                else:
404                        cctype = '';
405                        start = 0;
406
407                for ii in range(start, len(parts)):
408                        part = parts[ii];
409                        cctype += part[0].upper() + part[1:].lower();
410
411                #
412                # Mapping string types is more complicated.  Both types and
413                # class names for Strings specify a representation (e.g., Seq,
414                # Cons, External, or Sliced) and an encoding (TwoByte/OneByte),
415                # In the simplest case, both of these are explicit in both
416                # names, as in:
417                #
418                #       EXTERNAL_ONE_BYTE_STRING_TYPE => ExternalOneByteString
419                #
420                # However, either the representation or encoding can be omitted
421                # from the type name, in which case "Seq" and "TwoByte" are
422                # assumed, as in:
423                #
424                #       STRING_TYPE => SeqTwoByteString
425                #
426                # Additionally, sometimes the type name has more information
427                # than the class, as in:
428                #
429                #       CONS_ONE_BYTE_STRING_TYPE => ConsString
430                #
431                # To figure this out dynamically, we first check for a
432                # representation and encoding and add them if they're not
433                # present.  If that doesn't yield a valid class name, then we
434                # strip out the representation.
435                #
436                if (cctype.endswith('String')):
437                        if (cctype.find('Cons') == -1 and
438                            cctype.find('External') == -1 and
439                            cctype.find('Sliced') == -1):
440                                if (cctype.find('OneByte') != -1):
441                                        cctype = re.sub('OneByteString$',
442                                            'SeqOneByteString', cctype);
443                                else:
444                                        cctype = re.sub('String$',
445                                            'SeqString', cctype);
446
447                        if (cctype.find('OneByte') == -1):
448                                cctype = re.sub('String$', 'TwoByteString',
449                                    cctype);
450
451                        if (not (cctype in klasses)):
452                                cctype = re.sub('OneByte', '', cctype);
453                                cctype = re.sub('TwoByte', '', cctype);
454
455                #
456                # Despite all that, some types have no corresponding class.
457                #
458                if (cctype in klasses):
459                        typeclasses[type] = cctype;
460                        if (cctype in checktypes):
461                                del checktypes[cctype];
462
463        if (len(checktypes) > 0):
464                for klass in checktypes:
465                        print('error: expected class \"%s\" not found' % klass);
466
467                sys.exit(1);
468
469
470#
471# For a given macro call, pick apart the arguments and return an object
472# describing the corresponding output constant.  See load_fields().
473#
474def parse_field(call):
475        # Replace newlines with spaces.
476        for ii in range(0, len(call)):
477                if (call[ii] == '\n'):
478                        call[ii] == ' ';
479
480        idx = call.find('(');
481        kind = call[0:idx];
482        rest = call[idx + 1: len(call) - 1];
483        args = re.split('\s*,\s*', rest);
484
485        consts = [];
486
487        if (kind == 'ACCESSORS' or kind == 'ACCESSORS_GCSAFE'):
488                klass = args[0];
489                field = args[1];
490                dtype = args[2];
491                offset = args[3];
492
493                return ({
494                    'name': 'class_%s__%s__%s' % (klass, field, dtype),
495                    'value': '%s::%s' % (klass, offset)
496                });
497
498        assert(kind == 'SMI_ACCESSORS' or kind == 'ACCESSORS_TO_SMI');
499        klass = args[0];
500        field = args[1];
501        offset = args[2];
502
503        return ({
504            'name': 'class_%s__%s__%s' % (klass, field, 'SMI'),
505            'value': '%s::%s' % (klass, offset)
506        });
507
508#
509# Load field offset information from objects-inl.h.
510#
511def load_fields():
512        inlfilename = sys.argv[3];
513        inlfile = open(inlfilename, 'r');
514
515        #
516        # Each class's fields and the corresponding offsets are described in the
517        # source by calls to macros like "ACCESSORS" (and friends).  All we do
518        # here is extract these macro invocations, taking into account that they
519        # may span multiple lines and may contain nested parentheses.  We also
520        # call parse_field() to pick apart the invocation.
521        #
522        prefixes = [ 'ACCESSORS', 'ACCESSORS_GCSAFE',
523                     'SMI_ACCESSORS', 'ACCESSORS_TO_SMI' ];
524        current = '';
525        opens = 0;
526
527        for line in inlfile:
528                if (opens > 0):
529                        # Continuation line
530                        for ii in range(0, len(line)):
531                                if (line[ii] == '('):
532                                        opens += 1;
533                                elif (line[ii] == ')'):
534                                        opens -= 1;
535
536                                if (opens == 0):
537                                        break;
538
539                        current += line[0:ii + 1];
540                        continue;
541
542                for prefix in prefixes:
543                        if (not line.startswith(prefix + '(')):
544                                continue;
545
546                        if (len(current) > 0):
547                                fields.append(parse_field(current));
548                                current = '';
549
550                        for ii in range(len(prefix), len(line)):
551                                if (line[ii] == '('):
552                                        opens += 1;
553                                elif (line[ii] == ')'):
554                                        opens -= 1;
555
556                                if (opens == 0):
557                                        break;
558
559                        current += line[0:ii + 1];
560
561        if (len(current) > 0):
562                fields.append(parse_field(current));
563                current = '';
564
565        for body in extras_accessors:
566                fields.append(parse_field('ACCESSORS(%s)' % body));
567
568#
569# Emit a block of constants.
570#
571def emit_set(out, consts):
572        # Fix up overzealous parses.  This could be done inside the
573        # parsers but as there are several, it's easiest to do it here.
574        ws = re.compile('\s+')
575        for const in consts:
576                name = ws.sub('', const['name'])
577                value = ws.sub('', str(const['value']))  # Can be a number.
578                out.write('int v8dbg_%s = %s;\n' % (name, value))
579        out.write('\n');
580
581#
582# Emit the whole output file.
583#
584def emit_config():
585        out = file(sys.argv[1], 'w');
586
587        out.write(header);
588
589        out.write('/* miscellaneous constants */\n');
590        emit_set(out, consts_misc);
591
592        out.write('/* class type information */\n');
593        consts = [];
594        keys = typeclasses.keys();
595        keys.sort();
596        for typename in keys:
597                klass = typeclasses[typename];
598                consts.append({
599                    'name': 'type_%s__%s' % (klass, typename),
600                    'value': typename
601                });
602
603        emit_set(out, consts);
604
605        out.write('/* class hierarchy information */\n');
606        consts = [];
607        keys = klasses.keys();
608        keys.sort();
609        for klassname in keys:
610                pklass = klasses[klassname]['parent'];
611                bklass = get_base_class(klassname);
612                if (bklass != 'Object'):
613                        continue;
614                if (pklass == None):
615                        continue;
616
617                consts.append({
618                    'name': 'parent_%s__%s' % (klassname, pklass),
619                    'value': 0
620                });
621
622        emit_set(out, consts);
623
624        out.write('/* field information */\n');
625        emit_set(out, fields);
626
627        out.write(footer);
628
629if (len(sys.argv) < 4):
630        print('usage: %s output.cc objects.h objects-inl.h' % sys.argv[0]);
631        sys.exit(2);
632
633load_objects();
634load_fields();
635emit_config();
636