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