• 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    { 'name': 'APIObjectType',          'value': 'JS_API_OBJECT_TYPE' },
59    { 'name': 'SpecialAPIObjectType',   'value': 'JS_SPECIAL_API_OBJECT_TYPE' },
60
61    { 'name': 'FirstContextType',     'value': 'FIRST_CONTEXT_TYPE' },
62    { 'name': 'LastContextType',     'value': 'LAST_CONTEXT_TYPE' },
63
64    { 'name': 'IsNotStringMask',        'value': 'kIsNotStringMask' },
65    { 'name': 'StringTag',              'value': 'kStringTag' },
66
67    { 'name': 'StringEncodingMask',     'value': 'kStringEncodingMask' },
68    { 'name': 'TwoByteStringTag',       'value': 'kTwoByteStringTag' },
69    { 'name': 'OneByteStringTag',       'value': 'kOneByteStringTag' },
70
71    { 'name': 'StringRepresentationMask',
72        'value': 'kStringRepresentationMask' },
73    { 'name': 'SeqStringTag',           'value': 'kSeqStringTag' },
74    { 'name': 'ConsStringTag',          'value': 'kConsStringTag' },
75    { 'name': 'ExternalStringTag',      'value': 'kExternalStringTag' },
76    { 'name': 'SlicedStringTag',        'value': 'kSlicedStringTag' },
77    { 'name': 'ThinStringTag',          'value': 'kThinStringTag' },
78
79    { 'name': 'HeapObjectTag',          'value': 'kHeapObjectTag' },
80    { 'name': 'HeapObjectTagMask',      'value': 'kHeapObjectTagMask' },
81    { 'name': 'SmiTag',                 'value': 'kSmiTag' },
82    { 'name': 'SmiTagMask',             'value': 'kSmiTagMask' },
83    { 'name': 'SmiValueShift',          'value': 'kSmiTagSize' },
84    { 'name': 'SmiShiftSize',           'value': 'kSmiShiftSize' },
85    { 'name': 'PointerSizeLog2',        'value': 'kPointerSizeLog2' },
86
87    { 'name': 'OddballFalse',           'value': 'Oddball::kFalse' },
88    { 'name': 'OddballTrue',            'value': 'Oddball::kTrue' },
89    { 'name': 'OddballTheHole',         'value': 'Oddball::kTheHole' },
90    { 'name': 'OddballNull',            'value': 'Oddball::kNull' },
91    { 'name': 'OddballArgumentsMarker', 'value': 'Oddball::kArgumentsMarker' },
92    { 'name': 'OddballUndefined',       'value': 'Oddball::kUndefined' },
93    { 'name': 'OddballUninitialized',   'value': 'Oddball::kUninitialized' },
94    { 'name': 'OddballOther',           'value': 'Oddball::kOther' },
95    { 'name': 'OddballException',       'value': 'Oddball::kException' },
96
97    { 'name': 'prop_idx_first',
98        'value': 'DescriptorArray::kFirstIndex' },
99    { 'name': 'prop_kind_Data',
100        'value': 'kData' },
101    { 'name': 'prop_kind_Accessor',
102        'value': 'kAccessor' },
103    { 'name': 'prop_kind_mask',
104        'value': 'PropertyDetails::KindField::kMask' },
105    { 'name': 'prop_location_Descriptor',
106        'value': 'kDescriptor' },
107    { 'name': 'prop_location_Field',
108        'value': 'kField' },
109    { 'name': 'prop_location_mask',
110        'value': 'PropertyDetails::LocationField::kMask' },
111    { 'name': 'prop_location_shift',
112        'value': 'PropertyDetails::LocationField::kShift' },
113    { 'name': 'prop_attributes_NONE', 'value': 'NONE' },
114    { 'name': 'prop_attributes_READ_ONLY', 'value': 'READ_ONLY' },
115    { 'name': 'prop_attributes_DONT_ENUM', 'value': 'DONT_ENUM' },
116    { 'name': 'prop_attributes_DONT_DELETE', 'value': 'DONT_DELETE' },
117    { 'name': 'prop_attributes_mask',
118        'value': 'PropertyDetails::AttributesField::kMask' },
119    { 'name': 'prop_attributes_shift',
120        'value': 'PropertyDetails::AttributesField::kShift' },
121    { 'name': 'prop_index_mask',
122        'value': 'PropertyDetails::FieldIndexField::kMask' },
123    { 'name': 'prop_index_shift',
124        'value': 'PropertyDetails::FieldIndexField::kShift' },
125    { 'name': 'prop_representation_mask',
126        'value': 'PropertyDetails::RepresentationField::kMask' },
127    { 'name': 'prop_representation_shift',
128        'value': 'PropertyDetails::RepresentationField::kShift' },
129    { 'name': 'prop_representation_integer8',
130        'value': 'Representation::Kind::kInteger8' },
131    { 'name': 'prop_representation_uinteger8',
132        'value': 'Representation::Kind::kUInteger8' },
133    { 'name': 'prop_representation_integer16',
134        'value': 'Representation::Kind::kInteger16' },
135    { 'name': 'prop_representation_uinteger16',
136        'value': 'Representation::Kind::kUInteger16' },
137    { 'name': 'prop_representation_smi',
138        'value': 'Representation::Kind::kSmi' },
139    { 'name': 'prop_representation_integer32',
140        'value': 'Representation::Kind::kInteger32' },
141    { 'name': 'prop_representation_double',
142        'value': 'Representation::Kind::kDouble' },
143    { 'name': 'prop_representation_heapobject',
144        'value': 'Representation::Kind::kHeapObject' },
145    { 'name': 'prop_representation_tagged',
146        'value': 'Representation::Kind::kTagged' },
147    { 'name': 'prop_representation_external',
148        'value': 'Representation::Kind::kExternal' },
149
150    { 'name': 'prop_desc_key',
151        'value': 'DescriptorArray::kEntryKeyIndex' },
152    { 'name': 'prop_desc_details',
153        'value': 'DescriptorArray::kEntryDetailsIndex' },
154    { 'name': 'prop_desc_value',
155        'value': 'DescriptorArray::kEntryValueIndex' },
156    { 'name': 'prop_desc_size',
157        'value': 'DescriptorArray::kEntrySize' },
158
159    { 'name': 'elements_fast_holey_elements',
160        'value': 'HOLEY_ELEMENTS' },
161    { 'name': 'elements_fast_elements',
162        'value': 'PACKED_ELEMENTS' },
163    { 'name': 'elements_dictionary_elements',
164        'value': 'DICTIONARY_ELEMENTS' },
165
166    { 'name': 'bit_field2_elements_kind_mask',
167        'value': 'Map::ElementsKindBits::kMask' },
168    { 'name': 'bit_field2_elements_kind_shift',
169        'value': 'Map::ElementsKindBits::kShift' },
170    { 'name': 'bit_field3_is_dictionary_map_shift',
171        'value': 'Map::IsDictionaryMapBit::kShift' },
172    { 'name': 'bit_field3_number_of_own_descriptors_mask',
173        'value': 'Map::NumberOfOwnDescriptorsBits::kMask' },
174    { 'name': 'bit_field3_number_of_own_descriptors_shift',
175        'value': 'Map::NumberOfOwnDescriptorsBits::kShift' },
176
177    { 'name': 'off_fp_context_or_frame_type',
178        'value': 'CommonFrameConstants::kContextOrFrameTypeOffset'},
179    { 'name': 'off_fp_context',
180        'value': 'StandardFrameConstants::kContextOffset' },
181    { 'name': 'off_fp_constant_pool',
182        'value': 'StandardFrameConstants::kConstantPoolOffset' },
183    { 'name': 'off_fp_function',
184        'value': 'JavaScriptFrameConstants::kFunctionOffset' },
185    { 'name': 'off_fp_args',
186        'value': 'JavaScriptFrameConstants::kLastParameterOffset' },
187
188    { 'name': 'scopeinfo_idx_nparams',
189        'value': 'ScopeInfo::kParameterCount' },
190    { 'name': 'scopeinfo_idx_ncontextlocals',
191        'value': 'ScopeInfo::kContextLocalCount' },
192    { 'name': 'scopeinfo_idx_first_vars',
193        'value': 'ScopeInfo::kVariablePartIndex' },
194
195    { 'name': 'jsarray_buffer_was_neutered_mask',
196        'value': 'JSArrayBuffer::WasNeutered::kMask' },
197    { 'name': 'jsarray_buffer_was_neutered_shift',
198        'value': 'JSArrayBuffer::WasNeutered::kShift' },
199
200    { 'name': 'context_idx_scope_info',
201        'value': 'Context::SCOPE_INFO_INDEX' },
202    { 'name': 'context_idx_native',
203        'value': 'Context::NATIVE_CONTEXT_INDEX' },
204    { 'name': 'context_idx_prev',
205        'value': 'Context::PREVIOUS_INDEX' },
206    { 'name': 'context_idx_ext',
207        'value': 'Context::EXTENSION_INDEX' },
208    { 'name': 'context_min_slots',
209        'value': 'Context::MIN_CONTEXT_SLOTS' },
210    { 'name': 'context_idx_embedder_data',
211        'value': 'Internals::kContextEmbedderDataIndex' },
212
213
214    { 'name': 'namedictionaryshape_prefix_size',
215        'value': 'NameDictionaryShape::kPrefixSize' },
216    { 'name': 'namedictionaryshape_entry_size',
217        'value': 'NameDictionaryShape::kEntrySize' },
218    { 'name': 'globaldictionaryshape_entry_size',
219        'value': 'GlobalDictionaryShape::kEntrySize' },
220
221    { 'name': 'namedictionary_prefix_start_index',
222        'value': 'NameDictionary::kPrefixStartIndex' },
223
224    { 'name': 'numberdictionaryshape_prefix_size',
225        'value': 'NumberDictionaryShape::kPrefixSize' },
226    { 'name': 'numberdictionaryshape_entry_size',
227        'value': 'NumberDictionaryShape::kEntrySize' },
228
229    { 'name': 'simplenumberdictionaryshape_prefix_size',
230        'value': 'SimpleNumberDictionaryShape::kPrefixSize' },
231    { 'name': 'simplenumberdictionaryshape_entry_size',
232        'value': 'SimpleNumberDictionaryShape::kEntrySize' },
233
234    { 'name': 'type_JSError__JS_ERROR_TYPE', 'value': 'JS_ERROR_TYPE' },
235];
236
237#
238# The following useful fields are missing accessors, so we define fake ones.
239# Please note that extra accessors should _only_ be added to expose offsets that
240# can be used to access actual V8 objects' properties. They should not be added
241# for exposing other values. For instance, enumeration values or class'
242# constants should be exposed by adding an entry in the "consts_misc" table, not
243# in this "extras_accessors" table.
244#
245extras_accessors = [
246    'JSFunction, context, Context, kContextOffset',
247    'HeapObject, map, Map, kMapOffset',
248    'JSObject, elements, Object, kElementsOffset',
249    'JSObject, internal_fields, uintptr_t, kHeaderSize',
250    'FixedArray, data, uintptr_t, kHeaderSize',
251    'FixedTypedArrayBase, external_pointer, Object, kExternalPointerOffset',
252    'JSArrayBuffer, backing_store, Object, kBackingStoreOffset',
253    'JSArrayBufferView, byte_offset, Object, kByteOffsetOffset',
254    'JSTypedArray, length, Object, kLengthOffset',
255    'Map, instance_size_in_words, char, kInstanceSizeInWordsOffset',
256    'Map, inobject_properties_start_or_constructor_function_index, char, kInObjectPropertiesStartOrConstructorFunctionIndexOffset',
257    'Map, instance_type, uint16_t, kInstanceTypeOffset',
258    'Map, bit_field, char, kBitFieldOffset',
259    'Map, bit_field2, char, kBitField2Offset',
260    'Map, bit_field3, int, kBitField3Offset',
261    'Map, prototype, Object, kPrototypeOffset',
262    'Oddball, kind_offset, int, kKindOffset',
263    'HeapNumber, value, double, kValueOffset',
264    'ConsString, first, String, kFirstOffset',
265    'ConsString, second, String, kSecondOffset',
266    'ExternalString, resource, Object, kResourceOffset',
267    'SeqOneByteString, chars, char, kHeaderSize',
268    'SeqTwoByteString, chars, char, kHeaderSize',
269    'UncompiledData, start_position, int32_t, kStartPositionOffset',
270    'UncompiledData, end_position, int32_t, kEndPositionOffset',
271    'SharedFunctionInfo, raw_function_token_offset, int16_t, kFunctionTokenOffsetOffset',
272    'SharedFunctionInfo, internal_formal_parameter_count, uint16_t, kFormalParameterCountOffset',
273    'SharedFunctionInfo, flags, int, kFlagsOffset',
274    'SharedFunctionInfo, length, uint16_t, kLengthOffset',
275    'SlicedString, parent, String, kParentOffset',
276    'Code, instruction_start, uintptr_t, kHeaderSize',
277    'Code, instruction_size, int, kInstructionSizeOffset',
278];
279
280#
281# The following is a whitelist of classes we expect to find when scanning the
282# source code. This list is not exhaustive, but it's still useful to identify
283# when this script gets out of sync with the source. See load_objects().
284#
285expected_classes = [
286    'ConsString', 'FixedArray', 'HeapNumber', 'JSArray', 'JSFunction',
287    'JSObject', 'JSRegExp', 'JSValue', 'Map', 'Oddball', 'Script',
288    'SeqOneByteString', 'SharedFunctionInfo', 'ScopeInfo'
289];
290
291
292#
293# The following structures store high-level representations of the structures
294# for which we're going to emit descriptive constants.
295#
296types = {};             # set of all type names
297typeclasses = {};       # maps type names to corresponding class names
298klasses = {};           # known classes, including parents
299fields = [];            # field declarations
300
301header = '''
302/*
303 * This file is generated by %s.  Do not edit directly.
304 */
305
306#include "src/v8.h"
307#include "src/frames.h"
308#include "src/frames-inl.h" /* for architecture-specific frame constants */
309#include "src/contexts.h"
310#include "src/objects.h"
311#include "src/objects/js-regexp-string-iterator.h"
312
313using namespace v8::internal;
314
315extern "C" {
316
317/* stack frame constants */
318#define FRAME_CONST(value, klass)       \
319    int v8dbg_frametype_##klass = StackFrame::value;
320
321STACK_FRAME_TYPE_LIST(FRAME_CONST)
322
323#undef FRAME_CONST
324
325''' % sys.argv[0];
326
327footer = '''
328}
329'''
330
331#
332# Get the base class
333#
334def get_base_class(klass):
335        if (klass == 'Object'):
336                return klass;
337
338        if (not (klass in klasses)):
339                return None;
340
341        k = klasses[klass];
342
343        return get_base_class(k['parent']);
344
345#
346# Loads class hierarchy and type information from "objects.h" etc.
347#
348def load_objects():
349        #
350        # Construct a dictionary for the classes we're sure should be present.
351        #
352        checktypes = {};
353        for klass in expected_classes:
354                checktypes[klass] = True;
355
356
357        for filename in sys.argv[2:]:
358                if not filename.endswith("-inl.h"):
359                        load_objects_from_file(filename, checktypes)
360
361        if (len(checktypes) > 0):
362                for klass in checktypes:
363                        print('error: expected class \"%s\" not found' % klass);
364
365                sys.exit(1);
366
367
368def load_objects_from_file(objfilename, checktypes):
369        objfile = open(objfilename, 'r');
370        in_insttype = False;
371
372        typestr = '';
373
374        #
375        # Iterate the header file line-by-line to collect type and class
376        # information. For types, we accumulate a string representing the entire
377        # InstanceType enum definition and parse it later because it's easier to
378        # do so without the embedded newlines.
379        #
380        for line in objfile:
381                if (line.startswith('enum InstanceType : uint16_t {')):
382                        in_insttype = True;
383                        continue;
384
385                if (in_insttype and line.startswith('};')):
386                        in_insttype = False;
387                        continue;
388
389                line = re.sub('//.*', '', line.strip());
390
391                if (in_insttype):
392                        typestr += line;
393                        continue;
394
395                match = re.match('class (\w[^:]*)(: public (\w[^{]*))?\s*{\s*',
396                    line);
397
398                if (match):
399                        klass = match.group(1).strip();
400                        pklass = match.group(3);
401                        if (pklass):
402                                pklass = pklass.strip();
403                        klasses[klass] = { 'parent': pklass };
404
405        #
406        # Process the instance type declaration.
407        #
408        entries = typestr.split(',');
409        for entry in entries:
410                types[re.sub('\s*=.*', '', entry).lstrip()] = True;
411
412        #
413        # Infer class names for each type based on a systematic transformation.
414        # For example, "JS_FUNCTION_TYPE" becomes "JSFunction".  We find the
415        # class for each type rather than the other way around because there are
416        # fewer cases where one type maps to more than one class than the other
417        # way around.
418        #
419        for type in types:
420                #
421                # Symbols and Strings are implemented using the same classes.
422                #
423                usetype = re.sub('SYMBOL_', 'STRING_', type);
424
425                #
426                # REGEXP behaves like REG_EXP, as in JS_REGEXP_TYPE => JSRegExp.
427                #
428                usetype = re.sub('_REGEXP_', '_REG_EXP_', usetype);
429
430                #
431                # Remove the "_TYPE" suffix and then convert to camel case,
432                # except that a "JS" prefix remains uppercase (as in
433                # "JS_FUNCTION_TYPE" => "JSFunction").
434                #
435                if (not usetype.endswith('_TYPE')):
436                        continue;
437
438                usetype = usetype[0:len(usetype) - len('_TYPE')];
439                parts = usetype.split('_');
440                cctype = '';
441
442                if (parts[0] == 'JS'):
443                        cctype = 'JS';
444                        start = 1;
445                else:
446                        cctype = '';
447                        start = 0;
448
449                for ii in range(start, len(parts)):
450                        part = parts[ii];
451                        cctype += part[0].upper() + part[1:].lower();
452
453                #
454                # Mapping string types is more complicated.  Both types and
455                # class names for Strings specify a representation (e.g., Seq,
456                # Cons, External, or Sliced) and an encoding (TwoByte/OneByte),
457                # In the simplest case, both of these are explicit in both
458                # names, as in:
459                #
460                #       EXTERNAL_ONE_BYTE_STRING_TYPE => ExternalOneByteString
461                #
462                # However, either the representation or encoding can be omitted
463                # from the type name, in which case "Seq" and "TwoByte" are
464                # assumed, as in:
465                #
466                #       STRING_TYPE => SeqTwoByteString
467                #
468                # Additionally, sometimes the type name has more information
469                # than the class, as in:
470                #
471                #       CONS_ONE_BYTE_STRING_TYPE => ConsString
472                #
473                # To figure this out dynamically, we first check for a
474                # representation and encoding and add them if they're not
475                # present.  If that doesn't yield a valid class name, then we
476                # strip out the representation.
477                #
478                if (cctype.endswith('String')):
479                        if (cctype.find('Cons') == -1 and
480                            cctype.find('External') == -1 and
481                            cctype.find('Sliced') == -1):
482                                if (cctype.find('OneByte') != -1):
483                                        cctype = re.sub('OneByteString$',
484                                            'SeqOneByteString', cctype);
485                                else:
486                                        cctype = re.sub('String$',
487                                            'SeqString', cctype);
488
489                        if (cctype.find('OneByte') == -1):
490                                cctype = re.sub('String$', 'TwoByteString',
491                                    cctype);
492
493                        if (not (cctype in klasses)):
494                                cctype = re.sub('OneByte', '', cctype);
495                                cctype = re.sub('TwoByte', '', cctype);
496
497                #
498                # Despite all that, some types have no corresponding class.
499                #
500                if (cctype in klasses):
501                        typeclasses[type] = cctype;
502                        if (cctype in checktypes):
503                                del checktypes[cctype];
504
505#
506# For a given macro call, pick apart the arguments and return an object
507# describing the corresponding output constant.  See load_fields().
508#
509def parse_field(call):
510        # Replace newlines with spaces.
511        for ii in range(0, len(call)):
512                if (call[ii] == '\n'):
513                        call[ii] == ' ';
514
515        idx = call.find('(');
516        kind = call[0:idx];
517        rest = call[idx + 1: len(call) - 1];
518        args = re.split('\s*,\s*', rest);
519
520        consts = [];
521
522        if (kind == 'ACCESSORS' or kind == 'ACCESSORS_GCSAFE'):
523                klass = args[0];
524                field = args[1];
525                dtype = args[2].replace('<', '_').replace('>', '_')
526                offset = args[3];
527
528                return ({
529                    'name': 'class_%s__%s__%s' % (klass, field, dtype),
530                    'value': '%s::%s' % (klass, offset)
531                });
532
533        assert(kind == 'SMI_ACCESSORS' or kind == 'ACCESSORS_TO_SMI');
534        klass = args[0];
535        field = args[1];
536        offset = args[2];
537
538        return ({
539            'name': 'class_%s__%s__%s' % (klass, field, 'SMI'),
540            'value': '%s::%s' % (klass, offset)
541        });
542
543#
544# Load field offset information from objects-inl.h etc.
545#
546def load_fields():
547        for filename in sys.argv[2:]:
548                if filename.endswith("-inl.h"):
549                        load_fields_from_file(filename)
550
551        for body in extras_accessors:
552                fields.append(parse_field('ACCESSORS(%s)' % body));
553
554
555def load_fields_from_file(filename):
556        inlfile = open(filename, 'r');
557
558        #
559        # Each class's fields and the corresponding offsets are described in the
560        # source by calls to macros like "ACCESSORS" (and friends).  All we do
561        # here is extract these macro invocations, taking into account that they
562        # may span multiple lines and may contain nested parentheses.  We also
563        # call parse_field() to pick apart the invocation.
564        #
565        prefixes = [ 'ACCESSORS', 'ACCESSORS_GCSAFE',
566                     'SMI_ACCESSORS', 'ACCESSORS_TO_SMI' ];
567        current = '';
568        opens = 0;
569
570        for line in inlfile:
571                if (opens > 0):
572                        # Continuation line
573                        for ii in range(0, len(line)):
574                                if (line[ii] == '('):
575                                        opens += 1;
576                                elif (line[ii] == ')'):
577                                        opens -= 1;
578
579                                if (opens == 0):
580                                        break;
581
582                        current += line[0:ii + 1];
583                        continue;
584
585                for prefix in prefixes:
586                        if (not line.startswith(prefix + '(')):
587                                continue;
588
589                        if (len(current) > 0):
590                                fields.append(parse_field(current));
591                                current = '';
592
593                        for ii in range(len(prefix), len(line)):
594                                if (line[ii] == '('):
595                                        opens += 1;
596                                elif (line[ii] == ')'):
597                                        opens -= 1;
598
599                                if (opens == 0):
600                                        break;
601
602                        current += line[0:ii + 1];
603
604        if (len(current) > 0):
605                fields.append(parse_field(current));
606                current = '';
607
608#
609# Emit a block of constants.
610#
611def emit_set(out, consts):
612        # Fix up overzealous parses.  This could be done inside the
613        # parsers but as there are several, it's easiest to do it here.
614        ws = re.compile('\s+')
615        for const in consts:
616                name = ws.sub('', const['name'])
617                value = ws.sub('', str(const['value']))  # Can be a number.
618                out.write('int v8dbg_%s = %s;\n' % (name, value))
619        out.write('\n');
620
621#
622# Emit the whole output file.
623#
624def emit_config():
625        out = file(sys.argv[1], 'w');
626
627        out.write(header);
628
629        out.write('/* miscellaneous constants */\n');
630        emit_set(out, consts_misc);
631
632        out.write('/* class type information */\n');
633        consts = [];
634        keys = typeclasses.keys();
635        keys.sort();
636        for typename in keys:
637                klass = typeclasses[typename];
638                consts.append({
639                    'name': 'type_%s__%s' % (klass, typename),
640                    'value': typename
641                });
642
643        emit_set(out, consts);
644
645        out.write('/* class hierarchy information */\n');
646        consts = [];
647        keys = klasses.keys();
648        keys.sort();
649        for klassname in keys:
650                pklass = klasses[klassname]['parent'];
651                bklass = get_base_class(klassname);
652                if (bklass != 'Object'):
653                        continue;
654                if (pklass == None):
655                        continue;
656
657                consts.append({
658                    'name': 'parent_%s__%s' % (klassname, pklass),
659                    'value': 0
660                });
661
662        emit_set(out, consts);
663
664        out.write('/* field information */\n');
665        emit_set(out, fields);
666
667        out.write(footer);
668
669if (len(sys.argv) < 4):
670        print('usage: %s output.cc objects.h objects-inl.h' % sys.argv[0]);
671        sys.exit(2);
672
673load_objects();
674load_fields();
675emit_config();
676