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