1 # Copyright (C) 2013 Google Inc. All rights reserved. 2 # 3 # Redistribution and use in source and binary forms, with or without 4 # modification, are permitted provided that the following conditions are 5 # met: 6 # 7 # * Redistributions of source code must retain the above copyright 8 # notice, this list of conditions and the following disclaimer. 9 # * Redistributions in binary form must reproduce the above 10 # copyright notice, this list of conditions and the following disclaimer 11 # in the documentation and/or other materials provided with the 12 # distribution. 13 # * Neither the name of Google Inc. nor the names of its 14 # contributors may be used to endorse or promote products derived from 15 # this software without specific prior written permission. 16 # 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 """Functions for type handling and type conversion (Blink/C++ <-> V8/JS). 30 31 Extends IdlType and IdlUnionType with V8-specific properties, methods, and 32 class methods. 33 34 Spec: 35 http://www.w3.org/TR/WebIDL/#es-type-mapping 36 37 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler 38 """ 39 40 import posixpath 41 42 from idl_types import IdlTypeBase, IdlType, IdlUnionType, IdlArrayOrSequenceType, IdlNullableType 43 import v8_attributes # for IdlType.constructor_type_name 44 from v8_globals import includes 45 46 47 ################################################################################ 48 # V8-specific handling of IDL types 49 ################################################################################ 50 51 NON_WRAPPER_TYPES = frozenset([ 52 'Dictionary', 53 'EventHandler', 54 'EventListener', 55 'NodeFilter', 56 'SerializedScriptValue', 57 ]) 58 TYPED_ARRAYS = { 59 # (cpp_type, v8_type), used by constructor templates 60 'ArrayBuffer': None, 61 'ArrayBufferView': None, 62 'Float32Array': ('float', 'v8::kExternalFloatArray'), 63 'Float64Array': ('double', 'v8::kExternalDoubleArray'), 64 'Int8Array': ('signed char', 'v8::kExternalByteArray'), 65 'Int16Array': ('short', 'v8::kExternalShortArray'), 66 'Int32Array': ('int', 'v8::kExternalIntArray'), 67 'Uint8Array': ('unsigned char', 'v8::kExternalUnsignedByteArray'), 68 'Uint8ClampedArray': ('unsigned char', 'v8::kExternalPixelArray'), 69 'Uint16Array': ('unsigned short', 'v8::kExternalUnsignedShortArray'), 70 'Uint32Array': ('unsigned int', 'v8::kExternalUnsignedIntArray'), 71 } 72 73 IdlType.is_typed_array_element_type = property( 74 lambda self: self.base_type in TYPED_ARRAYS) 75 76 IdlType.is_wrapper_type = property( 77 lambda self: (self.is_interface_type and 78 self.base_type not in NON_WRAPPER_TYPES)) 79 80 81 ################################################################################ 82 # C++ types 83 ################################################################################ 84 85 CPP_TYPE_SAME_AS_IDL_TYPE = set([ 86 'double', 87 'float', 88 'long long', 89 'unsigned long long', 90 ]) 91 CPP_INT_TYPES = set([ 92 'byte', 93 'long', 94 'short', 95 ]) 96 CPP_UNSIGNED_TYPES = set([ 97 'octet', 98 'unsigned int', 99 'unsigned long', 100 'unsigned short', 101 ]) 102 CPP_SPECIAL_CONVERSION_RULES = { 103 'Date': 'double', 104 'Dictionary': 'Dictionary', 105 'EventHandler': 'EventListener*', 106 'NodeFilter': 'RefPtrWillBeRawPtr<NodeFilter>', 107 'Promise': 'ScriptPromise', 108 'ScriptValue': 'ScriptValue', 109 # FIXME: Eliminate custom bindings for XPathNSResolver http://crbug.com/345529 110 'XPathNSResolver': 'RefPtrWillBeRawPtr<XPathNSResolver>', 111 'boolean': 'bool', 112 'unrestricted double': 'double', 113 'unrestricted float': 'float', 114 } 115 116 117 def cpp_type(idl_type, extended_attributes=None, raw_type=False, used_as_rvalue_type=False, used_as_variadic_argument=False, used_in_cpp_sequence=False): 118 """Returns C++ type corresponding to IDL type. 119 120 |idl_type| argument is of type IdlType, while return value is a string 121 122 Args: 123 idl_type: 124 IdlType 125 raw_type: 126 bool, True if idl_type's raw/primitive C++ type should be returned. 127 used_as_rvalue_type: 128 bool, True if the C++ type is used as an argument or the return 129 type of a method. 130 used_as_variadic_argument: 131 bool, True if the C++ type is used as a variadic argument of a method. 132 used_in_cpp_sequence: 133 bool, True if the C++ type is used as an element of a container. 134 Containers can be an array, a sequence or a dictionary. 135 """ 136 def string_mode(): 137 if extended_attributes.get('TreatNullAs') == 'EmptyString': 138 return 'TreatNullAsEmptyString' 139 if idl_type.is_nullable or extended_attributes.get('TreatNullAs') == 'NullString': 140 if extended_attributes.get('TreatUndefinedAs') == 'NullString': 141 return 'TreatNullAndUndefinedAsNullString' 142 return 'TreatNullAsNullString' 143 return '' 144 145 extended_attributes = extended_attributes or {} 146 idl_type = idl_type.preprocessed_type 147 148 # Array or sequence types 149 if used_as_variadic_argument: 150 native_array_element_type = idl_type 151 else: 152 native_array_element_type = idl_type.native_array_element_type 153 if native_array_element_type: 154 vector_type = cpp_ptr_type('Vector', 'HeapVector', native_array_element_type.gc_type) 155 vector_template_type = cpp_template_type(vector_type, native_array_element_type.cpp_type_args(used_in_cpp_sequence=True)) 156 if used_as_rvalue_type: 157 return 'const %s&' % vector_template_type 158 return vector_template_type 159 160 # Simple types 161 base_idl_type = idl_type.base_type 162 163 if base_idl_type in CPP_TYPE_SAME_AS_IDL_TYPE: 164 return base_idl_type 165 if base_idl_type in CPP_INT_TYPES: 166 return 'int' 167 if base_idl_type in CPP_UNSIGNED_TYPES: 168 return 'unsigned' 169 if base_idl_type in CPP_SPECIAL_CONVERSION_RULES: 170 return CPP_SPECIAL_CONVERSION_RULES[base_idl_type] 171 172 if base_idl_type in NON_WRAPPER_TYPES: 173 return ('PassRefPtr<%s>' if used_as_rvalue_type else 'RefPtr<%s>') % base_idl_type 174 if idl_type.is_string_type: 175 if not raw_type: 176 return 'String' 177 return 'V8StringResource<%s>' % string_mode() 178 179 if idl_type.is_typed_array_element_type and raw_type: 180 return base_idl_type + '*' 181 if idl_type.is_interface_type: 182 implemented_as_class = idl_type.implemented_as 183 if raw_type: 184 return implemented_as_class + '*' 185 new_type = 'Member' if used_in_cpp_sequence else 'RawPtr' 186 ptr_type = cpp_ptr_type(('PassRefPtr' if used_as_rvalue_type else 'RefPtr'), new_type, idl_type.gc_type) 187 return cpp_template_type(ptr_type, implemented_as_class) 188 # Default, assume native type is a pointer with same type name as idl type 189 return base_idl_type + '*' 190 191 192 def cpp_type_initializer(idl_type): 193 """Returns a string containing a C++ initialization statement for the 194 corresponding type. 195 196 |idl_type| argument is of type IdlType. 197 """ 198 199 base_idl_type = idl_type.base_type 200 201 if idl_type.native_array_element_type: 202 return '' 203 if idl_type.is_numeric_type: 204 return ' = 0' 205 if base_idl_type == 'boolean': 206 return ' = false' 207 if (base_idl_type in NON_WRAPPER_TYPES or 208 base_idl_type in CPP_SPECIAL_CONVERSION_RULES or 209 base_idl_type == 'any' or 210 idl_type.is_string_type or 211 idl_type.is_enum): 212 return '' 213 return ' = nullptr' 214 215 216 def cpp_type_union(idl_type, extended_attributes=None, raw_type=False): 217 # FIXME: Need to revisit the design of union support. 218 # http://crbug.com/240176 219 return None 220 221 222 def cpp_type_initializer_union(idl_type): 223 return (member_type.cpp_type_initializer for member_type in idl_type.member_types) 224 225 226 # Allow access as idl_type.cpp_type if no arguments 227 IdlTypeBase.cpp_type = property(cpp_type) 228 IdlTypeBase.cpp_type_initializer = property(cpp_type_initializer) 229 IdlTypeBase.cpp_type_args = cpp_type 230 IdlUnionType.cpp_type = property(cpp_type_union) 231 IdlUnionType.cpp_type_initializer = property(cpp_type_initializer_union) 232 IdlUnionType.cpp_type_args = cpp_type_union 233 234 235 IdlArrayOrSequenceType.native_array_element_type = property( 236 lambda self: self.element_type) 237 238 239 def cpp_template_type(template, inner_type): 240 """Returns C++ template specialized to type, with space added if needed.""" 241 if inner_type.endswith('>'): 242 format_string = '{template}<{inner_type} >' 243 else: 244 format_string = '{template}<{inner_type}>' 245 return format_string.format(template=template, inner_type=inner_type) 246 247 248 def cpp_ptr_type(old_type, new_type, gc_type): 249 if gc_type == 'GarbageCollectedObject': 250 return new_type 251 if gc_type == 'WillBeGarbageCollectedObject': 252 if old_type == 'Vector': 253 return 'WillBe' + new_type 254 return old_type + 'WillBe' + new_type 255 return old_type 256 257 258 def v8_type(interface_name): 259 return 'V8' + interface_name 260 261 262 # [ImplementedAs] 263 # This handles [ImplementedAs] on interface types, not [ImplementedAs] in the 264 # interface being generated. e.g., given: 265 # Foo.idl: interface Foo {attribute Bar bar}; 266 # Bar.idl: [ImplementedAs=Zork] interface Bar {}; 267 # when generating bindings for Foo, the [ImplementedAs] on Bar is needed. 268 # This data is external to Foo.idl, and hence computed as global information in 269 # compute_interfaces_info.py to avoid having to parse IDLs of all used interfaces. 270 IdlType.implemented_as_interfaces = {} 271 272 273 def implemented_as(idl_type): 274 base_idl_type = idl_type.base_type 275 if base_idl_type in IdlType.implemented_as_interfaces: 276 return IdlType.implemented_as_interfaces[base_idl_type] 277 return base_idl_type 278 279 280 IdlType.implemented_as = property(implemented_as) 281 282 IdlType.set_implemented_as_interfaces = classmethod( 283 lambda cls, new_implemented_as_interfaces: 284 cls.implemented_as_interfaces.update(new_implemented_as_interfaces)) 285 286 287 # [GarbageCollected] 288 IdlType.garbage_collected_types = set() 289 290 IdlType.is_garbage_collected = property( 291 lambda self: self.base_type in IdlType.garbage_collected_types) 292 293 IdlType.set_garbage_collected_types = classmethod( 294 lambda cls, new_garbage_collected_types: 295 cls.garbage_collected_types.update(new_garbage_collected_types)) 296 297 298 # [WillBeGarbageCollected] 299 IdlType.will_be_garbage_collected_types = set() 300 301 IdlType.is_will_be_garbage_collected = property( 302 lambda self: self.base_type in IdlType.will_be_garbage_collected_types) 303 304 IdlType.set_will_be_garbage_collected_types = classmethod( 305 lambda cls, new_will_be_garbage_collected_types: 306 cls.will_be_garbage_collected_types.update(new_will_be_garbage_collected_types)) 307 308 309 def gc_type(idl_type): 310 if idl_type.is_garbage_collected: 311 return 'GarbageCollectedObject' 312 if idl_type.is_will_be_garbage_collected: 313 return 'WillBeGarbageCollectedObject' 314 return 'RefCountedObject' 315 316 IdlTypeBase.gc_type = property(gc_type) 317 318 319 ################################################################################ 320 # Includes 321 ################################################################################ 322 323 def includes_for_cpp_class(class_name, relative_dir_posix): 324 return set([posixpath.join('bindings', relative_dir_posix, class_name + '.h')]) 325 326 327 INCLUDES_FOR_TYPE = { 328 'object': set(), 329 'Dictionary': set(['bindings/core/v8/Dictionary.h']), 330 'EventHandler': set(['bindings/core/v8/V8AbstractEventListener.h', 331 'bindings/core/v8/V8EventListenerList.h']), 332 'EventListener': set(['bindings/core/v8/BindingSecurity.h', 333 'bindings/core/v8/V8EventListenerList.h', 334 'core/frame/LocalDOMWindow.h']), 335 'HTMLCollection': set(['bindings/core/v8/V8HTMLCollection.h', 336 'core/dom/ClassCollection.h', 337 'core/dom/TagCollection.h', 338 'core/html/HTMLCollection.h', 339 'core/html/HTMLDataListOptionsCollection.h', 340 'core/html/HTMLFormControlsCollection.h', 341 'core/html/HTMLTableRowsCollection.h']), 342 'NodeList': set(['bindings/core/v8/V8NodeList.h', 343 'core/dom/NameNodeList.h', 344 'core/dom/NodeList.h', 345 'core/dom/StaticNodeList.h', 346 'core/html/LabelsNodeList.h']), 347 'Promise': set(['bindings/core/v8/ScriptPromise.h']), 348 'SerializedScriptValue': set(['bindings/core/v8/SerializedScriptValue.h']), 349 'ScriptValue': set(['bindings/core/v8/ScriptValue.h']), 350 } 351 352 353 def includes_for_type(idl_type): 354 idl_type = idl_type.preprocessed_type 355 356 # Simple types 357 base_idl_type = idl_type.base_type 358 if base_idl_type in INCLUDES_FOR_TYPE: 359 return INCLUDES_FOR_TYPE[base_idl_type] 360 if idl_type.is_basic_type: 361 return set() 362 if idl_type.is_typed_array_element_type: 363 return set(['bindings/core/v8/custom/V8%sCustom.h' % base_idl_type]) 364 if base_idl_type.endswith('ConstructorConstructor'): 365 # FIXME: rename to NamedConstructor 366 # FIXME: replace with a [NamedConstructorAttribute] extended attribute 367 # Ending with 'ConstructorConstructor' indicates a named constructor, 368 # and these do not have header files, as they are part of the generated 369 # bindings for the interface 370 return set() 371 if base_idl_type.endswith('Constructor'): 372 # FIXME: replace with a [ConstructorAttribute] extended attribute 373 base_idl_type = idl_type.constructor_type_name 374 if base_idl_type not in component_dir: 375 return set() 376 return set(['bindings/%s/v8/V8%s.h' % (component_dir[base_idl_type], 377 base_idl_type)]) 378 379 IdlType.includes_for_type = property(includes_for_type) 380 IdlUnionType.includes_for_type = property( 381 lambda self: set.union(*[member_type.includes_for_type 382 for member_type in self.member_types])) 383 IdlArrayOrSequenceType.includes_for_type = property( 384 lambda self: self.element_type.includes_for_type) 385 386 387 def add_includes_for_type(idl_type): 388 includes.update(idl_type.includes_for_type) 389 390 IdlTypeBase.add_includes_for_type = add_includes_for_type 391 392 393 def includes_for_interface(interface_name): 394 return IdlType(interface_name).includes_for_type 395 396 397 def add_includes_for_interface(interface_name): 398 includes.update(includes_for_interface(interface_name)) 399 400 401 def impl_should_use_nullable_container(idl_type): 402 return not(idl_type.cpp_type_has_null_value) 403 404 IdlTypeBase.impl_should_use_nullable_container = property( 405 impl_should_use_nullable_container) 406 407 408 def impl_includes_for_type(idl_type, interfaces_info): 409 includes_for_type = set() 410 if idl_type.impl_should_use_nullable_container: 411 includes_for_type.add('bindings/core/v8/Nullable.h') 412 413 idl_type = idl_type.preprocessed_type 414 native_array_element_type = idl_type.native_array_element_type 415 if native_array_element_type: 416 includes_for_type.update(impl_includes_for_type( 417 native_array_element_type, interfaces_info)) 418 includes_for_type.add('wtf/Vector.h') 419 420 base_idl_type = idl_type.base_type 421 if idl_type.is_string_type: 422 includes_for_type.add('wtf/text/WTFString.h') 423 if base_idl_type in interfaces_info: 424 interface_info = interfaces_info[idl_type.base_type] 425 includes_for_type.add(interface_info['include_path']) 426 if base_idl_type in INCLUDES_FOR_TYPE: 427 includes_for_type.update(INCLUDES_FOR_TYPE[base_idl_type]) 428 return includes_for_type 429 430 IdlTypeBase.impl_includes_for_type = impl_includes_for_type 431 432 433 component_dir = {} 434 435 436 def set_component_dirs(new_component_dirs): 437 component_dir.update(new_component_dirs) 438 439 440 ################################################################################ 441 # V8 -> C++ 442 ################################################################################ 443 444 V8_VALUE_TO_CPP_VALUE = { 445 # Basic 446 'Date': 'toCoreDate({v8_value})', 447 'DOMString': '{v8_value}', 448 'ByteString': 'toByteString({arguments})', 449 'ScalarValueString': 'toScalarValueString({arguments})', 450 'boolean': '{v8_value}->BooleanValue()', 451 'float': 'toFloat({arguments})', 452 'unrestricted float': 'toFloat({arguments})', 453 'double': 'toDouble({arguments})', 454 'unrestricted double': 'toDouble({arguments})', 455 'byte': 'toInt8({arguments})', 456 'octet': 'toUInt8({arguments})', 457 'short': 'toInt16({arguments})', 458 'unsigned short': 'toUInt16({arguments})', 459 'long': 'toInt32({arguments})', 460 'unsigned long': 'toUInt32({arguments})', 461 'long long': 'toInt64({arguments})', 462 'unsigned long long': 'toUInt64({arguments})', 463 # Interface types 464 'Dictionary': 'Dictionary({v8_value}, {isolate})', 465 'EventTarget': 'V8DOMWrapper::isDOMWrapper({v8_value}) ? toWrapperTypeInfo(v8::Handle<v8::Object>::Cast({v8_value}))->toEventTarget(v8::Handle<v8::Object>::Cast({v8_value})) : 0', 466 'NodeFilter': 'toNodeFilter({v8_value}, info.Holder(), ScriptState::current({isolate}))', 467 'Promise': 'ScriptPromise::cast(ScriptState::current({isolate}), {v8_value})', 468 'SerializedScriptValue': 'SerializedScriptValue::create({v8_value}, 0, 0, exceptionState, {isolate})', 469 'ScriptValue': 'ScriptValue(ScriptState::current({isolate}), {v8_value})', 470 'Window': 'toDOMWindow({v8_value}, {isolate})', 471 'XPathNSResolver': 'toXPathNSResolver({v8_value}, {isolate})', 472 } 473 474 475 def v8_conversion_needs_exception_state(idl_type): 476 return (idl_type.is_numeric_type or 477 idl_type.is_dictionary or 478 idl_type.name in ('ByteString', 'ScalarValueString', 'SerializedScriptValue')) 479 480 IdlType.v8_conversion_needs_exception_state = property(v8_conversion_needs_exception_state) 481 IdlArrayOrSequenceType.v8_conversion_needs_exception_state = True 482 483 484 TRIVIAL_CONVERSIONS = frozenset([ 485 'any', 486 'boolean', 487 'Date', 488 'Dictionary', 489 'NodeFilter', 490 'XPathNSResolver', 491 'Promise' 492 ]) 493 494 495 def v8_conversion_is_trivial(idl_type): 496 # The conversion is a simple expression that returns the converted value and 497 # cannot raise an exception. 498 return (idl_type.base_type in TRIVIAL_CONVERSIONS or 499 idl_type.is_wrapper_type) 500 501 IdlType.v8_conversion_is_trivial = property(v8_conversion_is_trivial) 502 503 504 def v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, index, isolate): 505 if idl_type.name == 'void': 506 return '' 507 508 # Array or sequence types 509 native_array_element_type = idl_type.native_array_element_type 510 if native_array_element_type: 511 return v8_value_to_cpp_value_array_or_sequence(native_array_element_type, v8_value, index) 512 513 # Simple types 514 idl_type = idl_type.preprocessed_type 515 add_includes_for_type(idl_type) 516 base_idl_type = idl_type.base_type 517 518 if 'EnforceRange' in extended_attributes: 519 arguments = ', '.join([v8_value, 'EnforceRange', 'exceptionState']) 520 elif 'Clamp' in extended_attributes: 521 arguments = ', '.join([v8_value, 'Clamp', 'exceptionState']) 522 elif idl_type.v8_conversion_needs_exception_state: 523 arguments = ', '.join([v8_value, 'exceptionState']) 524 else: 525 arguments = v8_value 526 527 if base_idl_type in V8_VALUE_TO_CPP_VALUE: 528 cpp_expression_format = V8_VALUE_TO_CPP_VALUE[base_idl_type] 529 elif idl_type.is_typed_array_element_type: 530 cpp_expression_format = ( 531 '{v8_value}->Is{idl_type}() ? ' 532 'V8{idl_type}::toImpl(v8::Handle<v8::{idl_type}>::Cast({v8_value})) : 0') 533 elif idl_type.is_dictionary: 534 cpp_expression_format = 'V8{idl_type}::toImpl({isolate}, {v8_value}, exceptionState)' 535 else: 536 cpp_expression_format = ( 537 'V8{idl_type}::toImplWithTypeCheck({isolate}, {v8_value})') 538 539 return cpp_expression_format.format(arguments=arguments, idl_type=base_idl_type, v8_value=v8_value, isolate=isolate) 540 541 542 def v8_value_to_cpp_value_array_or_sequence(native_array_element_type, v8_value, index, isolate='info.GetIsolate()'): 543 # Index is None for setters, index (starting at 0) for method arguments, 544 # and is used to provide a human-readable exception message 545 if index is None: 546 index = 0 # special case, meaning "setter" 547 else: 548 index += 1 # human-readable index 549 if (native_array_element_type.is_interface_type and 550 native_array_element_type.name != 'Dictionary'): 551 this_cpp_type = None 552 ref_ptr_type = cpp_ptr_type('RefPtr', 'Member', native_array_element_type.gc_type) 553 expression_format = '(to{ref_ptr_type}NativeArray<{native_array_element_type}, V8{native_array_element_type}>({v8_value}, {index}, {isolate}, exceptionState))' 554 add_includes_for_type(native_array_element_type) 555 else: 556 ref_ptr_type = None 557 this_cpp_type = native_array_element_type.cpp_type 558 expression_format = 'toImplArray<{cpp_type}>({v8_value}, {index}, {isolate}, exceptionState)' 559 expression = expression_format.format(native_array_element_type=native_array_element_type.name, cpp_type=this_cpp_type, index=index, ref_ptr_type=ref_ptr_type, v8_value=v8_value, isolate=isolate) 560 return expression 561 562 563 def v8_value_to_local_cpp_value(idl_type, extended_attributes, v8_value, variable_name, index=None, declare_variable=True, isolate='info.GetIsolate()', used_in_private_script=False, return_promise=False): 564 """Returns an expression that converts a V8 value to a C++ value and stores it as a local value.""" 565 566 # FIXME: Support union type. 567 if idl_type.is_union_type: 568 return '/* no V8 -> C++ conversion for IDL union type: %s */' % idl_type.name 569 570 this_cpp_type = idl_type.cpp_type_args(extended_attributes=extended_attributes, raw_type=True) 571 idl_type = idl_type.preprocessed_type 572 573 if idl_type.base_type in ('void', 'object', 'EventHandler', 'EventListener'): 574 return '/* no V8 -> C++ conversion for IDL type: %s */' % idl_type.name 575 576 cpp_value = v8_value_to_cpp_value(idl_type, extended_attributes, v8_value, index, isolate) 577 if idl_type.is_string_type or idl_type.v8_conversion_needs_exception_state: 578 # Types that need error handling and use one of a group of (C++) macros 579 # to take care of this. 580 581 args = [variable_name, cpp_value] 582 583 if idl_type.v8_conversion_needs_exception_state: 584 macro = 'TONATIVE_DEFAULT_EXCEPTIONSTATE' if used_in_private_script else 'TONATIVE_VOID_EXCEPTIONSTATE' 585 elif return_promise: 586 macro = 'TOSTRING_VOID_EXCEPTIONSTATE' 587 else: 588 macro = 'TOSTRING_DEFAULT' if used_in_private_script else 'TOSTRING_VOID' 589 590 if macro.endswith('_EXCEPTIONSTATE'): 591 args.append('exceptionState') 592 593 if used_in_private_script: 594 args.append('false') 595 596 suffix = '' 597 598 if return_promise: 599 suffix += '_PROMISE' 600 args.append('info') 601 if macro.endswith('_EXCEPTIONSTATE'): 602 args.append('ScriptState::current(%s)' % isolate) 603 604 if declare_variable: 605 args.insert(0, this_cpp_type) 606 else: 607 suffix += '_INTERNAL' 608 609 return '%s(%s)' % (macro + suffix, ', '.join(args)) 610 611 # Types that don't need error handling, and simply assign a value to the 612 # local variable. 613 614 if not idl_type.v8_conversion_is_trivial: 615 raise Exception('unclassified V8 -> C++ conversion for IDL type: %s' % idl_type.name) 616 617 assignment = '%s = %s' % (variable_name, cpp_value) 618 if declare_variable: 619 return '%s %s' % (this_cpp_type, assignment) 620 return assignment 621 622 623 IdlTypeBase.v8_value_to_local_cpp_value = v8_value_to_local_cpp_value 624 625 626 ################################################################################ 627 # C++ -> V8 628 ################################################################################ 629 630 def preprocess_idl_type(idl_type): 631 if idl_type.is_enum: 632 # Enumerations are internally DOMStrings 633 return IdlType('DOMString') 634 if (idl_type.name in ['Any', 'Object'] or idl_type.is_callback_function): 635 return IdlType('ScriptValue') 636 return idl_type 637 638 IdlTypeBase.preprocessed_type = property(preprocess_idl_type) 639 640 641 def preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes): 642 """Returns IDL type and value, with preliminary type conversions applied.""" 643 idl_type = idl_type.preprocessed_type 644 if idl_type.name == 'Promise': 645 idl_type = IdlType('ScriptValue') 646 if idl_type.base_type in ['long long', 'unsigned long long']: 647 # long long and unsigned long long are not representable in ECMAScript; 648 # we represent them as doubles. 649 is_nullable = idl_type.is_nullable 650 idl_type = IdlType('double') 651 if is_nullable: 652 idl_type = IdlNullableType(idl_type) 653 cpp_value = 'static_cast<double>(%s)' % cpp_value 654 # HTML5 says that unsigned reflected attributes should be in the range 655 # [0, 2^31). When a value isn't in this range, a default value (or 0) 656 # should be returned instead. 657 extended_attributes = extended_attributes or {} 658 if ('Reflect' in extended_attributes and 659 idl_type.base_type in ['unsigned long', 'unsigned short']): 660 cpp_value = cpp_value.replace('getUnsignedIntegralAttribute', 661 'getIntegralAttribute') 662 cpp_value = 'std::max(0, static_cast<int>(%s))' % cpp_value 663 return idl_type, cpp_value 664 665 666 def v8_conversion_type(idl_type, extended_attributes): 667 """Returns V8 conversion type, adding any additional includes. 668 669 The V8 conversion type is used to select the C++ -> V8 conversion function 670 or v8SetReturnValue* function; it can be an idl_type, a cpp_type, or a 671 separate name for the type of conversion (e.g., 'DOMWrapper'). 672 """ 673 extended_attributes = extended_attributes or {} 674 675 # FIXME: Support union type. 676 if idl_type.is_union_type: 677 return '' 678 679 # Array or sequence types 680 native_array_element_type = idl_type.native_array_element_type 681 if native_array_element_type: 682 if native_array_element_type.is_interface_type: 683 add_includes_for_type(native_array_element_type) 684 return 'array' 685 686 # Simple types 687 base_idl_type = idl_type.base_type 688 # Basic types, without additional includes 689 if base_idl_type in CPP_INT_TYPES: 690 return 'int' 691 if base_idl_type in CPP_UNSIGNED_TYPES: 692 return 'unsigned' 693 if idl_type.is_string_type: 694 if idl_type.is_nullable: 695 return 'StringOrNull' 696 if 'TreatReturnedNullStringAs' not in extended_attributes: 697 return base_idl_type 698 treat_returned_null_string_as = extended_attributes['TreatReturnedNullStringAs'] 699 if treat_returned_null_string_as == 'Null': 700 return 'StringOrNull' 701 if treat_returned_null_string_as == 'Undefined': 702 return 'StringOrUndefined' 703 raise 'Unrecognized TreatReturnedNullStringAs value: "%s"' % treat_returned_null_string_as 704 if idl_type.is_basic_type or base_idl_type == 'ScriptValue': 705 return base_idl_type 706 707 # Data type with potential additional includes 708 add_includes_for_type(idl_type) 709 if base_idl_type in V8_SET_RETURN_VALUE: # Special v8SetReturnValue treatment 710 return base_idl_type 711 712 # Pointer type 713 return 'DOMWrapper' 714 715 IdlTypeBase.v8_conversion_type = v8_conversion_type 716 717 718 V8_SET_RETURN_VALUE = { 719 'boolean': 'v8SetReturnValueBool(info, {cpp_value})', 720 'int': 'v8SetReturnValueInt(info, {cpp_value})', 721 'unsigned': 'v8SetReturnValueUnsigned(info, {cpp_value})', 722 'DOMString': 'v8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', 723 'ByteString': 'v8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', 724 'ScalarValueString': 'v8SetReturnValueString(info, {cpp_value}, info.GetIsolate())', 725 # [TreatReturnedNullStringAs] 726 'StringOrNull': 'v8SetReturnValueStringOrNull(info, {cpp_value}, info.GetIsolate())', 727 'StringOrUndefined': 'v8SetReturnValueStringOrUndefined(info, {cpp_value}, info.GetIsolate())', 728 'void': '', 729 # No special v8SetReturnValue* function (set value directly) 730 'float': 'v8SetReturnValue(info, {cpp_value})', 731 'unrestricted float': 'v8SetReturnValue(info, {cpp_value})', 732 'double': 'v8SetReturnValue(info, {cpp_value})', 733 'unrestricted double': 'v8SetReturnValue(info, {cpp_value})', 734 # No special v8SetReturnValue* function, but instead convert value to V8 735 # and then use general v8SetReturnValue. 736 'array': 'v8SetReturnValue(info, {cpp_value})', 737 'Date': 'v8SetReturnValue(info, {cpp_value})', 738 'EventHandler': 'v8SetReturnValue(info, {cpp_value})', 739 'ScriptValue': 'v8SetReturnValue(info, {cpp_value})', 740 'SerializedScriptValue': 'v8SetReturnValue(info, {cpp_value})', 741 # DOMWrapper 742 'DOMWrapperForMainWorld': 'v8SetReturnValueForMainWorld(info, WTF::getPtr({cpp_value}))', 743 'DOMWrapperFast': 'v8SetReturnValueFast(info, WTF::getPtr({cpp_value}), {script_wrappable})', 744 'DOMWrapperDefault': 'v8SetReturnValue(info, {cpp_value})', 745 } 746 747 748 def v8_set_return_value(idl_type, cpp_value, extended_attributes=None, script_wrappable='', release=False, for_main_world=False): 749 """Returns a statement that converts a C++ value to a V8 value and sets it as a return value. 750 751 """ 752 def dom_wrapper_conversion_type(): 753 if not script_wrappable: 754 return 'DOMWrapperDefault' 755 if for_main_world: 756 return 'DOMWrapperForMainWorld' 757 return 'DOMWrapperFast' 758 759 idl_type, cpp_value = preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes) 760 this_v8_conversion_type = idl_type.v8_conversion_type(extended_attributes) 761 # SetReturn-specific overrides 762 if this_v8_conversion_type in ['Date', 'EventHandler', 'ScriptValue', 'SerializedScriptValue', 'array']: 763 # Convert value to V8 and then use general v8SetReturnValue 764 cpp_value = idl_type.cpp_value_to_v8_value(cpp_value, extended_attributes=extended_attributes) 765 if this_v8_conversion_type == 'DOMWrapper': 766 this_v8_conversion_type = dom_wrapper_conversion_type() 767 768 format_string = V8_SET_RETURN_VALUE[this_v8_conversion_type] 769 # FIXME: oilpan: Remove .release() once we remove all RefPtrs from generated code. 770 if release: 771 cpp_value = '%s.release()' % cpp_value 772 statement = format_string.format(cpp_value=cpp_value, script_wrappable=script_wrappable) 773 return statement 774 775 776 def v8_set_return_value_union(idl_type, cpp_value, extended_attributes=None, script_wrappable='', release=False, for_main_world=False): 777 # FIXME: Need to revisit the design of union support. 778 # http://crbug.com/240176 779 return None 780 781 782 IdlTypeBase.v8_set_return_value = v8_set_return_value 783 IdlUnionType.v8_set_return_value = v8_set_return_value_union 784 785 IdlType.release = property(lambda self: self.is_interface_type) 786 IdlUnionType.release = property( 787 lambda self: [member_type.is_interface_type 788 for member_type in self.member_types]) 789 790 791 CPP_VALUE_TO_V8_VALUE = { 792 # Built-in types 793 'Date': 'v8DateOrNaN({cpp_value}, {isolate})', 794 'DOMString': 'v8String({isolate}, {cpp_value})', 795 'ByteString': 'v8String({isolate}, {cpp_value})', 796 'ScalarValueString': 'v8String({isolate}, {cpp_value})', 797 'boolean': 'v8Boolean({cpp_value}, {isolate})', 798 'int': 'v8::Integer::New({isolate}, {cpp_value})', 799 'unsigned': 'v8::Integer::NewFromUnsigned({isolate}, {cpp_value})', 800 'float': 'v8::Number::New({isolate}, {cpp_value})', 801 'unrestricted float': 'v8::Number::New({isolate}, {cpp_value})', 802 'double': 'v8::Number::New({isolate}, {cpp_value})', 803 'unrestricted double': 'v8::Number::New({isolate}, {cpp_value})', 804 'void': 'v8Undefined()', 805 # [TreatReturnedNullStringAs] 806 'StringOrNull': '{cpp_value}.isNull() ? v8::Handle<v8::Value>(v8::Null({isolate})) : v8String({isolate}, {cpp_value})', 807 'StringOrUndefined': '{cpp_value}.isNull() ? v8Undefined() : v8String({isolate}, {cpp_value})', 808 # Special cases 809 'EventHandler': '{cpp_value} ? v8::Handle<v8::Value>(V8AbstractEventListener::cast({cpp_value})->getListenerObject(impl->executionContext())) : v8::Handle<v8::Value>(v8::Null({isolate}))', 810 'ScriptValue': '{cpp_value}.v8Value()', 811 'SerializedScriptValue': '{cpp_value} ? {cpp_value}->deserialize() : v8::Handle<v8::Value>(v8::Null({isolate}))', 812 # General 813 'array': 'v8Array({cpp_value}, {creation_context}, {isolate})', 814 'DOMWrapper': 'toV8({cpp_value}, {creation_context}, {isolate})', 815 } 816 817 818 def cpp_value_to_v8_value(idl_type, cpp_value, isolate='info.GetIsolate()', creation_context='info.Holder()', extended_attributes=None): 819 """Returns an expression that converts a C++ value to a V8 value.""" 820 # the isolate parameter is needed for callback interfaces 821 idl_type, cpp_value = preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes) 822 this_v8_conversion_type = idl_type.v8_conversion_type(extended_attributes) 823 format_string = CPP_VALUE_TO_V8_VALUE[this_v8_conversion_type] 824 statement = format_string.format(cpp_value=cpp_value, isolate=isolate, creation_context=creation_context) 825 return statement 826 827 IdlTypeBase.cpp_value_to_v8_value = cpp_value_to_v8_value 828 829 830 def literal_cpp_value(idl_type, idl_literal): 831 """Converts an expression that is a valid C++ literal for this type.""" 832 # FIXME: add validation that idl_type and idl_literal are compatible 833 literal_value = str(idl_literal) 834 if idl_type.base_type in CPP_UNSIGNED_TYPES: 835 return literal_value + 'u' 836 return literal_value 837 838 IdlType.literal_cpp_value = literal_cpp_value 839 840 841 ################################################################################ 842 # Utility properties for nullable types 843 ################################################################################ 844 845 846 def cpp_type_has_null_value(idl_type): 847 # - String types (String/AtomicString) represent null as a null string, 848 # i.e. one for which String::isNull() returns true. 849 # - Enum types, as they are implemented as Strings. 850 # - Wrapper types (raw pointer or RefPtr/PassRefPtr) represent null as 851 # a null pointer. 852 # - Dictionary types represent null as a null pointer. They are garbage 853 # collected so their type is raw pointer. 854 # - 'Object' type. We use ScriptValue for object type. 855 return (idl_type.is_string_type or idl_type.is_wrapper_type or 856 idl_type.is_enum or idl_type.is_dictionary or idl_type.base_type == 'object') 857 858 IdlTypeBase.cpp_type_has_null_value = property(cpp_type_has_null_value) 859 860 861 def is_implicit_nullable(idl_type): 862 # Nullable type where the corresponding C++ type supports a null value. 863 return idl_type.is_nullable and idl_type.cpp_type_has_null_value 864 865 866 def is_explicit_nullable(idl_type): 867 # Nullable type that isn't implicit nullable (see above.) For such types, 868 # we use Nullable<T> or similar explicit ways to represent a null value. 869 return idl_type.is_nullable and not idl_type.is_implicit_nullable 870 871 IdlTypeBase.is_implicit_nullable = property(is_implicit_nullable) 872 IdlUnionType.is_implicit_nullable = False 873 IdlTypeBase.is_explicit_nullable = property(is_explicit_nullable) 874