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