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