1# 2# Copyright (C) 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 3# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> 4# Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org> 5# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> 6# Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 7# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> 8# Copyright (C) Research In Motion Limited 2010. All rights reserved. 9# Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 10# Copyright (C) 2011 Patrick Gansterer <paroga@webkit.org> 11# Copyright (C) 2012 Ericsson AB. All rights reserved. 12# Copyright (C) 2007, 2008, 2009, 2012 Google Inc. 13# Copyright (C) 2013 Samsung Electronics. All rights reserved. 14# 15# This library is free software; you can redistribute it and/or 16# modify it under the terms of the GNU Library General Public 17# License as published by the Free Software Foundation; either 18# version 2 of the License, or (at your option) any later version. 19# 20# This library is distributed in the hope that it will be useful, 21# but WITHOUT ANY WARRANTY; without even the implied warranty of 22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23# Library General Public License for more details. 24# 25# You should have received a copy of the GNU Library General Public License 26# along with this library; see the file COPYING.LIB. If not, write to 27# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 28# Boston, MA 02110-1301, USA. 29 30package CodeGeneratorJS; 31 32use strict; 33use constant FileNamePrefix => "JS"; 34use Hasher; 35 36my $codeGenerator; 37 38my $writeDependencies = 0; 39 40my @headerContentHeader = (); 41my @headerContent = (); 42my %headerIncludes = (); 43my %headerTrailingIncludes = (); 44 45my @implContentHeader = (); 46my @implContent = (); 47my %implIncludes = (); 48my @depsContent = (); 49my $numCachedAttributes = 0; 50my $currentCachedAttribute = 0; 51 52# Default .h template 53my $headerTemplate = << "EOF"; 54/* 55 This file is part of the WebKit open source project. 56 This file has been generated by generate-bindings.pl. DO NOT MODIFY! 57 58 This library is free software; you can redistribute it and/or 59 modify it under the terms of the GNU Library General Public 60 License as published by the Free Software Foundation; either 61 version 2 of the License, or (at your option) any later version. 62 63 This library is distributed in the hope that it will be useful, 64 but WITHOUT ANY WARRANTY; without even the implied warranty of 65 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 66 Library General Public License for more details. 67 68 You should have received a copy of the GNU Library General Public License 69 along with this library; see the file COPYING.LIB. If not, write to 70 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 71 Boston, MA 02110-1301, USA. 72*/ 73EOF 74 75# Default constructor 76sub new 77{ 78 my $object = shift; 79 my $reference = { }; 80 81 $codeGenerator = shift; 82 shift; # $useLayerOnTop 83 shift; # $preprocessor 84 $writeDependencies = shift; 85 86 bless($reference, $object); 87 return $reference; 88} 89 90sub GenerateInterface 91{ 92 my $object = shift; 93 my $interface = shift; 94 my $defines = shift; 95 96 $codeGenerator->LinkOverloadedFunctions($interface); 97 98 # Start actual generation 99 if ($interface->isCallback) { 100 $object->GenerateCallbackHeader($interface); 101 $object->GenerateCallbackImplementation($interface); 102 } else { 103 $object->GenerateHeader($interface); 104 $object->GenerateImplementation($interface); 105 } 106} 107 108sub GenerateAttributeEventListenerCall 109{ 110 my $className = shift; 111 my $implSetterFunctionName = shift; 112 my $windowEventListener = shift; 113 114 my $wrapperObject = $windowEventListener ? "globalObject" : "thisObject"; 115 my @GenerateEventListenerImpl = (); 116 117 if ($className eq "JSSVGElementInstance") { 118 # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement 119 $wrapperObject = "asObject(correspondingElementWrapper)"; 120 121 push(@GenerateEventListenerImpl, <<END); 122 JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl->correspondingElement()); 123 if (correspondingElementWrapper.isObject()) 124END 125 126 # Add leading whitespace to format the impl->set... line correctly 127 push(@GenerateEventListenerImpl, " "); 128 } 129 130 push(@GenerateEventListenerImpl, " impl->set$implSetterFunctionName(createJSAttributeEventListener(exec, value, $wrapperObject));\n"); 131 return @GenerateEventListenerImpl; 132} 133 134sub GenerateEventListenerCall 135{ 136 my $className = shift; 137 my $functionName = shift; 138 my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()"; 139 140 $implIncludes{"JSEventListener.h"} = 1; 141 142 my @GenerateEventListenerImpl = (); 143 my $wrapperObject = "castedThis"; 144 if ($className eq "JSSVGElementInstance") { 145 # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement 146 $wrapperObject = "asObject(correspondingElementWrapper)"; 147 148 push(@GenerateEventListenerImpl, <<END); 149 JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl->correspondingElement()); 150 if (!correspondingElementWrapper.isObject()) 151 return JSValue::encode(jsUndefined()); 152END 153 } 154 155 push(@GenerateEventListenerImpl, <<END); 156 JSValue listener = exec->argument(1); 157 if (!listener.isObject()) 158 return JSValue::encode(jsUndefined()); 159 impl->${functionName}EventListener(exec->argument(0).toString(exec)->value(exec), JSEventListener::create(asObject(listener), $wrapperObject, false, currentWorld(exec))$passRefPtrHandling, exec->argument(2).toBoolean(exec)); 160 return JSValue::encode(jsUndefined()); 161END 162 return @GenerateEventListenerImpl; 163} 164 165sub GetParentClassName 166{ 167 my $interface = shift; 168 169 return $interface->extendedAttributes->{"JSLegacyParent"} if $interface->extendedAttributes->{"JSLegacyParent"}; 170 return "JSDOMWrapper" if (@{$interface->parents} eq 0); 171 return "JS" . $interface->parents(0); 172} 173 174sub GetCallbackClassName 175{ 176 my $className = shift; 177 178 return "JS$className"; 179} 180 181sub IndexGetterReturnsStrings 182{ 183 my $type = shift; 184 185 return 1 if $type eq "CSSStyleDeclaration" or $type eq "MediaList" or $type eq "DOMStringList" or $type eq "DOMTokenList" or $type eq "DOMSettableTokenList"; 186 return 0; 187} 188 189sub AddIncludesForTypeInImpl 190{ 191 my $type = shift; 192 my $isCallback = @_ ? shift : 0; 193 194 AddIncludesForType($type, $isCallback, \%implIncludes); 195} 196 197sub AddIncludesForTypeInHeader 198{ 199 my $type = shift; 200 my $isCallback = @_ ? shift : 0; 201 202 AddIncludesForType($type, $isCallback, \%headerIncludes); 203} 204 205my %typesWithoutHeader = ( 206 "Array" => 1, 207 "DOMString" => 1, 208 "DOMTimeStamp" => 1, 209 "any" => 1 210); 211 212sub SkipIncludeHeader 213{ 214 my $type = shift; 215 216 return 1 if $codeGenerator->SkipIncludeHeader($type); 217 return 1 if $codeGenerator->GetSequenceType($type) or $codeGenerator->GetArrayType($type); 218 return $typesWithoutHeader{$type}; 219} 220 221sub AddIncludesForType 222{ 223 my $type = shift; 224 my $isCallback = shift; 225 my $includesRef = shift; 226 227 return if SkipIncludeHeader($type); 228 229 # When we're finished with the one-file-per-class 230 # reorganization, we won't need these special cases. 231 if ($type =~ /SVGPathSeg/) { 232 my $joinedName = $type; 233 $joinedName =~ s/Abs|Rel//; 234 $includesRef->{"${joinedName}.h"} = 1; 235 } elsif ($type eq "XPathNSResolver") { 236 $includesRef->{"JSXPathNSResolver.h"} = 1; 237 $includesRef->{"JSCustomXPathNSResolver.h"} = 1; 238 } elsif ($isCallback && $codeGenerator->IsWrapperType($type)) { 239 $includesRef->{"JS${type}.h"} = 1; 240 } elsif ($codeGenerator->IsTypedArrayType($type)) { 241 $includesRef->{"<wtf/${type}.h>"} = 1; 242 } else { 243 # default, include the same named file 244 $includesRef->{"${type}.h"} = 1; 245 } 246} 247 248sub AddToImplIncludes 249{ 250 my $header = shift; 251 my $conditional = shift; 252 253 if (not $conditional) { 254 $implIncludes{$header} = 1; 255 } elsif (not exists($implIncludes{$header})) { 256 $implIncludes{$header} = $conditional; 257 } else { 258 my $oldValue = $implIncludes{$header}; 259 if ($oldValue ne 1) { 260 my %newValue = (); 261 $newValue{$conditional} = 1; 262 foreach my $condition (split(/\|/, $oldValue)) { 263 $newValue{$condition} = 1; 264 } 265 $implIncludes{$header} = join("|", sort keys %newValue); 266 } 267 } 268} 269 270sub IsScriptProfileType 271{ 272 my $type = shift; 273 return 1 if ($type eq "ScriptProfileNode"); 274 return 0; 275} 276 277sub IsReadonly 278{ 279 my $attribute = shift; 280 return $attribute->isReadOnly && !$attribute->signature->extendedAttributes->{"Replaceable"}; 281} 282 283sub AddTypedefForScriptProfileType 284{ 285 my $type = shift; 286 (my $jscType = $type) =~ s/Script//; 287 288 push(@headerContent, "typedef JSC::$jscType $type;\n\n"); 289} 290 291sub AddClassForwardIfNeeded 292{ 293 my $interfaceName = shift; 294 295 # SVGAnimatedLength/Number/etc. are typedefs to SVGAnimatedTemplate, so don't use class forwards for them! 296 unless ($codeGenerator->IsSVGAnimatedType($interfaceName) or IsScriptProfileType($interfaceName) or $codeGenerator->IsTypedArrayType($interfaceName)) { 297 push(@headerContent, "class $interfaceName;\n\n"); 298 # ScriptProfile and ScriptProfileNode are typedefs to JSC::Profile and JSC::ProfileNode. 299 } elsif (IsScriptProfileType($interfaceName)) { 300 $headerIncludes{"<profiler/ProfileNode.h>"} = 1; 301 AddTypedefForScriptProfileType($interfaceName); 302 } 303} 304 305sub hashTableAccessor 306{ 307 my $noStaticTables = shift; 308 my $className = shift; 309 if ($noStaticTables) { 310 return "get${className}Table(exec)"; 311 } else { 312 return "&${className}Table"; 313 } 314} 315 316sub prototypeHashTableAccessor 317{ 318 my $noStaticTables = shift; 319 my $className = shift; 320 if ($noStaticTables) { 321 return "get${className}PrototypeTable(exec)"; 322 } else { 323 return "&${className}PrototypeTable"; 324 } 325} 326 327sub constructorHashTableAccessor 328{ 329 my $noStaticTables = shift; 330 my $constructorClassName = shift; 331 if ($noStaticTables) { 332 return "get${constructorClassName}Table(exec)"; 333 } else { 334 return "&${constructorClassName}Table"; 335 } 336} 337 338sub GetGenerateIsReachable 339{ 340 my $interface = shift; 341 return $interface->extendedAttributes->{"GenerateIsReachable"}; 342} 343 344sub GetCustomIsReachable 345{ 346 my $interface = shift; 347 return $interface->extendedAttributes->{"CustomIsReachable"}; 348} 349 350sub GenerateGetOwnPropertySlotBody 351{ 352 my ($interface, $interfaceName, $className, $hasAttributes, $inlined) = @_; 353 354 my $namespaceMaybe = ($inlined ? "JSC::" : ""); 355 my $namedGetterFunction = GetNamedGetterFunction($interface); 356 my $indexedGetterFunction = GetIndexedGetterFunction($interface); 357 my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0; 358 359 my @getOwnPropertySlotImpl = (); 360 361 if ($interfaceName eq "NamedNodeMap" or $interfaceName =~ /^HTML\w*Collection$/) { 362 push(@getOwnPropertySlotImpl, " ${namespaceMaybe}JSValue proto = thisObject->prototype();\n"); 363 push(@getOwnPropertySlotImpl, " if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n"); 364 push(@getOwnPropertySlotImpl, " return false;\n\n"); 365 } 366 367 my $manualLookupGetterGeneration = sub { 368 my $requiresManualLookup = ($indexedGetterFunction && !$hasNumericIndexedGetter) || $namedGetterFunction; 369 if ($requiresManualLookup) { 370 push(@getOwnPropertySlotImpl, " const ${namespaceMaybe}HashEntry* entry = getStaticValueSlotEntryWithoutCaching<$className>(exec, propertyName);\n"); 371 push(@getOwnPropertySlotImpl, " if (entry) {\n"); 372 push(@getOwnPropertySlotImpl, " slot.setCustom(thisObject, entry->propertyGetter());\n"); 373 push(@getOwnPropertySlotImpl, " return true;\n"); 374 push(@getOwnPropertySlotImpl, " }\n"); 375 } 376 }; 377 378 if (!$interface->extendedAttributes->{"CustomNamedGetter"}) { 379 &$manualLookupGetterGeneration(); 380 } 381 382 if ($indexedGetterFunction) { 383 push(@getOwnPropertySlotImpl, " unsigned index = propertyName.asIndex();\n"); 384 385 # If the item function returns a string then we let the TreatReturnedNullStringAs handle the cases 386 # where the index is out of range. 387 if (IndexGetterReturnsStrings($interfaceName)) { 388 push(@getOwnPropertySlotImpl, " if (index != PropertyName::NotAnIndex) {\n"); 389 } else { 390 push(@getOwnPropertySlotImpl, " if (index != PropertyName::NotAnIndex && index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n"); 391 } 392 if ($hasNumericIndexedGetter) { 393 push(@getOwnPropertySlotImpl, " slot.setValue(thisObject->getByIndex(exec, index));\n"); 394 } else { 395 push(@getOwnPropertySlotImpl, " slot.setCustomIndex(thisObject, index, indexGetter);\n"); 396 } 397 push(@getOwnPropertySlotImpl, " return true;\n"); 398 push(@getOwnPropertySlotImpl, " }\n"); 399 } 400 401 if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) { 402 push(@getOwnPropertySlotImpl, " if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n"); 403 push(@getOwnPropertySlotImpl, " slot.setCustom(thisObject, thisObject->nameGetter);\n"); 404 push(@getOwnPropertySlotImpl, " return true;\n"); 405 push(@getOwnPropertySlotImpl, " }\n"); 406 if ($inlined) { 407 $headerIncludes{"wtf/text/AtomicString.h"} = 1; 408 } else { 409 $implIncludes{"wtf/text/AtomicString.h"} = 1; 410 } 411 } 412 413 if ($interface->extendedAttributes->{"CustomNamedGetter"}) { 414 &$manualLookupGetterGeneration(); 415 } 416 417 if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) { 418 push(@getOwnPropertySlotImpl, " if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n"); 419 push(@getOwnPropertySlotImpl, " return true;\n"); 420 } 421 422 if ($hasAttributes) { 423 if ($inlined) { 424 die "Cannot inline if NoStaticTables is set." if ($interface->extendedAttributes->{"JSNoStaticTables"}); 425 push(@getOwnPropertySlotImpl, " return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, s_info.staticPropHashTable, thisObject, propertyName, slot);\n"); 426 } else { 427 push(@getOwnPropertySlotImpl, " return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, " . hashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n"); 428 } 429 } else { 430 push(@getOwnPropertySlotImpl, " return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n"); 431 } 432 433 return @getOwnPropertySlotImpl; 434} 435 436sub GenerateGetOwnPropertyDescriptorBody 437{ 438 my ($interface, $interfaceName, $className, $hasAttributes, $inlined) = @_; 439 440 my $namespaceMaybe = ($inlined ? "JSC::" : ""); 441 my $namedGetterFunction = GetNamedGetterFunction($interface); 442 my $indexedGetterFunction = GetIndexedGetterFunction($interface); 443 my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0; 444 445 446 my @getOwnPropertyDescriptorImpl = (); 447 if ($interface->extendedAttributes->{"CheckSecurity"}) { 448 if ($interfaceName eq "DOMWindow") { 449 $implIncludes{"BindingSecurity.h"} = 1; 450 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, jsCast<$className*>(thisObject)->impl()))\n"); 451 } else { 452 push(@implContent, " if (!shouldAllowAccessToFrame(exec, thisObject->impl()->frame()))\n"); 453 } 454 push(@implContent, " return false;\n"); 455 } 456 457 if ($interfaceName eq "NamedNodeMap" or $interfaceName =~ /^HTML\w*Collection$/) { 458 push(@getOwnPropertyDescriptorImpl, " ${namespaceMaybe}JSValue proto = thisObject->prototype();\n"); 459 push(@getOwnPropertyDescriptorImpl, " if (proto.isObject() && jsCast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n"); 460 push(@getOwnPropertyDescriptorImpl, " return false;\n\n"); 461 } 462 463 my $manualLookupGetterGeneration = sub { 464 my $requiresManualLookup = ($indexedGetterFunction && !$hasNumericIndexedGetter) || $namedGetterFunction; 465 if ($requiresManualLookup) { 466 push(@getOwnPropertyDescriptorImpl, " const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n"); 467 push(@getOwnPropertyDescriptorImpl, " if (entry) {\n"); 468 push(@getOwnPropertyDescriptorImpl, " PropertySlot slot;\n"); 469 push(@getOwnPropertyDescriptorImpl, " slot.setCustom(thisObject, entry->propertyGetter());\n"); 470 push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());\n"); 471 push(@getOwnPropertyDescriptorImpl, " return true;\n"); 472 push(@getOwnPropertyDescriptorImpl, " }\n"); 473 } 474 }; 475 476 if (!$interface->extendedAttributes->{"CustomNamedGetter"}) { 477 &$manualLookupGetterGeneration(); 478 } 479 480 if ($indexedGetterFunction) { 481 push(@getOwnPropertyDescriptorImpl, " unsigned index = propertyName.asIndex();\n"); 482 push(@getOwnPropertyDescriptorImpl, " if (index != PropertyName::NotAnIndex && index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n"); 483 if ($hasNumericIndexedGetter) { 484 # Assume that if there's a setter, the index will be writable 485 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) { 486 push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete);\n"); 487 } else { 488 push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n"); 489 } 490 } else { 491 push(@getOwnPropertyDescriptorImpl, " ${namespaceMaybe}PropertySlot slot;\n"); 492 push(@getOwnPropertyDescriptorImpl, " slot.setCustomIndex(thisObject, index, indexGetter);\n"); 493 # Assume that if there's a setter, the index will be writable 494 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) { 495 push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete);\n"); 496 } else { 497 push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n"); 498 } 499 } 500 push(@getOwnPropertyDescriptorImpl, " return true;\n"); 501 push(@getOwnPropertyDescriptorImpl, " }\n"); 502 } 503 504 if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) { 505 push(@getOwnPropertyDescriptorImpl, " if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n"); 506 push(@getOwnPropertyDescriptorImpl, " ${namespaceMaybe}PropertySlot slot;\n"); 507 push(@getOwnPropertyDescriptorImpl, " slot.setCustom(thisObject, nameGetter);\n"); 508 push(@getOwnPropertyDescriptorImpl, " descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);\n"); 509 push(@getOwnPropertyDescriptorImpl, " return true;\n"); 510 push(@getOwnPropertyDescriptorImpl, " }\n"); 511 if ($inlined) { 512 $headerIncludes{"wtf/text/AtomicString.h"} = 1; 513 } else { 514 $implIncludes{"wtf/text/AtomicString.h"} = 1; 515 } 516 } 517 518 if ($interface->extendedAttributes->{"CustomNamedGetter"}) { 519 &$manualLookupGetterGeneration(); 520 } 521 522 if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) { 523 push(@getOwnPropertyDescriptorImpl, " if (thisObject->getOwnPropertyDescriptorDelegate(exec, propertyName, descriptor))\n"); 524 push(@getOwnPropertyDescriptorImpl, " return true;\n"); 525 } 526 527 if ($hasAttributes) { 528 if ($inlined) { 529 die "Cannot inline if NoStaticTables is set." if ($interface->extendedAttributes->{"JSNoStaticTables"}); 530 push(@getOwnPropertyDescriptorImpl, " return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, s_info.staticPropHashTable, thisObject, propertyName, descriptor);\n"); 531 } else { 532 push(@getOwnPropertyDescriptorImpl, " return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, " . hashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n"); 533 } 534 } else { 535 push(@getOwnPropertyDescriptorImpl, " return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);\n"); 536 } 537 538 return @getOwnPropertyDescriptorImpl; 539} 540 541sub GenerateHeaderContentHeader 542{ 543 my $interface = shift; 544 my $className = "JS" . $interface->name; 545 546 my @headerContentHeader = split("\r", $headerTemplate); 547 548 # - Add header protection 549 push(@headerContentHeader, "\n#ifndef $className" . "_h"); 550 push(@headerContentHeader, "\n#define $className" . "_h\n\n"); 551 552 my $conditionalString = $codeGenerator->GenerateConditionalString($interface); 553 push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString; 554 return @headerContentHeader; 555} 556 557sub GenerateImplementationContentHeader 558{ 559 my $interface = shift; 560 my $className = "JS" . $interface->name; 561 562 my @implContentHeader = split("\r", $headerTemplate); 563 564 push(@implContentHeader, "\n#include \"config.h\"\n"); 565 my $conditionalString = $codeGenerator->GenerateConditionalString($interface); 566 push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString; 567 push(@implContentHeader, "#include \"$className.h\"\n\n"); 568 return @implContentHeader; 569} 570 571my %usesToJSNewlyCreated = ( 572 "CDATASection" => 1, 573 "Element" => 1, 574 "Node" => 1, 575 "Text" => 1, 576 "Touch" => 1, 577 "TouchList" => 1 578); 579 580sub ShouldGenerateToJSDeclaration 581{ 582 my ($hasParent, $interface) = @_; 583 return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"}); 584 return 1 if (!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"} or $interface->extendedAttributes->{"CustomToJSObject"}); 585 return 0; 586} 587 588sub ShouldGenerateToJSImplementation 589{ 590 my ($hasParent, $interface) = @_; 591 return 0 if ($interface->extendedAttributes->{"SuppressToJSObject"}); 592 return 1 if ((!$hasParent or $interface->extendedAttributes->{"JSGenerateToJSObject"}) and !$interface->extendedAttributes->{"CustomToJSObject"}); 593 return 0; 594} 595 596sub GetAttributeGetterName 597{ 598 my ($interfaceName, $className, $attribute) = @_; 599 if ($attribute->isStatic) { 600 return $codeGenerator->WK_lcfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name); 601 } 602 return "js" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : ""); 603} 604 605sub GetAttributeSetterName 606{ 607 my ($interfaceName, $className, $attribute) = @_; 608 if ($attribute->isStatic) { 609 return "set" . $codeGenerator->WK_ucfirst($className) . "Constructor" . $codeGenerator->WK_ucfirst($attribute->signature->name); 610 } 611 return "setJS" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : ""); 612} 613 614sub GetFunctionName 615{ 616 my ($className, $function) = @_; 617 my $kind = $function->isStatic ? "Constructor" : "Prototype"; 618 return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($function->signature->name); 619} 620 621sub GetSpecialAccessorFunctionForType 622{ 623 my $interface = shift; 624 my $special = shift; 625 my $firstParameterType = shift; 626 my $numberOfParameters = shift; 627 628 foreach my $function (@{$interface->functions}, @{$interface->anonymousFunctions}) { 629 my $specials = $function->signature->specials; 630 my $specialExists = grep { $_ eq $special } @$specials; 631 my $parameters = $function->parameters; 632 if ($specialExists and scalar(@$parameters) == $numberOfParameters and $parameters->[0]->type eq $firstParameterType) { 633 return $function; 634 } 635 } 636 637 return 0; 638} 639 640sub GetIndexedGetterFunction 641{ 642 my $interface = shift; 643 return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1); 644} 645 646sub GetNamedGetterFunction 647{ 648 my $interface = shift; 649 return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1); 650} 651 652sub GenerateHeader 653{ 654 my $object = shift; 655 my $interface = shift; 656 657 my $interfaceName = $interface->name; 658 my $className = "JS$interfaceName"; 659 my @ancestorInterfaceNames = (); 660 my %structureFlags = (); 661 662 # We only support multiple parents with SVG (for now). 663 if (@{$interface->parents} > 1) { 664 die "A class can't have more than one parent" unless $interfaceName =~ /SVG/; 665 $codeGenerator->AddMethodsConstantsAndAttributesFromParentInterfaces($interface, \@ancestorInterfaceNames); 666 } 667 668 my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"}; 669 my $hasRealParent = @{$interface->parents} > 0; 670 my $hasParent = $hasLegacyParent || $hasRealParent; 671 my $parentClassName = GetParentClassName($interface); 672 my $needsMarkChildren = $interface->extendedAttributes->{"JSCustomMarkFunction"} || $interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget"; 673 674 # - Add default header template and header protection 675 push(@headerContentHeader, GenerateHeaderContentHeader($interface)); 676 677 if ($hasParent) { 678 $headerIncludes{"$parentClassName.h"} = 1; 679 } else { 680 $headerIncludes{"JSDOMBinding.h"} = 1; 681 $headerIncludes{"<runtime/JSGlobalObject.h>"} = 1; 682 if ($interface->isException) { 683 $headerIncludes{"<runtime/ErrorPrototype.h>"} = 1; 684 } else { 685 $headerIncludes{"<runtime/ObjectPrototype.h>"} = 1; 686 } 687 } 688 689 if ($interface->extendedAttributes->{"CustomCall"}) { 690 $headerIncludes{"<runtime/CallData.h>"} = 1; 691 } 692 693 if ($interface->extendedAttributes->{"JSInlineGetOwnPropertySlot"}) { 694 $headerIncludes{"<runtime/Lookup.h>"} = 1; 695 } 696 697 if ($hasParent && $interface->extendedAttributes->{"JSGenerateToNativeObject"}) { 698 if ($codeGenerator->IsTypedArrayType($interfaceName)) { 699 $headerIncludes{"<wtf/$interfaceName.h>"} = 1; 700 } else { 701 $headerIncludes{"$interfaceName.h"} = 1; 702 } 703 } 704 705 $headerIncludes{"<runtime/JSObject.h>"} = 1; 706 $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/; 707 708 my $implType = $interfaceName; 709 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType); 710 $implType = $svgNativeType if $svgNativeType; 711 712 my $svgPropertyOrListPropertyType; 713 $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType; 714 $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType; 715 716 my $numConstants = @{$interface->constants}; 717 my $numAttributes = @{$interface->attributes}; 718 my $numFunctions = @{$interface->functions}; 719 720 push(@headerContent, "\nnamespace WebCore {\n\n"); 721 722 if ($codeGenerator->IsSVGAnimatedType($interfaceName)) { 723 $headerIncludes{"$interfaceName.h"} = 1; 724 } else { 725 # Implementation class forward declaration 726 if ($interfaceName eq "DOMWindow" || $interface->extendedAttributes->{"IsWorkerContext"}) { 727 AddClassForwardIfNeeded($interfaceName) unless $svgPropertyOrListPropertyType; 728 } 729 } 730 731 AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow"; 732 AddClassForwardIfNeeded("JSDictionary") if $codeGenerator->IsConstructorTemplate($interface, "Event"); 733 734 # Class declaration 735 push(@headerContent, "class $className : public $parentClassName {\n"); 736 737 # Static create methods 738 push(@headerContent, "public:\n"); 739 push(@headerContent, " typedef $parentClassName Base;\n"); 740 if ($interfaceName eq "DOMWindow") { 741 push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* windowShell)\n"); 742 push(@headerContent, " {\n"); 743 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, impl, windowShell);\n"); 744 push(@headerContent, " ptr->finishCreation(vm, windowShell);\n"); 745 push(@headerContent, " vm.heap.addFinalizer(ptr, destroy);\n"); 746 push(@headerContent, " return ptr;\n"); 747 push(@headerContent, " }\n\n"); 748 } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) { 749 push(@headerContent, " static $className* create(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<$implType> impl)\n"); 750 push(@headerContent, " {\n"); 751 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, impl);\n"); 752 push(@headerContent, " ptr->finishCreation(vm);\n"); 753 push(@headerContent, " vm.heap.addFinalizer(ptr, destroy);\n"); 754 push(@headerContent, " return ptr;\n"); 755 push(@headerContent, " }\n\n"); 756 } elsif ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) { 757 AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType; 758 push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n"); 759 push(@headerContent, " {\n"); 760 push(@headerContent, " globalObject->masqueradesAsUndefinedWatchpoint()->notifyWrite();\n"); 761 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, globalObject, impl);\n"); 762 push(@headerContent, " ptr->finishCreation(globalObject->vm());\n"); 763 push(@headerContent, " return ptr;\n"); 764 push(@headerContent, " }\n\n"); 765 } else { 766 AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType; 767 push(@headerContent, " static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n"); 768 push(@headerContent, " {\n"); 769 push(@headerContent, " $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->vm().heap)) $className(structure, globalObject, impl);\n"); 770 push(@headerContent, " ptr->finishCreation(globalObject->vm());\n"); 771 push(@headerContent, " return ptr;\n"); 772 push(@headerContent, " }\n\n"); 773 } 774 775 if ($interfaceName eq "DOMWindow" || $interface->extendedAttributes->{"IsWorkerContext"}) { 776 push(@headerContent, " static const bool needsDestruction = false;\n\n"); 777 } 778 779 # Prototype 780 push(@headerContent, " static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n") unless ($interface->extendedAttributes->{"ExtendsDOMGlobalObject"}); 781 782 $headerTrailingIncludes{"${className}Custom.h"} = 1 if $interface->extendedAttributes->{"JSCustomHeader"}; 783 784 $implIncludes{"${className}Custom.h"} = 1 if !$interface->extendedAttributes->{"JSCustomHeader"} && ($interface->extendedAttributes->{"CustomPutFunction"} || $interface->extendedAttributes->{"CustomNamedSetter"}); 785 786 my $namedGetterFunction = GetNamedGetterFunction($interface); 787 my $indexedGetterFunction = GetIndexedGetterFunction($interface); 788 my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0; 789 790 my $hasImpureNamedGetter = 791 $namedGetterFunction 792 || $interface->extendedAttributes->{"CustomNamedGetter"} 793 || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}; 794 795 my $hasComplexGetter = 796 $indexedGetterFunction 797 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"} 798 || $hasImpureNamedGetter; 799 800 my $hasGetter = $numAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"} || $hasComplexGetter; 801 802 if ($hasImpureNamedGetter) { 803 $structureFlags{"JSC::HasImpureGetOwnPropertySlot"} = 1; 804 } 805 806 # Getters 807 if ($hasGetter) { 808 push(@headerContent, " static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n"); 809 push(@headerContent, " static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n"); 810 push(@headerContent, " static bool getOwnPropertySlotByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($hasComplexGetter); 811 push(@headerContent, " bool getOwnPropertySlotDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n") if $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}; 812 push(@headerContent, " bool getOwnPropertyDescriptorDelegate(JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n") if $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}; 813 $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1; 814 $structureFlags{"JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero"} = 1; 815 } 816 817 # Check if we have any writable properties 818 my $hasReadWriteProperties = 0; 819 foreach (@{$interface->attributes}) { 820 if (!IsReadonly($_) && !$_->isStatic) { 821 $hasReadWriteProperties = 1; 822 } 823 } 824 825 my $hasComplexSetter = 826 $interface->extendedAttributes->{"CustomPutFunction"} 827 || $interface->extendedAttributes->{"CustomNamedSetter"} 828 || $interface->extendedAttributes->{"CustomIndexedSetter"}; 829 830 my $hasSetter = $hasReadWriteProperties || $hasComplexSetter; 831 832 # Getters 833 if ($hasSetter) { 834 push(@headerContent, " static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n"); 835 push(@headerContent, " static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n") if ($hasComplexSetter); 836 push(@headerContent, " bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n") if $interface->extendedAttributes->{"CustomNamedSetter"}; 837 } 838 839 if (!$hasParent) { 840 push(@headerContent, " static void destroy(JSC::JSCell*);\n"); 841 push(@headerContent, " ~${className}();\n"); 842 } 843 844 # Class info 845 if ($interfaceName eq "Node") { 846 push(@headerContent, " static WEBKIT_EXPORTDATA const JSC::ClassInfo s_info;\n\n"); 847 } else { 848 push(@headerContent, " static const JSC::ClassInfo s_info;\n\n"); 849 } 850 # Structure ID 851 if ($interfaceName eq "DOMWindow") { 852 $structureFlags{"JSC::ImplementsHasInstance"} = 1; 853 } 854 push(@headerContent, " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n"); 855 push(@headerContent, " {\n"); 856 if ($interfaceName eq "DOMWindow" || $interface->extendedAttributes->{"IsWorkerContext"}) { 857 push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), &s_info);\n"); 858 } else { 859 push(@headerContent, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n"); 860 } 861 push(@headerContent, " }\n\n"); 862 863 # Custom pushEventHandlerScope function 864 push(@headerContent, " JSC::JSScope* pushEventHandlerScope(JSC::ExecState*, JSC::JSScope*) const;\n\n") if $interface->extendedAttributes->{"JSCustomPushEventHandlerScope"}; 865 866 # Custom call functions 867 push(@headerContent, " static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $interface->extendedAttributes->{"CustomCall"}; 868 869 # Custom deleteProperty function 870 push(@headerContent, " static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"}; 871 push(@headerContent, " static bool deletePropertyByIndex(JSC::JSCell*, JSC::ExecState*, unsigned);\n") if $interface->extendedAttributes->{"CustomDeleteProperty"}; 872 873 # Custom getPropertyNames function exists on DOMWindow 874 if ($interfaceName eq "DOMWindow") { 875 push(@headerContent, " static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n"); 876 $structureFlags{"JSC::OverridesGetPropertyNames"} = 1; 877 } 878 879 # Custom getOwnPropertyNames function 880 if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction) { 881 push(@headerContent, " static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n"); 882 $structureFlags{"JSC::OverridesGetPropertyNames"} = 1; 883 } 884 885 # Custom defineOwnProperty function 886 push(@headerContent, " static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnProperty"}; 887 888 # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'. 889 if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) { 890 $structureFlags{"JSC::MasqueradesAsUndefined"} = 1; 891 } 892 893 # Constructor object getter 894 unless ($interface->extendedAttributes->{"NoInterfaceObject"}) { 895 push(@headerContent, " static JSC::JSValue getConstructor(JSC::ExecState*, JSC::JSGlobalObject*);\n"); 896 push(@headerContent, " static JSC::JSValue getNamedConstructor(JSC::ExecState*, JSC::JSGlobalObject*);\n") if $interface->extendedAttributes->{"NamedConstructor"}; 897 } 898 899 my $numCustomFunctions = 0; 900 my $numCustomAttributes = 0; 901 902 # Attribute and function enums 903 if ($numAttributes > 0) { 904 foreach (@{$interface->attributes}) { 905 my $attribute = $_; 906 $numCustomAttributes++ if HasCustomGetter($attribute->signature->extendedAttributes); 907 $numCustomAttributes++ if HasCustomSetter($attribute->signature->extendedAttributes); 908 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) { 909 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature); 910 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString; 911 push(@headerContent, " JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n"); 912 $numCachedAttributes++; 913 $needsMarkChildren = 1; 914 push(@headerContent, "#endif\n") if $conditionalString; 915 } 916 } 917 } 918 919 # visit function 920 if ($needsMarkChildren) { 921 push(@headerContent, " static void visitChildren(JSCell*, JSC::SlotVisitor&);\n\n"); 922 $structureFlags{"JSC::OverridesVisitChildren"} = 1; 923 } 924 925 if ($numCustomAttributes > 0) { 926 push(@headerContent, "\n // Custom attributes\n"); 927 928 foreach my $attribute (@{$interface->attributes}) { 929 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature); 930 if (HasCustomGetter($attribute->signature->extendedAttributes)) { 931 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString; 932 my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name); 933 push(@headerContent, " JSC::JSValue " . $methodName . "(JSC::ExecState*) const;\n"); 934 push(@headerContent, "#endif\n") if $conditionalString; 935 } 936 if (HasCustomSetter($attribute->signature->extendedAttributes) && !IsReadonly($attribute)) { 937 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString; 938 push(@headerContent, " void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue);\n"); 939 push(@headerContent, "#endif\n") if $conditionalString; 940 } 941 } 942 } 943 944 foreach my $function (@{$interface->functions}) { 945 $numCustomFunctions++ if HasCustomMethod($function->signature->extendedAttributes); 946 } 947 948 if ($numCustomFunctions > 0) { 949 push(@headerContent, "\n // Custom functions\n"); 950 foreach my $function (@{$interface->functions}) { 951 next unless HasCustomMethod($function->signature->extendedAttributes); 952 next if $function->{overloads} && $function->{overloadIndex} != 1; 953 my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature); 954 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString; 955 my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name); 956 push(@headerContent, " " . ($function->isStatic ? "static " : "") . "JSC::JSValue " . $functionImplementationName . "(JSC::ExecState*);\n"); 957 push(@headerContent, "#endif\n") if $conditionalString; 958 } 959 } 960 961 if (!$hasParent) { 962 push(@headerContent, " $implType* impl() const { return m_impl; }\n"); 963 push(@headerContent, " void releaseImpl() { m_impl->deref(); m_impl = 0; }\n\n"); 964 push(@headerContent, " void releaseImplIfNotNull()\n"); 965 push(@headerContent, " {\n"); 966 push(@headerContent, " if (m_impl) {\n"); 967 push(@headerContent, " m_impl->deref();\n"); 968 push(@headerContent, " m_impl = 0;\n"); 969 push(@headerContent, " }\n"); 970 push(@headerContent, " }\n\n"); 971 push(@headerContent, "private:\n"); 972 push(@headerContent, " $implType* m_impl;\n"); 973 } elsif ($interface->extendedAttributes->{"JSGenerateToNativeObject"}) { 974 push(@headerContent, " $interfaceName* impl() const\n"); 975 push(@headerContent, " {\n"); 976 push(@headerContent, " return static_cast<$interfaceName*>(Base::impl());\n"); 977 push(@headerContent, " }\n"); 978 } 979 980 if ($codeGenerator->IsTypedArrayType($implType) and ($implType ne "ArrayBufferView") and ($implType ne "ArrayBuffer")) { 981 push(@headerContent, " static const JSC::TypedArrayType TypedArrayStorageType = JSC::"); 982 push(@headerContent, "TypedArrayInt8") if $implType eq "Int8Array"; 983 push(@headerContent, "TypedArrayInt16") if $implType eq "Int16Array"; 984 push(@headerContent, "TypedArrayInt32") if $implType eq "Int32Array"; 985 push(@headerContent, "TypedArrayUint8") if $implType eq "Uint8Array"; 986 push(@headerContent, "TypedArrayUint8Clamped") if $implType eq "Uint8ClampedArray"; 987 push(@headerContent, "TypedArrayUint16") if $implType eq "Uint16Array"; 988 push(@headerContent, "TypedArrayUint32") if $implType eq "Uint32Array"; 989 push(@headerContent, "TypedArrayFloat32") if $implType eq "Float32Array"; 990 push(@headerContent, "TypedArrayFloat64") if $implType eq "Float64Array"; 991 push(@headerContent, ";\n"); 992 push(@headerContent, " intptr_t m_storageLength;\n"); 993 push(@headerContent, " void* m_storage;\n"); 994 } 995 996 push(@headerContent, "protected:\n"); 997 # Constructor 998 if ($interfaceName eq "DOMWindow") { 999 push(@headerContent, " $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>, JSDOMWindowShell*);\n"); 1000 } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) { 1001 push(@headerContent, " $className(JSC::VM&, JSC::Structure*, PassRefPtr<$implType>);\n"); 1002 } else { 1003 push(@headerContent, " $className(JSC::Structure*, JSDOMGlobalObject*, PassRefPtr<$implType>);\n"); 1004 push(@headerContent, " void finishCreation(JSC::VM&);\n"); 1005 } 1006 1007 # structure flags 1008 push(@headerContent, " static const unsigned StructureFlags = "); 1009 foreach my $structureFlag (keys %structureFlags) { 1010 push(@headerContent, $structureFlag . " | "); 1011 } 1012 push(@headerContent, "Base::StructureFlags;\n"); 1013 1014 # Index getter 1015 if ($indexedGetterFunction) { 1016 if ($hasNumericIndexedGetter) { 1017 push(@headerContent, " JSC::JSValue getByIndex(JSC::ExecState*, unsigned index);\n"); 1018 } else { 1019 push(@headerContent, " static JSC::JSValue indexGetter(JSC::ExecState*, JSC::JSValue, unsigned);\n"); 1020 } 1021 } 1022 1023 # Index setter 1024 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) { 1025 push(@headerContent, " void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n"); 1026 } 1027 # Name getter 1028 if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) { 1029 push(@headerContent, "private:\n"); 1030 push(@headerContent, " static bool canGetItemsForName(JSC::ExecState*, $interfaceName*, JSC::PropertyName);\n"); 1031 push(@headerContent, " static JSC::JSValue nameGetter(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n"); 1032 } 1033 1034 push(@headerContent, "};\n\n"); 1035 1036 if ($interface->extendedAttributes->{"JSInlineGetOwnPropertySlot"} && !$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) { 1037 push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertySlot(JSC::JSCell* cell, JSC::ExecState* exec, JSC::PropertyName propertyName, JSC::PropertySlot& slot)\n"); 1038 push(@headerContent, "{\n"); 1039 push(@headerContent, " ${className}* thisObject = JSC::jsCast<${className}*>(cell);\n"); 1040 push(@headerContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 1041 push(@headerContent, GenerateGetOwnPropertySlotBody($interface, $interfaceName, $className, $numAttributes > 0, 1)); 1042 push(@headerContent, "}\n\n"); 1043 push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertyDescriptor(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, JSC::PropertyDescriptor& descriptor)\n"); 1044 push(@headerContent, "{\n"); 1045 push(@headerContent, " ${className}* thisObject = JSC::jsCast<${className}*>(object);\n"); 1046 push(@headerContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 1047 push(@headerContent, GenerateGetOwnPropertyDescriptorBody($interface, $interfaceName, $className, $numAttributes > 0, 1)); 1048 push(@headerContent, "}\n\n"); 1049 } 1050 1051 if (!$hasParent || 1052 GetGenerateIsReachable($interface) || 1053 GetCustomIsReachable($interface) || 1054 $interface->extendedAttributes->{"JSCustomFinalize"} || 1055 $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) { 1056 if ($interfaceName ne "Node" && $codeGenerator->InheritsInterface($interface, "Node")) { 1057 $headerIncludes{"JSNode.h"} = 1; 1058 push(@headerContent, "class JS${interfaceName}Owner : public JSNodeOwner {\n"); 1059 } else { 1060 push(@headerContent, "class JS${interfaceName}Owner : public JSC::WeakHandleOwner {\n"); 1061 } 1062 push(@headerContent, "public:\n"); 1063 push(@headerContent, " virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n"); 1064 push(@headerContent, " virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n"); 1065 push(@headerContent, "};\n"); 1066 push(@headerContent, "\n"); 1067 push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, $implType*)\n"); 1068 push(@headerContent, "{\n"); 1069 push(@headerContent, " DEFINE_STATIC_LOCAL(JS${interfaceName}Owner, js${interfaceName}Owner, ());\n"); 1070 push(@headerContent, " return &js${interfaceName}Owner;\n"); 1071 push(@headerContent, "}\n"); 1072 push(@headerContent, "\n"); 1073 push(@headerContent, "inline void* wrapperContext(DOMWrapperWorld* world, $implType*)\n"); 1074 push(@headerContent, "{\n"); 1075 push(@headerContent, " return world;\n"); 1076 push(@headerContent, "}\n"); 1077 push(@headerContent, "\n"); 1078 } 1079 if (ShouldGenerateToJSDeclaration($hasParent, $interface)) { 1080 push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n"); 1081 } 1082 if (!$hasParent || $interface->extendedAttributes->{"JSGenerateToNativeObject"}) { 1083 if ($interfaceName eq "NodeFilter") { 1084 push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::VM&, JSC::JSValue);\n"); 1085 } elsif ($interfaceName eq "DOMStringList") { 1086 push(@headerContent, "PassRefPtr<DOMStringList> toDOMStringList(JSC::ExecState*, JSC::JSValue);\n"); 1087 } else { 1088 push(@headerContent, "$implType* to${interfaceName}(JSC::JSValue);\n"); 1089 } 1090 } 1091 if ($usesToJSNewlyCreated{$interfaceName}) { 1092 push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, $interfaceName*);\n"); 1093 } 1094 1095 push(@headerContent, "\n"); 1096 1097 # Add prototype declaration. 1098 %structureFlags = (); 1099 push(@headerContent, "class ${className}Prototype : public JSC::JSNonFinalObject {\n"); 1100 push(@headerContent, "public:\n"); 1101 push(@headerContent, " typedef JSC::JSNonFinalObject Base;\n"); 1102 if ($interfaceName ne "DOMWindow" && !$interface->extendedAttributes->{"IsWorkerContext"}) { 1103 push(@headerContent, " static JSC::JSObject* self(JSC::ExecState*, JSC::JSGlobalObject*);\n"); 1104 } 1105 1106 push(@headerContent, " static ${className}Prototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)\n"); 1107 push(@headerContent, " {\n"); 1108 push(@headerContent, " ${className}Prototype* ptr = new (NotNull, JSC::allocateCell<${className}Prototype>(vm.heap)) ${className}Prototype(vm, globalObject, structure);\n"); 1109 push(@headerContent, " ptr->finishCreation(vm);\n"); 1110 push(@headerContent, " return ptr;\n"); 1111 push(@headerContent, " }\n\n"); 1112 1113 push(@headerContent, " static const JSC::ClassInfo s_info;\n"); 1114 if ($numFunctions > 0 || $numConstants > 0) { 1115 push(@headerContent, " static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n"); 1116 push(@headerContent, " static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n"); 1117 $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1; 1118 } 1119 if ($interface->extendedAttributes->{"JSCustomMarkFunction"} or $needsMarkChildren) { 1120 $structureFlags{"JSC::OverridesVisitChildren"} = 1; 1121 } 1122 push(@headerContent, 1123 " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n" . 1124 " {\n" . 1125 " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n" . 1126 " }\n"); 1127 if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) { 1128 push(@headerContent, " static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n"); 1129 push(@headerContent, " bool putDelegate(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n"); 1130 } 1131 1132 # Custom defineOwnProperty function 1133 push(@headerContent, " static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interface->extendedAttributes->{"JSCustomDefineOwnPropertyOnPrototype"}; 1134 1135 push(@headerContent, "\nprivate:\n"); 1136 push(@headerContent, " ${className}Prototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) : JSC::JSNonFinalObject(vm, structure) { }\n"); 1137 1138 # structure flags 1139 push(@headerContent, "protected:\n"); 1140 push(@headerContent, " static const unsigned StructureFlags = "); 1141 foreach my $structureFlag (keys %structureFlags) { 1142 push(@headerContent, $structureFlag . " | "); 1143 } 1144 push(@headerContent, "Base::StructureFlags;\n"); 1145 1146 push(@headerContent, "};\n\n"); 1147 1148 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) { 1149 $headerIncludes{"JSDOMBinding.h"} = 1; 1150 GenerateConstructorDeclaration(\@headerContent, $className, $interface, $interfaceName); 1151 } 1152 1153 if ($numFunctions > 0) { 1154 push(@headerContent,"// Functions\n\n"); 1155 foreach my $function (@{$interface->functions}) { 1156 next if $function->{overloadIndex} && $function->{overloadIndex} > 1; 1157 my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature); 1158 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString; 1159 my $functionName = GetFunctionName($className, $function); 1160 push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n"); 1161 push(@headerContent, "#endif\n") if $conditionalString; 1162 } 1163 } 1164 1165 if ($numAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"}) { 1166 push(@headerContent,"// Attributes\n\n"); 1167 foreach my $attribute (@{$interface->attributes}) { 1168 my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature); 1169 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString; 1170 my $getter = GetAttributeGetterName($interfaceName, $className, $attribute); 1171 push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n"); 1172 if (!IsReadonly($attribute)) { 1173 my $setter = GetAttributeSetterName($interfaceName, $className, $attribute); 1174 push(@headerContent, "void ${setter}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n"); 1175 } 1176 push(@headerContent, "#endif\n") if $conditionalString; 1177 } 1178 1179 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) { 1180 my $getter = "js" . $interfaceName . "Constructor"; 1181 push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n"); 1182 } 1183 1184 if ($interface->extendedAttributes->{"ReplaceableConstructor"}) { 1185 my $constructorFunctionName = "setJS" . $interfaceName . "Constructor"; 1186 push(@headerContent, "void ${constructorFunctionName}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n"); 1187 } 1188 } 1189 1190 if ($numConstants > 0) { 1191 push(@headerContent,"// Constants\n\n"); 1192 foreach my $constant (@{$interface->constants}) { 1193 my $conditionalString = $codeGenerator->GenerateConditionalString($constant); 1194 push(@headerContent, "#if ${conditionalString}\n") if $conditionalString; 1195 my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name); 1196 push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);\n"); 1197 push(@headerContent, "#endif\n") if $conditionalString; 1198 } 1199 } 1200 1201 my $conditionalString = $codeGenerator->GenerateConditionalString($interface); 1202 push(@headerContent, "\n} // namespace WebCore\n\n"); 1203 push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString; 1204 push(@headerContent, "#endif\n"); 1205 1206 # - Generate dependencies. 1207 if ($writeDependencies && @ancestorInterfaceNames) { 1208 push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestorInterfaceNames), "\n"); 1209 push(@depsContent, map { "$_.idl :\n" } @ancestorInterfaceNames); 1210 } 1211} 1212 1213sub GenerateAttributesHashTable($$) 1214{ 1215 my ($object, $interface) = @_; 1216 1217 # FIXME: These should be functions on $interface. 1218 my $interfaceName = $interface->name; 1219 my $className = "JS$interfaceName"; 1220 1221 # - Add all attributes in a hashtable definition 1222 my $numAttributes = @{$interface->attributes}; 1223 $numAttributes++ if !$interface->extendedAttributes->{"NoInterfaceObject"}; 1224 1225 return 0 if !$numAttributes; 1226 1227 my $hashSize = $numAttributes; 1228 my $hashName = $className . "Table"; 1229 1230 my @hashKeys = (); 1231 my @hashSpecials = (); 1232 my @hashValue1 = (); 1233 my @hashValue2 = (); 1234 my %conditionals = (); 1235 1236 my @entries = (); 1237 1238 foreach my $attribute (@{$interface->attributes}) { 1239 next if ($attribute->isStatic); 1240 my $name = $attribute->signature->name; 1241 push(@hashKeys, $name); 1242 1243 my @specials = (); 1244 # As per Web IDL specification, constructor properties on the ECMAScript global object should be 1245 # configurable and should not be enumerable. 1246 my $is_global_constructor = $attribute->signature->type =~ /Constructor$/; 1247 push(@specials, "DontDelete") unless ($attribute->signature->extendedAttributes->{"Deletable"} || $is_global_constructor); 1248 push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor); 1249 push(@specials, "ReadOnly") if IsReadonly($attribute); 1250 my $special = (@specials > 0) ? join(" | ", @specials) : "0"; 1251 push(@hashSpecials, $special); 1252 1253 my $getter = GetAttributeGetterName($interfaceName, $className, $attribute); 1254 push(@hashValue1, $getter); 1255 1256 if (IsReadonly($attribute)) { 1257 push(@hashValue2, "0"); 1258 } else { 1259 my $setter = GetAttributeSetterName($interfaceName, $className, $attribute); 1260 push(@hashValue2, $setter); 1261 } 1262 1263 my $conditional = $attribute->signature->extendedAttributes->{"Conditional"}; 1264 if ($conditional) { 1265 $conditionals{$name} = $conditional; 1266 } 1267 } 1268 1269 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) { 1270 push(@hashKeys, "constructor"); 1271 my $getter = "js" . $interfaceName . "Constructor"; 1272 push(@hashValue1, $getter); 1273 if ($interface->extendedAttributes->{"ReplaceableConstructor"}) { 1274 my $setter = "setJS" . $interfaceName . "Constructor"; 1275 push(@hashValue2, $setter); 1276 push(@hashSpecials, "DontEnum | DontDelete"); 1277 } else { 1278 push(@hashValue2, "0"); 1279 push(@hashSpecials, "DontEnum | ReadOnly"); 1280 } 1281 } 1282 1283 $object->GenerateHashTable($hashName, $hashSize, 1284 \@hashKeys, \@hashSpecials, 1285 \@hashValue1, \@hashValue2, 1286 \%conditionals); 1287 return $numAttributes; 1288} 1289 1290sub GenerateParametersCheckExpression 1291{ 1292 my $numParameters = shift; 1293 my $function = shift; 1294 1295 my @andExpression = (); 1296 push(@andExpression, "argsCount == $numParameters"); 1297 my $parameterIndex = 0; 1298 my %usedArguments = (); 1299 foreach my $parameter (@{$function->parameters}) { 1300 last if $parameterIndex >= $numParameters; 1301 my $value = "arg$parameterIndex"; 1302 my $type = $parameter->type; 1303 1304 # Only DOMString or wrapper types are checked. 1305 # For DOMString with StrictTypeChecking only Null, Undefined and Object 1306 # are accepted for compatibility. Otherwise, no restrictions are made to 1307 # match the non-overloaded behavior. 1308 # FIXME: Implement WebIDL overload resolution algorithm. 1309 if ($codeGenerator->IsStringType($type)) { 1310 if ($parameter->extendedAttributes->{"StrictTypeChecking"}) { 1311 push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isString() || ${value}.isObject())"); 1312 $usedArguments{$parameterIndex} = 1; 1313 } 1314 } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) { 1315 # For Callbacks only checks if the value is null or object. 1316 push(@andExpression, "(${value}.isNull() || ${value}.isFunction())"); 1317 $usedArguments{$parameterIndex} = 1; 1318 } elsif ($codeGenerator->GetArrayType($type) || $codeGenerator->GetSequenceType($type)) { 1319 # FIXME: Add proper support for T[], T[]?, sequence<T> 1320 if ($parameter->isNullable) { 1321 push(@andExpression, "(${value}.isNull() || (${value}.isObject() && isJSArray(${value})))"); 1322 } else { 1323 push(@andExpression, "(${value}.isObject() && isJSArray(${value}))"); 1324 } 1325 $usedArguments{$parameterIndex} = 1; 1326 } elsif (!IsNativeType($type)) { 1327 if ($parameter->isNullable) { 1328 push(@andExpression, "(${value}.isNull() || (${value}.isObject() && asObject(${value})->inherits(&JS${type}::s_info)))"); 1329 } else { 1330 push(@andExpression, "(${value}.isObject() && asObject(${value})->inherits(&JS${type}::s_info))"); 1331 } 1332 $usedArguments{$parameterIndex} = 1; 1333 } 1334 $parameterIndex++; 1335 } 1336 my $res = join(" && ", @andExpression); 1337 $res = "($res)" if @andExpression > 1; 1338 return ($res, keys %usedArguments); 1339} 1340 1341# As per Web IDL specification, the length of a function Object is 1342# its number of mandatory parameters. 1343sub GetFunctionLength 1344{ 1345 my $function = shift; 1346 1347 my $numMandatoryParams = 0; 1348 foreach my $parameter (@{$function->parameters}) { 1349 # Abort as soon as we find the first optional parameter as no mandatory 1350 # parameter can follow an optional one. 1351 last if $parameter->isOptional; 1352 $numMandatoryParams++; 1353 } 1354 return $numMandatoryParams; 1355} 1356 1357sub GenerateFunctionParametersCheck 1358{ 1359 my $function = shift; 1360 1361 my @orExpression = (); 1362 my $numParameters = 0; 1363 my @neededArguments = (); 1364 my $hasVariadic = 0; 1365 my $numMandatoryParams = @{$function->parameters}; 1366 1367 foreach my $parameter (@{$function->parameters}) { 1368 if ($parameter->isOptional) { 1369 my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function); 1370 push(@orExpression, $expression); 1371 push(@neededArguments, @usedArguments); 1372 $numMandatoryParams--; 1373 } 1374 if ($parameter->isVariadic) { 1375 $hasVariadic = 1; 1376 last; 1377 } 1378 $numParameters++; 1379 } 1380 if (!$hasVariadic) { 1381 my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function); 1382 push(@orExpression, $expression); 1383 push(@neededArguments, @usedArguments); 1384 } 1385 return ($numMandatoryParams, join(" || ", @orExpression), @neededArguments); 1386} 1387 1388sub GenerateOverloadedFunction 1389{ 1390 my $function = shift; 1391 my $interface = shift; 1392 my $interfaceName = shift; 1393 1394 # Generate code for choosing the correct overload to call. Overloads are 1395 # chosen based on the total number of arguments passed and the type of 1396 # values passed in non-primitive argument slots. When more than a single 1397 # overload is applicable, precedence is given according to the order of 1398 # declaration in the IDL. 1399 1400 my $kind = $function->isStatic ? "Constructor" : "Prototype"; 1401 my $functionName = "js${interfaceName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name); 1402 1403 push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n"); 1404 push(@implContent, <<END); 1405{ 1406 size_t argsCount = exec->argumentCount(); 1407END 1408 1409 my %fetchedArguments = (); 1410 my $leastNumMandatoryParams = 255; 1411 1412 foreach my $overload (@{$function->{overloads}}) { 1413 my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload); 1414 $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams); 1415 1416 foreach my $parameterIndex (@neededArguments) { 1417 next if exists $fetchedArguments{$parameterIndex}; 1418 push(@implContent, " JSValue arg$parameterIndex(exec->argument($parameterIndex));\n"); 1419 $fetchedArguments{$parameterIndex} = 1; 1420 } 1421 1422 push(@implContent, " if ($parametersCheck)\n"); 1423 push(@implContent, " return ${functionName}$overload->{overloadIndex}(exec);\n"); 1424 } 1425 if ($leastNumMandatoryParams >= 1) { 1426 push(@implContent, " if (argsCount < $leastNumMandatoryParams)\n"); 1427 push(@implContent, " return throwVMError(exec, createNotEnoughArgumentsError(exec));\n"); 1428 } 1429 push(@implContent, <<END); 1430 return throwVMTypeError(exec); 1431} 1432 1433END 1434} 1435 1436sub GetNativeTypeForConversions 1437{ 1438 my $interface = shift; 1439 my $interfaceName = $interface->name; 1440 $interfaceName = $codeGenerator->GetSVGTypeNeedingTearOff($interfaceName) if $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName); 1441 return $interfaceName; 1442} 1443 1444# See http://refspecs.linux-foundation.org/cxxabi-1.83.html. 1445sub GetGnuVTableRefForInterface 1446{ 1447 my $interface = shift; 1448 my $vtableName = GetGnuVTableNameForInterface($interface); 1449 if (!$vtableName) { 1450 return "0"; 1451 } 1452 my $typename = GetNativeTypeForConversions($interface); 1453 my $offset = GetGnuVTableOffsetForType($typename); 1454 return "&" . $vtableName . "[" . $offset . "]"; 1455} 1456 1457sub GetGnuVTableNameForInterface 1458{ 1459 my $interface = shift; 1460 my $typename = GetNativeTypeForConversions($interface); 1461 my $templatePosition = index($typename, "<"); 1462 return "" if $templatePosition != -1; 1463 return "" if GetImplementationLacksVTableForInterface($interface); 1464 return "" if GetSkipVTableValidationForInterface($interface); 1465 return "_ZTV" . GetGnuMangledNameForInterface($interface); 1466} 1467 1468sub GetGnuMangledNameForInterface 1469{ 1470 my $interface = shift; 1471 my $typename = GetNativeTypeForConversions($interface); 1472 my $templatePosition = index($typename, "<"); 1473 if ($templatePosition != -1) { 1474 return ""; 1475 } 1476 my $mangledType = length($typename) . $typename; 1477 my $namespace = GetNamespaceForInterface($interface); 1478 my $mangledNamespace = "N" . length($namespace) . $namespace; 1479 return $mangledNamespace . $mangledType . "E"; 1480} 1481 1482sub GetGnuVTableOffsetForType 1483{ 1484 my $typename = shift; 1485 if ($typename eq "SVGAElement" 1486 || $typename eq "SVGCircleElement" 1487 || $typename eq "SVGClipPathElement" 1488 || $typename eq "SVGDefsElement" 1489 || $typename eq "SVGEllipseElement" 1490 || $typename eq "SVGForeignObjectElement" 1491 || $typename eq "SVGGElement" 1492 || $typename eq "SVGImageElement" 1493 || $typename eq "SVGLineElement" 1494 || $typename eq "SVGPathElement" 1495 || $typename eq "SVGPolyElement" 1496 || $typename eq "SVGPolygonElement" 1497 || $typename eq "SVGPolylineElement" 1498 || $typename eq "SVGRectElement" 1499 || $typename eq "SVGSVGElement" 1500 || $typename eq "SVGStyledLocatableElement" 1501 || $typename eq "SVGStyledTransformableElement" 1502 || $typename eq "SVGSwitchElement" 1503 || $typename eq "SVGTextElement" 1504 || $typename eq "SVGTransformable" 1505 || $typename eq "SVGUseElement") { 1506 return "3"; 1507 } 1508 return "2"; 1509} 1510 1511# See http://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B_Name_Mangling. 1512sub GetWinVTableRefForInterface 1513{ 1514 my $interface = shift; 1515 my $vtableName = GetWinVTableNameForInterface($interface); 1516 return 0 if !$vtableName; 1517 return "__identifier(\"" . $vtableName . "\")"; 1518} 1519 1520sub GetWinVTableNameForInterface 1521{ 1522 my $interface = shift; 1523 my $typename = GetNativeTypeForConversions($interface); 1524 my $templatePosition = index($typename, "<"); 1525 return "" if $templatePosition != -1; 1526 return "" if GetImplementationLacksVTableForInterface($interface); 1527 return "" if GetSkipVTableValidationForInterface($interface); 1528 return "??_7" . GetWinMangledNameForInterface($interface) . "6B@"; 1529} 1530 1531sub GetWinMangledNameForInterface 1532{ 1533 my $interface = shift; 1534 my $typename = GetNativeTypeForConversions($interface); 1535 my $namespace = GetNamespaceForInterface($interface); 1536 return $typename . "@" . $namespace . "@@"; 1537} 1538 1539sub GetNamespaceForInterface 1540{ 1541 my $interface = shift; 1542 return $interface->extendedAttributes->{"ImplementationNamespace"} || "WebCore"; 1543} 1544 1545sub GetImplementationLacksVTableForInterface 1546{ 1547 my $interface = shift; 1548 return $interface->extendedAttributes->{"ImplementationLacksVTable"}; 1549} 1550 1551sub GetSkipVTableValidationForInterface 1552{ 1553 my $interface = shift; 1554 return $interface->extendedAttributes->{"SkipVTableValidation"}; 1555} 1556 1557# URL becomes url, but SetURL becomes setURL. 1558sub ToMethodName 1559{ 1560 my $param = shift; 1561 my $ret = lcfirst($param); 1562 $ret =~ s/hTML/html/ if $ret =~ /^hTML/; 1563 $ret =~ s/uRL/url/ if $ret =~ /^uRL/; 1564 $ret =~ s/jS/js/ if $ret =~ /^jS/; 1565 $ret =~ s/xML/xml/ if $ret =~ /^xML/; 1566 $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/; 1567 $ret =~ s/cSS/css/ if $ret =~ /^cSS/; 1568 1569 # For HTML5 FileSystem API Flags attributes. 1570 # (create is widely used to instantiate an object and must be avoided.) 1571 $ret =~ s/^create/isCreate/ if $ret =~ /^create$/; 1572 $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/; 1573 1574 return $ret; 1575} 1576 1577# Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled. 1578sub GetRuntimeEnableFunctionName 1579{ 1580 my $signature = shift; 1581 1582 # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method. 1583 return "RuntimeEnabledFeatures::" . ToMethodName($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "VALUE_IS_MISSING"); 1584 1585 # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled(). 1586 return "RuntimeEnabledFeatures::" . ToMethodName($signature->name) . "Enabled"; 1587} 1588 1589sub GenerateImplementation 1590{ 1591 my ($object, $interface) = @_; 1592 1593 my $interfaceName = $interface->name; 1594 my $className = "JS$interfaceName"; 1595 1596 my $hasLegacyParent = $interface->extendedAttributes->{"JSLegacyParent"}; 1597 my $hasRealParent = @{$interface->parents} > 0; 1598 my $hasParent = $hasLegacyParent || $hasRealParent; 1599 my $parentClassName = GetParentClassName($interface); 1600 my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface); 1601 my $eventTarget = $interface->extendedAttributes->{"EventTarget"} || ($codeGenerator->InheritsInterface($interface, "EventTarget") && $interface->name ne "EventTarget"); 1602 my $needsMarkChildren = $interface->extendedAttributes->{"JSCustomMarkFunction"} || $interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget"; 1603 1604 my $namedGetterFunction = GetNamedGetterFunction($interface); 1605 my $indexedGetterFunction = GetIndexedGetterFunction($interface); 1606 my $hasNumericIndexedGetter = $indexedGetterFunction ? $codeGenerator->IsNumericType($indexedGetterFunction->signature->type) : 0; 1607 1608 # - Add default header template 1609 push(@implContentHeader, GenerateImplementationContentHeader($interface)); 1610 1611 $implIncludes{"<wtf/GetPtr.h>"} = 1; 1612 $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $indexedGetterFunction; 1613 1614 AddIncludesForTypeInImpl($interfaceName); 1615 1616 @implContent = (); 1617 1618 push(@implContent, "\nusing namespace JSC;\n\n"); 1619 push(@implContent, "namespace WebCore {\n\n"); 1620 1621 my $numAttributes = GenerateAttributesHashTable($object, $interface); 1622 1623 my $numConstants = @{$interface->constants}; 1624 my $numFunctions = @{$interface->functions}; 1625 1626 # - Add all constants 1627 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) { 1628 my $hashSize = $numConstants; 1629 my $hashName = $className . "ConstructorTable"; 1630 1631 my @hashKeys = (); 1632 my @hashValue1 = (); 1633 my @hashValue2 = (); 1634 my @hashSpecials = (); 1635 my %conditionals = (); 1636 1637 # FIXME: we should not need a function for every constant. 1638 foreach my $constant (@{$interface->constants}) { 1639 my $name = $constant->name; 1640 push(@hashKeys, $name); 1641 my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name); 1642 push(@hashValue1, $getter); 1643 push(@hashValue2, "0"); 1644 push(@hashSpecials, "DontDelete | ReadOnly"); 1645 1646 my $implementedBy = $constant->extendedAttributes->{"ImplementedBy"}; 1647 if ($implementedBy) { 1648 $implIncludes{"${implementedBy}.h"} = 1; 1649 } 1650 my $conditional = $constant->extendedAttributes->{"Conditional"}; 1651 if ($conditional) { 1652 $conditionals{$name} = $conditional; 1653 } 1654 } 1655 1656 foreach my $attribute (@{$interface->attributes}) { 1657 next unless ($attribute->isStatic); 1658 my $name = $attribute->signature->name; 1659 push(@hashKeys, $name); 1660 1661 my @specials = (); 1662 push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"}; 1663 push(@specials, "ReadOnly") if IsReadonly($attribute); 1664 my $special = (@specials > 0) ? join(" | ", @specials) : "0"; 1665 push(@hashSpecials, $special); 1666 1667 my $getter = GetAttributeGetterName($interfaceName, $className, $attribute); 1668 push(@hashValue1, $getter); 1669 1670 if (IsReadonly($attribute)) { 1671 push(@hashValue2, "0"); 1672 } else { 1673 my $setter = GetAttributeSetterName($interfaceName, $className, $attribute); 1674 push(@hashValue2, $setter); 1675 } 1676 1677 my $conditional = $attribute->signature->extendedAttributes->{"Conditional"}; 1678 if ($conditional) { 1679 $conditionals{$name} = $conditional; 1680 } 1681 } 1682 1683 foreach my $function (@{$interface->functions}) { 1684 next unless ($function->isStatic); 1685 next if $function->{overloadIndex} && $function->{overloadIndex} > 1; 1686 my $name = $function->signature->name; 1687 push(@hashKeys, $name); 1688 1689 my $functionName = GetFunctionName($className, $function); 1690 push(@hashValue1, $functionName); 1691 1692 my $functionLength = GetFunctionLength($function); 1693 push(@hashValue2, $functionLength); 1694 1695 my @specials = (); 1696 push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"}; 1697 push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"}; 1698 push(@specials, "JSC::Function"); 1699 my $special = (@specials > 0) ? join(" | ", @specials) : "0"; 1700 push(@hashSpecials, $special); 1701 1702 my $conditional = $function->signature->extendedAttributes->{"Conditional"}; 1703 if ($conditional) { 1704 $conditionals{$name} = $conditional; 1705 } 1706 } 1707 1708 $object->GenerateHashTable($hashName, $hashSize, 1709 \@hashKeys, \@hashSpecials, 1710 \@hashValue1, \@hashValue2, 1711 \%conditionals); 1712 1713 push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($interface)); 1714 1715 my $protoClassName = "${className}Prototype"; 1716 GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface); 1717 if ($interface->extendedAttributes->{"NamedConstructor"}) { 1718 GenerateConstructorDefinitions(\@implContent, $className, $protoClassName, $interfaceName, $interface->extendedAttributes->{"NamedConstructor"}, $interface, "GeneratingNamedConstructor"); 1719 } 1720 } 1721 1722 # - Add functions and constants to a hashtable definition 1723 my $hashSize = $numFunctions + $numConstants; 1724 my $hashName = $className . "PrototypeTable"; 1725 1726 my @hashKeys = (); 1727 my @hashValue1 = (); 1728 my @hashValue2 = (); 1729 my @hashSpecials = (); 1730 my %conditionals = (); 1731 1732 # FIXME: we should not need a function for every constant. 1733 foreach my $constant (@{$interface->constants}) { 1734 my $name = $constant->name; 1735 push(@hashKeys, $name); 1736 my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name); 1737 push(@hashValue1, $getter); 1738 push(@hashValue2, "0"); 1739 push(@hashSpecials, "DontDelete | ReadOnly"); 1740 1741 my $conditional = $constant->extendedAttributes->{"Conditional"}; 1742 if ($conditional) { 1743 $conditionals{$name} = $conditional; 1744 } 1745 } 1746 1747 foreach my $function (@{$interface->functions}) { 1748 next if ($function->isStatic); 1749 next if $function->{overloadIndex} && $function->{overloadIndex} > 1; 1750 my $name = $function->signature->name; 1751 push(@hashKeys, $name); 1752 1753 my $functionName = GetFunctionName($className, $function); 1754 push(@hashValue1, $functionName); 1755 1756 my $functionLength = GetFunctionLength($function); 1757 push(@hashValue2, $functionLength); 1758 1759 my @specials = (); 1760 push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"}; 1761 push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"NotEnumerable"}; 1762 push(@specials, "JSC::Function"); 1763 my $special = (@specials > 0) ? join(" | ", @specials) : "0"; 1764 push(@hashSpecials, $special); 1765 1766 my $conditional = $function->signature->extendedAttributes->{"Conditional"}; 1767 if ($conditional) { 1768 $conditionals{$name} = $conditional; 1769 } 1770 } 1771 1772 $object->GenerateHashTable($hashName, $hashSize, 1773 \@hashKeys, \@hashSpecials, 1774 \@hashValue1, \@hashValue2, 1775 \%conditionals); 1776 1777 if ($interface->extendedAttributes->{"JSNoStaticTables"}) { 1778 push(@implContent, "static const HashTable* get${className}PrototypeTable(ExecState* exec)\n"); 1779 push(@implContent, "{\n"); 1780 push(@implContent, " return getHashTableForGlobalData(exec->vm(), &${className}PrototypeTable);\n"); 1781 push(@implContent, "}\n\n"); 1782 push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, 0, get${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n"); 1783 } else { 1784 push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}Prototype\", &Base::s_info, &${className}PrototypeTable, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n"); 1785 } 1786 if ($interfaceName ne "DOMWindow" && !$interface->extendedAttributes->{"IsWorkerContext"}) { 1787 push(@implContent, "JSObject* ${className}Prototype::self(ExecState* exec, JSGlobalObject* globalObject)\n"); 1788 push(@implContent, "{\n"); 1789 push(@implContent, " return getDOMPrototype<${className}>(exec, globalObject);\n"); 1790 push(@implContent, "}\n\n"); 1791 } 1792 1793 if ($numConstants > 0 || $numFunctions > 0) { 1794 push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n"); 1795 push(@implContent, "{\n"); 1796 push(@implContent, " ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n"); 1797 1798 if ($numConstants eq 0 && $numFunctions eq 0) { 1799 push(@implContent, " return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n"); 1800 } elsif ($numConstants eq 0) { 1801 push(@implContent, " return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n"); 1802 } elsif ($numFunctions eq 0) { 1803 push(@implContent, " return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n"); 1804 } else { 1805 push(@implContent, " return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n"); 1806 } 1807 push(@implContent, "}\n\n"); 1808 1809 push(@implContent, "bool ${className}Prototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)\n"); 1810 push(@implContent, "{\n"); 1811 push(@implContent, " ${className}Prototype* thisObject = jsCast<${className}Prototype*>(object);\n"); 1812 1813 if ($numConstants eq 0 && $numFunctions eq 0) { 1814 push(@implContent, " return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);\n"); 1815 } elsif ($numConstants eq 0) { 1816 push(@implContent, " return getStaticFunctionDescriptor<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n"); 1817 } elsif ($numFunctions eq 0) { 1818 push(@implContent, " return getStaticValueDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n"); 1819 } else { 1820 push(@implContent, " return getStaticPropertyDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n"); 1821 } 1822 push(@implContent, "}\n\n"); 1823 } 1824 1825 if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) { 1826 push(@implContent, "void ${className}Prototype::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n"); 1827 push(@implContent, "{\n"); 1828 push(@implContent, " ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n"); 1829 push(@implContent, " if (thisObject->putDelegate(exec, propertyName, value, slot))\n"); 1830 push(@implContent, " return;\n"); 1831 push(@implContent, " Base::put(thisObject, exec, propertyName, value, slot);\n"); 1832 push(@implContent, "}\n\n"); 1833 } 1834 1835 # - Initialize static ClassInfo object 1836 if ($numAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) { 1837 push(@implContent, "static const HashTable* get${className}Table(ExecState* exec)\n"); 1838 push(@implContent, "{\n"); 1839 push(@implContent, " return getHashTableForGlobalData(exec->vm(), &${className}Table);\n"); 1840 push(@implContent, "}\n\n"); 1841 } 1842 1843 push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, "); 1844 1845 if ($numAttributes > 0 && !$interface->extendedAttributes->{"JSNoStaticTables"}) { 1846 push(@implContent, "&${className}Table"); 1847 } else { 1848 push(@implContent, "0"); 1849 } 1850 if ($numAttributes > 0 && $interface->extendedAttributes->{"JSNoStaticTables"}) { 1851 push(@implContent, ", get${className}Table "); 1852 } else { 1853 push(@implContent, ", 0 "); 1854 } 1855 push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n"); 1856 1857 my $implType = $interfaceName; 1858 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType); 1859 $implType = $svgNativeType if $svgNativeType; 1860 1861 my $svgPropertyOrListPropertyType; 1862 $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType; 1863 $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType; 1864 1865 # Constructor 1866 if ($interfaceName eq "DOMWindow") { 1867 AddIncludesForTypeInImpl("JSDOMWindowShell"); 1868 push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n"); 1869 push(@implContent, " : $parentClassName(vm, structure, impl, shell)\n"); 1870 push(@implContent, "{\n"); 1871 push(@implContent, "}\n\n"); 1872 } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) { 1873 AddIncludesForTypeInImpl($interfaceName); 1874 push(@implContent, "${className}::$className(VM& vm, Structure* structure, PassRefPtr<$implType> impl)\n"); 1875 push(@implContent, " : $parentClassName(vm, structure, impl)\n"); 1876 push(@implContent, "{\n"); 1877 push(@implContent, "}\n\n"); 1878 } else { 1879 push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n"); 1880 if ($hasParent) { 1881 push(@implContent, " : $parentClassName(structure, globalObject, impl)\n"); 1882 } else { 1883 push(@implContent, " : $parentClassName(structure, globalObject)\n"); 1884 push(@implContent, " , m_impl(impl.leakRef())\n"); 1885 } 1886 push(@implContent, "{\n"); 1887 push(@implContent, "}\n\n"); 1888 1889 push(@implContent, "void ${className}::finishCreation(VM& vm)\n"); 1890 push(@implContent, "{\n"); 1891 push(@implContent, " Base::finishCreation(vm);\n"); 1892 if ($codeGenerator->IsTypedArrayType($implType) and ($implType ne "ArrayBufferView") and ($implType ne "ArrayBuffer")) { 1893 push(@implContent, " TypedArrayDescriptor descriptor(&${className}::s_info, OBJECT_OFFSETOF(${className}, m_storage), OBJECT_OFFSETOF(${className}, m_storageLength));\n"); 1894 push(@implContent, " vm.registerTypedArrayDescriptor(impl(), descriptor);\n"); 1895 push(@implContent, " m_storage = impl()->data();\n"); 1896 push(@implContent, " m_storageLength = impl()->length();\n"); 1897 } 1898 push(@implContent, " ASSERT(inherits(&s_info));\n"); 1899 push(@implContent, "}\n\n"); 1900 } 1901 1902 if (!$interface->extendedAttributes->{"ExtendsDOMGlobalObject"}) { 1903 push(@implContent, "JSObject* ${className}::createPrototype(ExecState* exec, JSGlobalObject* globalObject)\n"); 1904 push(@implContent, "{\n"); 1905 if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") { 1906 push(@implContent, " return ${className}Prototype::create(exec->vm(), globalObject, ${className}Prototype::createStructure(exec->vm(), globalObject, ${parentClassName}Prototype::self(exec, globalObject)));\n"); 1907 } else { 1908 my $prototype = $interface->isException ? "errorPrototype" : "objectPrototype"; 1909 push(@implContent, " return ${className}Prototype::create(exec->vm(), globalObject, ${className}Prototype::createStructure(globalObject->vm(), globalObject, globalObject->${prototype}()));\n"); 1910 } 1911 push(@implContent, "}\n\n"); 1912 } 1913 1914 if (!$hasParent) { 1915 # FIXME: This destroy function should not be necessary, as 1916 # a finalizer should be called for each DOM object wrapper. 1917 # However, that seems not to be the case, so this has been 1918 # added back to avoid leaking while we figure out why the 1919 # finalizers are not always getting called. The work tracking 1920 # the finalizer issue is being tracked in http://webkit.org/b/75451 1921 push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n"); 1922 push(@implContent, "{\n"); 1923 push(@implContent, " ${className}* thisObject = static_cast<${className}*>(cell);\n"); 1924 push(@implContent, " thisObject->${className}::~${className}();\n"); 1925 push(@implContent, "}\n\n"); 1926 1927 # We also need a destructor for the allocateCell to work properly with the destructor-free part of the heap. 1928 # Otherwise, these destroy functions/destructors won't get called. 1929 push(@implContent, "${className}::~${className}()\n"); 1930 push(@implContent, "{\n"); 1931 push(@implContent, " releaseImplIfNotNull();\n"); 1932 push(@implContent, "}\n\n"); 1933 } 1934 1935 my $hasGetter = $numAttributes > 0 1936 || !$interface->extendedAttributes->{"NoInterfaceObject"} 1937 || $indexedGetterFunction 1938 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"} 1939 || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"} 1940 || $namedGetterFunction 1941 || $interface->extendedAttributes->{"CustomNamedGetter"}; 1942 1943 # Attributes 1944 if ($hasGetter) { 1945 if (!$interface->extendedAttributes->{"JSInlineGetOwnPropertySlot"} && !$interface->extendedAttributes->{"CustomGetOwnPropertySlot"}) { 1946 push(@implContent, "bool ${className}::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n"); 1947 push(@implContent, "{\n"); 1948 push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n"); 1949 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 1950 push(@implContent, GenerateGetOwnPropertySlotBody($interface, $interfaceName, $className, $numAttributes > 0, 0)); 1951 push(@implContent, "}\n\n"); 1952 push(@implContent, "bool ${className}::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)\n"); 1953 push(@implContent, "{\n"); 1954 push(@implContent, " ${className}* thisObject = jsCast<${className}*>(object);\n"); 1955 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 1956 push(@implContent, GenerateGetOwnPropertyDescriptorBody($interface, $interfaceName, $className, $numAttributes > 0, 0)); 1957 push(@implContent, "}\n\n"); 1958 } 1959 1960 if ($indexedGetterFunction || $namedGetterFunction 1961 || $interface->extendedAttributes->{"CustomNamedGetter"} 1962 || $interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) { 1963 push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned index, PropertySlot& slot)\n"); 1964 push(@implContent, "{\n"); 1965 push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n"); 1966 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 1967 1968 # Sink the int-to-string conversion that happens when we create a PropertyName 1969 # to the point where we actually need it. 1970 my $generatedPropertyName = 0; 1971 my $propertyNameGeneration = sub { 1972 if ($generatedPropertyName) { 1973 return; 1974 } 1975 push(@implContent, " PropertyName propertyName = Identifier::from(exec, index);\n"); 1976 $generatedPropertyName = 1; 1977 }; 1978 1979 if ($indexedGetterFunction) { 1980 if (IndexGetterReturnsStrings($interfaceName)) { 1981 push(@implContent, " if (index <= MAX_ARRAY_INDEX) {\n"); 1982 } else { 1983 push(@implContent, " if (index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n"); 1984 } 1985 if ($hasNumericIndexedGetter) { 1986 push(@implContent, " slot.setValue(thisObject->getByIndex(exec, index));\n"); 1987 } else { 1988 push(@implContent, " slot.setCustomIndex(thisObject, index, thisObject->indexGetter);\n"); 1989 } 1990 push(@implContent, " return true;\n"); 1991 push(@implContent, " }\n"); 1992 } 1993 1994 if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) { 1995 &$propertyNameGeneration(); 1996 push(@implContent, " if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n"); 1997 push(@implContent, " slot.setCustom(thisObject, thisObject->nameGetter);\n"); 1998 push(@implContent, " return true;\n"); 1999 push(@implContent, " }\n"); 2000 $implIncludes{"wtf/text/AtomicString.h"} = 1; 2001 } 2002 2003 if ($interface->extendedAttributes->{"JSCustomGetOwnPropertySlotAndDescriptor"}) { 2004 &$propertyNameGeneration(); 2005 push(@implContent, " if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n"); 2006 push(@implContent, " return true;\n"); 2007 } 2008 2009 push(@implContent, " return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);\n"); 2010 push(@implContent, "}\n\n"); 2011 } 2012 2013 if ($numAttributes > 0) { 2014 foreach my $attribute (@{$interface->attributes}) { 2015 my $name = $attribute->signature->name; 2016 my $type = $attribute->signature->type; 2017 my $isNullable = $attribute->signature->isNullable; 2018 $codeGenerator->AssertNotSequenceType($type); 2019 my $getFunctionName = GetAttributeGetterName($interfaceName, $className, $attribute); 2020 my $implGetterFunctionName = $codeGenerator->WK_lcfirst($name); 2021 2022 my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature); 2023 push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString; 2024 2025 push(@implContent, "JSValue ${getFunctionName}(ExecState* exec, JSValue slotBase, PropertyName)\n"); 2026 push(@implContent, "{\n"); 2027 2028 if (!$attribute->isStatic || $attribute->signature->type =~ /Constructor$/) { 2029 push(@implContent, " ${className}* castedThis = jsCast<$className*>(asObject(slotBase));\n"); 2030 } else { 2031 push(@implContent, " UNUSED_PARAM(slotBase);\n"); 2032 } 2033 2034 # Global constructors can be disabled at runtime. 2035 if ($attribute->signature->type =~ /Constructor$/) { 2036 if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) { 2037 AddToImplIncludes("RuntimeEnabledFeatures.h"); 2038 my $enable_function = GetRuntimeEnableFunctionName($attribute->signature); 2039 push(@implContent, " if (!${enable_function}())\n"); 2040 push(@implContent, " return jsUndefined();\n"); 2041 } elsif ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) { 2042 AddToImplIncludes("Frame.h"); 2043 AddToImplIncludes("Settings.h"); 2044 my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled"; 2045 push(@implContent, " Settings* settings = castedThis->impl()->frame() ? castedThis->impl()->frame()->settings() : 0;\n"); 2046 push(@implContent, " if (!settings || !settings->$enable_function())\n"); 2047 push(@implContent, " return jsUndefined();\n"); 2048 } 2049 } 2050 2051 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) { 2052 $needsMarkChildren = 1; 2053 } 2054 2055 if ($interface->extendedAttributes->{"CheckSecurity"} && 2056 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"} && 2057 !$attribute->signature->extendedAttributes->{"DoNotCheckSecurityOnGetter"}) { 2058 $implIncludes{"BindingSecurity.h"} = 1; 2059 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n"); 2060 push(@implContent, " return jsUndefined();\n"); 2061 } 2062 2063 if (HasCustomGetter($attribute->signature->extendedAttributes)) { 2064 push(@implContent, " return castedThis->$implGetterFunctionName(exec);\n"); 2065 } elsif ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) { 2066 $implIncludes{"JSDOMBinding.h"} = 1; 2067 push(@implContent, " $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n"); 2068 push(@implContent, " return shouldAllowAccessToNode(exec, impl->" . $attribute->signature->name . "()) ? " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl->$implGetterFunctionName()", "castedThis") . " : jsNull();\n"); 2069 } elsif ($type eq "EventListener") { 2070 $implIncludes{"EventListener.h"} = 1; 2071 push(@implContent, " UNUSED_PARAM(exec);\n"); 2072 push(@implContent, " $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n"); 2073 push(@implContent, " if (EventListener* listener = impl->$implGetterFunctionName()) {\n"); 2074 push(@implContent, " if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {\n"); 2075 if ($interfaceName eq "Document" || $interfaceName eq "WorkerContext" || $interfaceName eq "SharedWorkerContext" || $interfaceName eq "DedicatedWorkerContext") { 2076 push(@implContent, " if (JSObject* jsFunction = jsListener->jsFunction(impl))\n"); 2077 } else { 2078 push(@implContent, " if (JSObject* jsFunction = jsListener->jsFunction(impl->scriptExecutionContext()))\n"); 2079 } 2080 push(@implContent, " return jsFunction;\n"); 2081 push(@implContent, " }\n"); 2082 push(@implContent, " }\n"); 2083 push(@implContent, " return jsNull();\n"); 2084 } elsif ($attribute->signature->type =~ /Constructor$/) { 2085 my $constructorType = $attribute->signature->type; 2086 $constructorType =~ s/Constructor$//; 2087 # When Constructor attribute is used by DOMWindow.idl, it's correct to pass castedThis as the global object 2088 # When JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject() 2089 if ($interfaceName eq "DOMWindow") { 2090 my $named = ($constructorType =~ /Named$/) ? "Named" : ""; 2091 $constructorType =~ s/Named$//; 2092 push(@implContent, " return JS" . $constructorType . "::get${named}Constructor(exec, castedThis);\n"); 2093 } else { 2094 AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"}); 2095 push(@implContent, " return JS" . $constructorType . "::getConstructor(exec, castedThis->globalObject());\n"); 2096 } 2097 } elsif (!$attribute->signature->extendedAttributes->{"GetterRaisesException"}) { 2098 push(@implContent, " UNUSED_PARAM(exec);\n") if !$attribute->signature->extendedAttributes->{"CallWith"}; 2099 push(@implContent, " bool isNull = false;\n") if $isNullable; 2100 2101 my $cacheIndex = 0; 2102 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) { 2103 $cacheIndex = $currentCachedAttribute; 2104 $currentCachedAttribute++; 2105 push(@implContent, " if (JSValue cachedValue = castedThis->m_" . $attribute->signature->name . ".get())\n"); 2106 push(@implContent, " return cachedValue;\n"); 2107 } 2108 2109 my @callWithArgs = GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "jsUndefined()"); 2110 2111 if ($svgListPropertyType) { 2112 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "castedThis->impl()->$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n"); 2113 } elsif ($svgPropertyOrListPropertyType) { 2114 push(@implContent, " $svgPropertyOrListPropertyType& impl = castedThis->impl()->propertyReference();\n"); 2115 if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber 2116 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl", "castedThis") . ";\n"); 2117 } else { 2118 push(@implContent, " JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . (join ", ", @callWithArgs) . ")", "castedThis") . ";\n"); 2119 2120 } 2121 } else { 2122 my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute); 2123 push(@arguments, "isNull") if $isNullable; 2124 if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) { 2125 my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"}; 2126 $implIncludes{"${implementedBy}.h"} = 1; 2127 $functionName = "${implementedBy}::${functionName}"; 2128 unshift(@arguments, "impl") if !$attribute->isStatic; 2129 } elsif ($attribute->isStatic) { 2130 $functionName = "${interfaceName}::${functionName}"; 2131 } else { 2132 $functionName = "impl->${functionName}"; 2133 } 2134 2135 unshift(@arguments, @callWithArgs); 2136 my $jsType = NativeToJSValue($attribute->signature, 0, $interfaceName, "${functionName}(" . join(", ", @arguments) . ")", "castedThis"); 2137 push(@implContent, " $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n") if !$attribute->isStatic; 2138 if ($codeGenerator->IsSVGAnimatedType($type)) { 2139 push(@implContent, " RefPtr<$type> obj = $jsType;\n"); 2140 push(@implContent, " JSValue result = toJS(exec, castedThis->globalObject(), obj.get());\n"); 2141 } else { 2142 push(@implContent, " JSValue result = $jsType;\n"); 2143 } 2144 2145 if ($isNullable) { 2146 push(@implContent, " if (isNull)\n"); 2147 push(@implContent, " return jsNull();\n"); 2148 } 2149 } 2150 2151 push(@implContent, " castedThis->m_" . $attribute->signature->name . ".set(exec->vm(), castedThis, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"}); 2152 push(@implContent, " return result;\n"); 2153 2154 } else { 2155 my @arguments = ("ec"); 2156 push(@implContent, " ExceptionCode ec = 0;\n"); 2157 2158 if ($isNullable) { 2159 push(@implContent, " bool isNull = false;\n"); 2160 unshift(@arguments, "isNull"); 2161 } 2162 2163 unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "jsUndefined()")); 2164 2165 if ($svgPropertyOrListPropertyType) { 2166 push(@implContent, " $svgPropertyOrListPropertyType impl(*castedThis->impl());\n"); 2167 push(@implContent, " JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n"); 2168 } else { 2169 push(@implContent, " $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n"); 2170 push(@implContent, " JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl->$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n"); 2171 } 2172 2173 if ($isNullable) { 2174 push(@implContent, " if (isNull)\n"); 2175 push(@implContent, " return jsNull();\n"); 2176 } 2177 2178 push(@implContent, " setDOMException(exec, ec);\n"); 2179 push(@implContent, " return result;\n"); 2180 } 2181 2182 push(@implContent, "}\n\n"); 2183 2184 push(@implContent, "#endif\n") if $attributeConditionalString; 2185 2186 push(@implContent, "\n"); 2187 } 2188 2189 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) { 2190 my $constructorFunctionName = "js" . $interfaceName . "Constructor"; 2191 2192 push(@implContent, "JSValue ${constructorFunctionName}(ExecState* exec, JSValue slotBase, PropertyName)\n"); 2193 push(@implContent, "{\n"); 2194 push(@implContent, " ${className}* domObject = jsCast<$className*>(asObject(slotBase));\n"); 2195 2196 if ($interface->extendedAttributes->{"CheckSecurity"}) { 2197 $implIncludes{"BindingSecurity.h"} = 1; 2198 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, domObject->impl()))\n"); 2199 push(@implContent, " return jsUndefined();\n"); 2200 } 2201 2202 push(@implContent, " return ${className}::getConstructor(exec, domObject->globalObject());\n"); 2203 push(@implContent, "}\n\n"); 2204 } 2205 } 2206 2207 # Check if we have any writable attributes 2208 my $hasReadWriteProperties = 0; 2209 foreach my $attribute (@{$interface->attributes}) { 2210 $hasReadWriteProperties = 1 if !IsReadonly($attribute) && !$attribute->isStatic; 2211 } 2212 2213 my $hasSetter = $hasReadWriteProperties 2214 || $interface->extendedAttributes->{"CustomNamedSetter"} 2215 || $interface->extendedAttributes->{"CustomIndexedSetter"}; 2216 2217 if ($hasSetter) { 2218 if (!$interface->extendedAttributes->{"CustomPutFunction"}) { 2219 push(@implContent, "void ${className}::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)\n"); 2220 push(@implContent, "{\n"); 2221 push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n"); 2222 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 2223 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) { 2224 push(@implContent, " unsigned index = propertyName.asIndex();\n"); 2225 push(@implContent, " if (index != PropertyName::NotAnIndex) {\n"); 2226 push(@implContent, " thisObject->indexSetter(exec, index, value);\n"); 2227 push(@implContent, " return;\n"); 2228 push(@implContent, " }\n"); 2229 } 2230 if ($interface->extendedAttributes->{"CustomNamedSetter"}) { 2231 push(@implContent, " if (thisObject->putDelegate(exec, propertyName, value, slot))\n"); 2232 push(@implContent, " return;\n"); 2233 } 2234 2235 if ($hasReadWriteProperties) { 2236 push(@implContent, " lookupPut<$className, Base>(exec, propertyName, value, " . hashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, slot);\n"); 2237 } else { 2238 push(@implContent, " Base::put(thisObject, exec, propertyName, value, slot);\n"); 2239 } 2240 push(@implContent, "}\n\n"); 2241 2242 if ($interface->extendedAttributes->{"CustomIndexedSetter"} || $interface->extendedAttributes->{"CustomNamedSetter"}) { 2243 push(@implContent, "void ${className}::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)\n"); 2244 push(@implContent, "{\n"); 2245 push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n"); 2246 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 2247 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) { 2248 push(@implContent, " if (index <= MAX_ARRAY_INDEX) {\n"); 2249 push(@implContent, " UNUSED_PARAM(shouldThrow);\n"); 2250 push(@implContent, " thisObject->indexSetter(exec, index, value);\n"); 2251 push(@implContent, " return;\n"); 2252 push(@implContent, " }\n"); 2253 } 2254 2255 if ($interface->extendedAttributes->{"CustomNamedSetter"}) { 2256 push(@implContent, " PropertyName propertyName = Identifier::from(exec, index);\n"); 2257 push(@implContent, " PutPropertySlot slot(shouldThrow);\n"); 2258 push(@implContent, " if (thisObject->putDelegate(exec, propertyName, value, slot))\n"); 2259 push(@implContent, " return;\n"); 2260 } 2261 2262 push(@implContent, " Base::putByIndex(cell, exec, index, value, shouldThrow);\n"); 2263 push(@implContent, "}\n\n"); 2264 } 2265 } 2266 2267 if ($hasReadWriteProperties) { 2268 foreach my $attribute (@{$interface->attributes}) { 2269 if (!IsReadonly($attribute)) { 2270 my $name = $attribute->signature->name; 2271 my $type = $attribute->signature->type; 2272 my $putFunctionName = GetAttributeSetterName($interfaceName, $className, $attribute); 2273 my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name); 2274 my $setterRaisesException = $attribute->signature->extendedAttributes->{"SetterRaisesException"}; 2275 2276 my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature); 2277 push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString; 2278 2279 push(@implContent, "void ${putFunctionName}(ExecState* exec, JSObject*"); 2280 push(@implContent, " thisObject") if !$attribute->isStatic; 2281 push(@implContent, ", JSValue value)\n"); 2282 push(@implContent, "{\n"); 2283 2284 push(@implContent, " UNUSED_PARAM(exec);\n"); 2285 2286 if ($interface->extendedAttributes->{"CheckSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckSecurity"}) { 2287 if ($interfaceName eq "DOMWindow") { 2288 $implIncludes{"BindingSecurity.h"} = 1; 2289 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, jsCast<$className*>(thisObject)->impl()))\n"); 2290 } else { 2291 push(@implContent, " if (!shouldAllowAccessToFrame(exec, jsCast<$className*>(thisObject)->impl()->frame()))\n"); 2292 } 2293 push(@implContent, " return;\n"); 2294 } 2295 2296 if (HasCustomSetter($attribute->signature->extendedAttributes)) { 2297 push(@implContent, " jsCast<$className*>(thisObject)->set$implSetterFunctionName(exec, value);\n"); 2298 } elsif ($type eq "EventListener") { 2299 $implIncludes{"JSEventListener.h"} = 1; 2300 push(@implContent, " UNUSED_PARAM(exec);\n"); 2301 push(@implContent, " ${className}* castedThis = jsCast<${className}*>(thisObject);\n"); 2302 my $windowEventListener = $attribute->signature->extendedAttributes->{"JSWindowEventListener"}; 2303 if ($windowEventListener) { 2304 push(@implContent, " JSDOMGlobalObject* globalObject = castedThis->globalObject();\n"); 2305 } 2306 push(@implContent, " $interfaceName* impl = static_cast<$interfaceName*>(castedThis->impl());\n"); 2307 if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerContext")) and $name eq "onerror") { 2308 $implIncludes{"JSErrorHandler.h"} = 1; 2309 push(@implContent, " impl->set$implSetterFunctionName(createJSErrorHandler(exec, value, thisObject));\n"); 2310 } else { 2311 push(@implContent, GenerateAttributeEventListenerCall($className, $implSetterFunctionName, $windowEventListener)); 2312 } 2313 } elsif ($attribute->signature->type =~ /Constructor$/) { 2314 my $constructorType = $attribute->signature->type; 2315 $constructorType =~ s/Constructor$//; 2316 # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor. 2317 # We do not generate the header file for NamedConstructor of class XXXX, 2318 # since we generate the NamedConstructor declaration into the header file of class XXXX. 2319 if ($constructorType ne "any" and $constructorType !~ /Named$/) { 2320 AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"}); 2321 } 2322 push(@implContent, " // Shadowing a built-in constructor\n"); 2323 if ($interfaceName eq "DOMWindow" && $className eq "JSblah") { 2324 # FIXME: This branch never executes and should be removed. 2325 push(@implContent, " jsCast<$className*>(thisObject)->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n"); 2326 } else { 2327 push(@implContent, " jsCast<$className*>(thisObject)->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n"); 2328 } 2329 } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) { 2330 push(@implContent, " // Shadowing a built-in object\n"); 2331 push(@implContent, " jsCast<$className*>(thisObject)->putDirect(exec->vm(), Identifier(exec, \"$name\"), value);\n"); 2332 } else { 2333 if (!$attribute->isStatic) { 2334 push(@implContent, " $className* castedThis = jsCast<$className*>(thisObject);\n"); 2335 push(@implContent, " $implType* impl = static_cast<$implType*>(castedThis->impl());\n"); 2336 } 2337 push(@implContent, " ExceptionCode ec = 0;\n") if $setterRaisesException; 2338 2339 # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an 2340 # interface type, then if the incoming value does not implement that interface, a TypeError 2341 # is thrown rather than silently passing NULL to the C++ code. 2342 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to 2343 # both strings and numbers, so do not throw TypeError if the attribute is of these types. 2344 if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) { 2345 $implIncludes{"<runtime/Error.h>"} = 1; 2346 2347 my $argType = $attribute->signature->type; 2348 if (!IsNativeType($argType)) { 2349 push(@implContent, " if (!value.isUndefinedOrNull() && !value.inherits(&JS${argType}::s_info)) {\n"); 2350 push(@implContent, " throwVMTypeError(exec);\n"); 2351 push(@implContent, " return;\n"); 2352 push(@implContent, " };\n"); 2353 } 2354 } 2355 2356 push(@implContent, " " . GetNativeTypeFromSignature($attribute->signature) . " nativeValue(" . JSValueToNative($attribute->signature, "value") . ");\n"); 2357 push(@implContent, " if (exec->hadException())\n"); 2358 push(@implContent, " return;\n"); 2359 2360 if ($codeGenerator->IsEnumType($type)) { 2361 my @enumValues = $codeGenerator->ValidEnumValues($type); 2362 my @enumChecks = (); 2363 foreach my $enumValue (@enumValues) { 2364 push(@enumChecks, "nativeValue != \"$enumValue\""); 2365 } 2366 push (@implContent, " if (" . join(" && ", @enumChecks) . ")\n"); 2367 push (@implContent, " return;\n"); 2368 } 2369 2370 if ($svgPropertyOrListPropertyType) { 2371 if ($svgPropertyType) { 2372 push(@implContent, " if (impl->isReadOnly()) {\n"); 2373 push(@implContent, " setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n"); 2374 push(@implContent, " return;\n"); 2375 push(@implContent, " }\n"); 2376 $implIncludes{"ExceptionCode.h"} = 1; 2377 } 2378 push(@implContent, " $svgPropertyOrListPropertyType& podImpl = impl->propertyReference();\n"); 2379 if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber 2380 push(@implContent, " podImpl = nativeValue;\n"); 2381 } else { 2382 push(@implContent, " podImpl.set$implSetterFunctionName(nativeValue"); 2383 push(@implContent, ", ec") if $setterRaisesException; 2384 push(@implContent, ");\n"); 2385 push(@implContent, " setDOMException(exec, ec);\n") if $setterRaisesException; 2386 } 2387 if ($svgPropertyType) { 2388 if ($setterRaisesException) { 2389 push(@implContent, " if (!ec)\n"); 2390 push(@implContent, " impl->commitChange();\n"); 2391 } else { 2392 push(@implContent, " impl->commitChange();\n"); 2393 } 2394 } 2395 } else { 2396 my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute); 2397 push(@arguments, "nativeValue"); 2398 if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) { 2399 my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"}; 2400 $implIncludes{"${implementedBy}.h"} = 1; 2401 unshift(@arguments, "impl") if !$attribute->isStatic; 2402 $functionName = "${implementedBy}::${functionName}"; 2403 } elsif ($attribute->isStatic) { 2404 $functionName = "${interfaceName}::${functionName}"; 2405 } else { 2406 $functionName = "impl->${functionName}"; 2407 } 2408 2409 unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContent, "")); 2410 2411 push(@arguments, "ec") if $setterRaisesException; 2412 push(@implContent, " ${functionName}(" . join(", ", @arguments) . ");\n"); 2413 push(@implContent, " setDOMException(exec, ec);\n") if $setterRaisesException; 2414 } 2415 } 2416 2417 push(@implContent, "}\n\n"); 2418 push(@implContent, "#endif\n") if $attributeConditionalString; 2419 push(@implContent, "\n"); 2420 } 2421 } 2422 } 2423 2424 if ($interface->extendedAttributes->{"ReplaceableConstructor"}) { 2425 my $constructorFunctionName = "setJS" . $interfaceName . "Constructor"; 2426 2427 push(@implContent, "void ${constructorFunctionName}(ExecState* exec, JSObject* thisObject, JSValue value)\n"); 2428 push(@implContent, "{\n"); 2429 if ($interface->extendedAttributes->{"CheckSecurity"}) { 2430 if ($interfaceName eq "DOMWindow") { 2431 $implIncludes{"BindingSecurity.h"} = 1; 2432 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, jsCast<$className*>(thisObject)->impl()))\n"); 2433 } else { 2434 push(@implContent, " if (!shouldAllowAccessToFrame(exec, jsCast<$className*>(thisObject)->impl()->frame()))\n"); 2435 } 2436 push(@implContent, " return;\n"); 2437 } 2438 2439 push(@implContent, " // Shadowing a built-in constructor\n"); 2440 2441 if ($interfaceName eq "DOMWindow") { 2442 push(@implContent, " jsCast<$className*>(thisObject)->putDirect(exec->vm(), exec->propertyNames().constructor, value);\n"); 2443 } else { 2444 die "No way to handle interface with ReplaceableConstructor extended attribute: $interfaceName"; 2445 } 2446 push(@implContent, "}\n\n"); 2447 } 2448 } 2449 } 2450 2451 if ($indexedGetterFunction && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) { 2452 push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)\n"); 2453 push(@implContent, "{\n"); 2454 push(@implContent, " ${className}* thisObject = jsCast<${className}*>(object);\n"); 2455 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 2456 push(@implContent, " for (unsigned i = 0; i < static_cast<${interfaceName}*>(thisObject->impl())->length(); ++i)\n"); 2457 push(@implContent, " propertyNames.add(Identifier::from(exec, i));\n"); 2458 push(@implContent, " Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);\n"); 2459 push(@implContent, "}\n\n"); 2460 } 2461 2462 if (!$interface->extendedAttributes->{"NoInterfaceObject"}) { 2463 push(@implContent, "JSValue ${className}::getConstructor(ExecState* exec, JSGlobalObject* globalObject)\n{\n"); 2464 push(@implContent, " return getDOMConstructor<${className}Constructor>(exec, jsCast<JSDOMGlobalObject*>(globalObject));\n"); 2465 push(@implContent, "}\n\n"); 2466 if ($interface->extendedAttributes->{"NamedConstructor"}) { 2467 push(@implContent, "JSValue ${className}::getNamedConstructor(ExecState* exec, JSGlobalObject* globalObject)\n{\n"); 2468 push(@implContent, " return getDOMConstructor<${className}NamedConstructor>(exec, jsCast<JSDOMGlobalObject*>(globalObject));\n"); 2469 push(@implContent, "}\n\n"); 2470 } 2471 } 2472 2473 # Functions 2474 if ($numFunctions > 0) { 2475 foreach my $function (@{$interface->functions}) { 2476 AddIncludesForTypeInImpl($function->signature->type); 2477 2478 my $isCustom = HasCustomMethod($function->signature->extendedAttributes); 2479 my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1; 2480 my $raisesException = $function->signature->extendedAttributes->{"RaisesException"}; 2481 2482 next if $isCustom && $isOverloaded && $function->{overloadIndex} > 1; 2483 2484 my $functionName = GetFunctionName($className, $function); 2485 2486 my $conditional = $function->signature->extendedAttributes->{"Conditional"}; 2487 if ($conditional) { 2488 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional); 2489 push(@implContent, "#if ${conditionalString}\n"); 2490 } 2491 2492 2493 if (!$isCustom && $isOverloaded) { 2494 # Append a number to an overloaded method's name to make it unique: 2495 $functionName = $functionName . $function->{overloadIndex}; 2496 # Make this function static to avoid compiler warnings, since we 2497 # don't generate a prototype for it in the header. 2498 push(@implContent, "static "); 2499 } 2500 2501 my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $codeGenerator->WK_lcfirst($function->signature->name); 2502 2503 push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n"); 2504 push(@implContent, "{\n"); 2505 2506 $implIncludes{"<runtime/Error.h>"} = 1; 2507 2508 if ($function->isStatic) { 2509 if ($isCustom) { 2510 GenerateArgumentsCountCheck(\@implContent, $function, $interface); 2511 push(@implContent, " return JSValue::encode(${className}::" . $functionImplementationName . "(exec));\n"); 2512 } else { 2513 GenerateArgumentsCountCheck(\@implContent, $function, $interface); 2514 2515 push(@implContent, " ExceptionCode ec = 0;\n") if $raisesException; 2516 2517 my $numParameters = @{$function->parameters}; 2518 my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType); 2519 GenerateImplementationFunctionCall($function, $functionString, " ", $svgPropertyType, $interfaceName); 2520 } 2521 } else { 2522 if ($interfaceName eq "DOMWindow") { 2523 push(@implContent, " $className* castedThis = toJSDOMWindow(exec->hostThisValue().toThisObject(exec));\n"); 2524 push(@implContent, " if (!castedThis)\n"); 2525 push(@implContent, " return throwVMTypeError(exec);\n"); 2526 } elsif ($interface->extendedAttributes->{"IsWorkerContext"}) { 2527 push(@implContent, " $className* castedThis = to${className}(exec->hostThisValue().toThisObject(exec));\n"); 2528 push(@implContent, " if (!castedThis)\n"); 2529 push(@implContent, " return throwVMTypeError(exec);\n"); 2530 } else { 2531 push(@implContent, " JSValue thisValue = exec->hostThisValue();\n"); 2532 push(@implContent, " if (!thisValue.inherits(&${className}::s_info))\n"); 2533 push(@implContent, " return throwVMTypeError(exec);\n"); 2534 push(@implContent, " $className* castedThis = jsCast<$className*>(asObject(thisValue));\n"); 2535 } 2536 2537 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(castedThis, &${className}::s_info);\n"); 2538 2539 if ($interface->extendedAttributes->{"CheckSecurity"} and 2540 !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) { 2541 $implIncludes{"BindingSecurity.h"} = 1; 2542 push(@implContent, " if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))\n"); 2543 push(@implContent, " return JSValue::encode(jsUndefined());\n"); 2544 } 2545 2546 if ($isCustom) { 2547 push(@implContent, " return JSValue::encode(castedThis->" . $functionImplementationName . "(exec));\n"); 2548 } else { 2549 if ($function->signature->name eq "set" and $interface->extendedAttributes->{"TypedArray"}) { 2550 my $viewType = $interface->extendedAttributes->{"TypedArray"}; 2551 push(@implContent, " return JSValue::encode(setWebGLArrayHelper<$implType, $viewType>(exec, castedThis->impl()));\n"); 2552 push(@implContent, "}\n\n"); 2553 next; 2554 } 2555 2556 push(@implContent, " $implType* impl = static_cast<$implType*>(castedThis->impl());\n"); 2557 if ($svgPropertyType) { 2558 push(@implContent, " if (impl->isReadOnly()) {\n"); 2559 push(@implContent, " setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n"); 2560 push(@implContent, " return JSValue::encode(jsUndefined());\n"); 2561 push(@implContent, " }\n"); 2562 push(@implContent, " $svgPropertyType& podImpl = impl->propertyReference();\n"); 2563 $implIncludes{"ExceptionCode.h"} = 1; 2564 } 2565 2566 # For compatibility with legacy content, the EventListener calls are generated without GenerateArgumentsCountCheck. 2567 if ($function->signature->name eq "addEventListener") { 2568 push(@implContent, GenerateEventListenerCall($className, "add")); 2569 } elsif ($function->signature->name eq "removeEventListener") { 2570 push(@implContent, GenerateEventListenerCall($className, "remove")); 2571 } else { 2572 GenerateArgumentsCountCheck(\@implContent, $function, $interface); 2573 2574 push(@implContent, " ExceptionCode ec = 0;\n") if $raisesException; 2575 2576 if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) { 2577 push(@implContent, " if (!shouldAllowAccessToNode(exec, impl->" . $function->signature->name . "(" . ($raisesException ? "ec" : "") .")))\n"); 2578 push(@implContent, " return JSValue::encode(jsNull());\n"); 2579 $implIncludes{"JSDOMBinding.h"} = 1; 2580 } 2581 2582 my $numParameters = @{$function->parameters}; 2583 my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $interface, $numParameters, $interfaceName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType); 2584 GenerateImplementationFunctionCall($function, $functionString, " ", $svgPropertyType, $interfaceName); 2585 } 2586 } 2587 } 2588 2589 push(@implContent, "}\n\n"); 2590 2591 if (!$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}}) { 2592 # Generate a function dispatching call to the rest of the overloads. 2593 GenerateOverloadedFunction($function, $interface, $interfaceName); 2594 } 2595 2596 push(@implContent, "#endif\n\n") if $conditional; 2597 } 2598 } 2599 2600 if ($needsMarkChildren && !$interface->extendedAttributes->{"JSCustomMarkFunction"}) { 2601 push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n"); 2602 push(@implContent, "{\n"); 2603 push(@implContent, " ${className}* thisObject = jsCast<${className}*>(cell);\n"); 2604 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n"); 2605 push(@implContent, " COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);\n"); 2606 push(@implContent, " ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());\n"); 2607 push(@implContent, " Base::visitChildren(thisObject, visitor);\n"); 2608 if ($interface->extendedAttributes->{"EventTarget"} || $interface->name eq "EventTarget") { 2609 push(@implContent, " thisObject->impl()->visitJSEventListeners(visitor);\n"); 2610 } 2611 if ($numCachedAttributes > 0) { 2612 foreach (@{$interface->attributes}) { 2613 my $attribute = $_; 2614 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) { 2615 push(@implContent, " visitor.append(&thisObject->m_" . $attribute->signature->name . ");\n"); 2616 } 2617 } 2618 } 2619 push(@implContent, "}\n\n"); 2620 } 2621 2622 # Cached attributes are indeed allowed when there is a custom mark/visitChildren function. 2623 # The custom function must make sure to account for the cached attribute. 2624 # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present. 2625 # die "Can't generate binding for class with cached attribute and custom mark." if (($numCachedAttributes > 0) and ($interface->extendedAttributes->{"JSCustomMarkFunction"})); 2626 2627 if ($numConstants > 0) { 2628 push(@implContent, "// Constant getters\n\n"); 2629 2630 foreach my $constant (@{$interface->constants}) { 2631 my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name); 2632 my $conditional = $constant->extendedAttributes->{"Conditional"}; 2633 2634 if ($conditional) { 2635 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional); 2636 push(@implContent, "#if ${conditionalString}\n"); 2637 } 2638 2639 # FIXME: this casts into int to match our previous behavior which turned 0xFFFFFFFF in -1 for NodeFilter.SHOW_ALL 2640 push(@implContent, "JSValue ${getter}(ExecState* exec, JSValue, PropertyName)\n"); 2641 push(@implContent, "{\n"); 2642 if ($constant->type eq "DOMString") { 2643 push(@implContent, " return jsStringOrNull(exec, String(" . $constant->value . "));\n"); 2644 } else { 2645 push(@implContent, " UNUSED_PARAM(exec);\n"); 2646 push(@implContent, " return jsNumber(static_cast<int>(" . $constant->value . "));\n"); 2647 } 2648 push(@implContent, "}\n\n"); 2649 push(@implContent, "#endif\n") if $conditional; 2650 } 2651 } 2652 2653 if ($indexedGetterFunction && !$hasNumericIndexedGetter) { 2654 push(@implContent, "\nJSValue ${className}::indexGetter(ExecState* exec, JSValue slotBase, unsigned index)\n"); 2655 push(@implContent, "{\n"); 2656 push(@implContent, " ${className}* thisObj = jsCast<$className*>(asObject(slotBase));\n"); 2657 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObj, &s_info);\n"); 2658 if (IndexGetterReturnsStrings($interfaceName)) { 2659 $implIncludes{"KURL.h"} = 1; 2660 push(@implContent, " return jsStringOrUndefined(exec, thisObj->impl()->item(index));\n"); 2661 } else { 2662 push(@implContent, " return toJS(exec, thisObj->globalObject(), static_cast<$interfaceName*>(thisObj->impl())->item(index));\n"); 2663 } 2664 push(@implContent, "}\n\n"); 2665 if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") { 2666 $implIncludes{"JSNode.h"} = 1; 2667 $implIncludes{"Node.h"} = 1; 2668 } 2669 } 2670 2671 if ($hasNumericIndexedGetter) { 2672 push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n"); 2673 push(@implContent, "{\n"); 2674 push(@implContent, " ASSERT_GC_OBJECT_INHERITS(this, &s_info);\n"); 2675 push(@implContent, " double result = static_cast<$interfaceName*>(impl())->item(index);\n"); 2676 # jsNumber conversion doesn't suppress signalling NaNs, so enforce that here. 2677 push(@implContent, " if (std::isnan(result))\n"); 2678 push(@implContent, " return jsNaN();\n"); 2679 push(@implContent, " return JSValue(result);\n"); 2680 push(@implContent, "}\n\n"); 2681 if ($interfaceName =~ /^HTML\w*Collection$/) { 2682 $implIncludes{"JSNode.h"} = 1; 2683 $implIncludes{"Node.h"} = 1; 2684 } 2685 } 2686 2687 if ($interfaceName eq "HTMLPropertiesCollection" or $interfaceName eq "DOMNamedFlowCollection") { 2688 if ($namedGetterFunction) { 2689 push(@implContent, "bool ${className}::canGetItemsForName(ExecState*, $interfaceName* collection, PropertyName propertyName)\n"); 2690 push(@implContent, "{\n"); 2691 push(@implContent, " return collection->hasNamedItem(propertyNameToAtomicString(propertyName));\n"); 2692 push(@implContent, "}\n\n"); 2693 push(@implContent, "JSValue ${className}::nameGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName)\n"); 2694 push(@implContent, "{\n"); 2695 push(@implContent, " ${className}* thisObj = jsCast<$className*>(asObject(slotBase));\n"); 2696 if ($interfaceName eq "HTMLPropertiesCollection") { 2697 push(@implContent, " return toJS(exec, thisObj->globalObject(), WTF::getPtr(static_cast<$interfaceName*>(thisObj->impl())->propertyNodeList(propertyNameToAtomicString(propertyName))));\n"); 2698 } else { 2699 push(@implContent, " return toJS(exec, thisObj->globalObject(), static_cast<$interfaceName*>(thisObj->impl())->namedItem(propertyNameToAtomicString(propertyName)));\n"); 2700 } 2701 push(@implContent, "}\n\n"); 2702 } 2703 } 2704 2705 if ((!$hasParent && !GetCustomIsReachable($interface))|| GetGenerateIsReachable($interface) || $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) { 2706 push(@implContent, "static inline bool isObservable(JS${interfaceName}* js${interfaceName})\n"); 2707 push(@implContent, "{\n"); 2708 push(@implContent, " if (js${interfaceName}->hasCustomProperties())\n"); 2709 push(@implContent, " return true;\n"); 2710 if ($eventTarget) { 2711 push(@implContent, " if (js${interfaceName}->impl()->hasEventListeners())\n"); 2712 push(@implContent, " return true;\n"); 2713 } 2714 push(@implContent, " return false;\n"); 2715 push(@implContent, "}\n\n"); 2716 2717 push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n"); 2718 push(@implContent, "{\n"); 2719 push(@implContent, " JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n"); 2720 # All ActiveDOMObjects implement hasPendingActivity(), but not all of them 2721 # increment their C++ reference counts when hasPendingActivity() becomes 2722 # true. As a result, ActiveDOMObjects can be prematurely destroyed before 2723 # their pending activities complete. To wallpaper over this bug, JavaScript 2724 # wrappers unconditionally keep ActiveDOMObjects with pending activity alive. 2725 # FIXME: Fix this lifetime issue in the DOM, and move this hasPendingActivity 2726 # check below the isObservable check. 2727 if ($codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) { 2728 push(@implContent, " if (js${interfaceName}->impl()->hasPendingActivity())\n"); 2729 push(@implContent, " return true;\n"); 2730 } 2731 if ($codeGenerator->InheritsExtendedAttribute($interface, "EventTarget")) { 2732 push(@implContent, " if (js${interfaceName}->impl()->isFiringEventListeners())\n"); 2733 push(@implContent, " return true;\n"); 2734 } 2735 if ($codeGenerator->InheritsInterface($interface, "Node")) { 2736 push(@implContent, " if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor))\n"); 2737 push(@implContent, " return true;\n"); 2738 } 2739 push(@implContent, " if (!isObservable(js${interfaceName}))\n"); 2740 push(@implContent, " return false;\n"); 2741 if (GetGenerateIsReachable($interface)) { 2742 my $rootString; 2743 if (GetGenerateIsReachable($interface) eq "Impl") { 2744 $rootString = " ${implType}* root = js${interfaceName}->impl();\n"; 2745 } elsif (GetGenerateIsReachable($interface) eq "ImplContext") { 2746 $rootString = " WebGLRenderingContext* root = js${interfaceName}->impl()->context();\n"; 2747 } elsif (GetGenerateIsReachable($interface) eq "ImplFrame") { 2748 $rootString = " Frame* root = js${interfaceName}->impl()->frame();\n"; 2749 $rootString .= " if (!root)\n"; 2750 $rootString .= " return false;\n"; 2751 } elsif (GetGenerateIsReachable($interface) eq "ImplDocument") { 2752 $rootString = " Document* root = js${interfaceName}->impl()->document();\n"; 2753 $rootString .= " if (!root)\n"; 2754 $rootString .= " return false;\n"; 2755 } elsif (GetGenerateIsReachable($interface) eq "ImplElementRoot") { 2756 $implIncludes{"Element.h"} = 1; 2757 $implIncludes{"JSNodeCustom.h"} = 1; 2758 $rootString = " Element* element = js${interfaceName}->impl()->element();\n"; 2759 $rootString .= " if (!element)\n"; 2760 $rootString .= " return false;\n"; 2761 $rootString .= " void* root = WebCore::root(element);\n"; 2762 } elsif ($interfaceName eq "CanvasRenderingContext") { 2763 $rootString = " void* root = WebCore::root(js${interfaceName}->impl()->canvas());\n"; 2764 } elsif (GetGenerateIsReachable($interface) eq "ImplOwnerNodeRoot") { 2765 $implIncludes{"Element.h"} = 1; 2766 $implIncludes{"JSNodeCustom.h"} = 1; 2767 $rootString = " void* root = WebCore::root(js${interfaceName}->impl()->ownerNode());\n"; 2768 } else { 2769 $rootString = " void* root = WebCore::root(js${interfaceName}->impl());\n"; 2770 } 2771 2772 push(@implContent, $rootString); 2773 push(@implContent, " return visitor.containsOpaqueRoot(root);\n"); 2774 } else { 2775 push(@implContent, " UNUSED_PARAM(visitor);\n"); 2776 push(@implContent, " return false;\n"); 2777 } 2778 push(@implContent, "}\n\n"); 2779 } 2780 2781 if (!$interface->extendedAttributes->{"JSCustomFinalize"} && 2782 (!$hasParent || 2783 GetGenerateIsReachable($interface) || 2784 GetCustomIsReachable($interface) || 2785 $codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject"))) { 2786 push(@implContent, "void JS${interfaceName}Owner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)\n"); 2787 push(@implContent, "{\n"); 2788 push(@implContent, " JS${interfaceName}* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.get().asCell());\n"); 2789 push(@implContent, " DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context);\n"); 2790 push(@implContent, " uncacheWrapper(world, js${interfaceName}->impl(), js${interfaceName});\n"); 2791 push(@implContent, " js${interfaceName}->releaseImpl();\n"); 2792 push(@implContent, "}\n\n"); 2793 } 2794 2795 if (ShouldGenerateToJSImplementation($hasParent, $interface)) { 2796 my $vtableNameGnu = GetGnuVTableNameForInterface($interface); 2797 my $vtableRefGnu = GetGnuVTableRefForInterface($interface); 2798 my $vtableRefWin = GetWinVTableRefForInterface($interface); 2799 2800 push(@implContent, <<END) if $vtableNameGnu; 2801#if ENABLE(BINDING_INTEGRITY) 2802#if PLATFORM(WIN) 2803#pragma warning(disable: 4483) 2804extern "C" { extern void (*const ${vtableRefWin}[])(); } 2805#else 2806extern "C" { extern void* ${vtableNameGnu}[]; } 2807#endif 2808#endif 2809END 2810 2811 push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n"); 2812 push(@implContent, "{\n"); 2813 push(@implContent, <<END); 2814 if (!impl) 2815 return jsNull(); 2816END 2817 2818 if ($svgPropertyType) { 2819 push(@implContent, " if (JSValue result = getExistingWrapper<$className, $implType>(exec, impl))\n"); 2820 push(@implContent, " return result;\n"); 2821 } else { 2822 push(@implContent, " if (JSValue result = getExistingWrapper<$className>(exec, impl))\n"); 2823 push(@implContent, " return result;\n"); 2824 } 2825 push(@implContent, <<END) if $vtableNameGnu; 2826 2827#if ENABLE(BINDING_INTEGRITY) 2828 void* actualVTablePointer = *(reinterpret_cast<void**>(impl)); 2829#if PLATFORM(WIN) 2830 void* expectedVTablePointer = reinterpret_cast<void*>(${vtableRefWin}); 2831#else 2832 void* expectedVTablePointer = ${vtableRefGnu}; 2833#if COMPILER(CLANG) 2834 // If this fails $implType does not have a vtable, so you need to add the 2835 // ImplementationLacksVTable attribute to the interface definition 2836 COMPILE_ASSERT(__is_polymorphic($implType), ${implType}_is_not_polymorphic); 2837#endif 2838#endif 2839 // If you hit this assertion you either have a use after free bug, or 2840 // $implType has subclasses. If $implType has subclasses that get passed 2841 // to toJS() we currently require $interfaceName you to opt out of binding hardening 2842 // by adding the SkipVTableValidation attribute to the interface IDL definition 2843 RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer); 2844#endif 2845END 2846 push(@implContent, <<END) if $interface->extendedAttributes->{"ImplementationLacksVTable"}; 2847#if COMPILER(CLANG) 2848 // If you hit this failure the interface definition has the ImplementationLacksVTable 2849 // attribute. You should remove that attribute. If the class has subclasses 2850 // that may be passed through this toJS() function you should use the SkipVTableValidation 2851 // attribute to $interfaceName. 2852 COMPILE_ASSERT(!__is_polymorphic($implType), ${implType}_is_polymorphic_but_idl_claims_not_to_be); 2853#endif 2854END 2855 push(@implContent, <<END); 2856 ReportMemoryCost<$implType>::reportMemoryCost(exec, impl); 2857END 2858 2859 if ($svgPropertyType) { 2860 push(@implContent, " return createNewWrapper<$className, $implType>(exec, globalObject, impl);\n"); 2861 } else { 2862 push(@implContent, " return createNewWrapper<$className>(exec, globalObject, impl);\n"); 2863 } 2864 2865 push(@implContent, "}\n\n"); 2866 } 2867 2868 if ((!$hasParent or $interface->extendedAttributes->{"JSGenerateToNativeObject"}) and !$interface->extendedAttributes->{"JSCustomToNativeObject"}) { 2869 push(@implContent, "$implType* to${interfaceName}(JSC::JSValue value)\n"); 2870 push(@implContent, "{\n"); 2871 push(@implContent, " return value.inherits(&${className}::s_info) ? jsCast<$className*>(asObject(value))->impl() : 0"); 2872 push(@implContent, ";\n}\n"); 2873 } 2874 2875 push(@implContent, "\n}\n"); 2876 2877 my $conditionalString = $codeGenerator->GenerateConditionalString($interface); 2878 push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString; 2879} 2880 2881sub GenerateCallWith 2882{ 2883 my $callWith = shift; 2884 return () unless $callWith; 2885 my $outputArray = shift; 2886 my $returnValue = shift; 2887 my $function = shift; 2888 2889 my @callWithArgs; 2890 if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) { 2891 push(@callWithArgs, "exec"); 2892 } 2893 if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptExecutionContext")) { 2894 push(@$outputArray, " ScriptExecutionContext* scriptContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();\n"); 2895 push(@$outputArray, " if (!scriptContext)\n"); 2896 push(@$outputArray, " return" . ($returnValue ? " " . $returnValue : "") . ";\n"); 2897 push(@callWithArgs, "scriptContext"); 2898 } 2899 if ($function and $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments")) { 2900 push(@$outputArray, " RefPtr<ScriptArguments> scriptArguments(createScriptArguments(exec, " . @{$function->parameters} . "));\n"); 2901 $implIncludes{"ScriptArguments.h"} = 1; 2902 $implIncludes{"ScriptCallStackFactory.h"} = 1; 2903 push(@callWithArgs, "scriptArguments.release()"); 2904 } 2905 return @callWithArgs; 2906} 2907 2908sub GenerateArgumentsCountCheck 2909{ 2910 my $outputArray = shift; 2911 my $function = shift; 2912 my $interface = shift; 2913 2914 my $numMandatoryParams = @{$function->parameters}; 2915 foreach my $param (reverse(@{$function->parameters})) { 2916 if ($param->isOptional or $param->isVariadic) { 2917 $numMandatoryParams--; 2918 } else { 2919 last; 2920 } 2921 } 2922 if ($numMandatoryParams >= 1) 2923 { 2924 push(@$outputArray, " if (exec->argumentCount() < $numMandatoryParams)\n"); 2925 push(@$outputArray, " return throwVMError(exec, createNotEnoughArgumentsError(exec));\n"); 2926 } 2927} 2928 2929sub GenerateParametersCheck 2930{ 2931 my $outputArray = shift; 2932 my $function = shift; 2933 my $interface = shift; 2934 my $numParameters = shift; 2935 my $interfaceName = shift; 2936 my $functionImplementationName = shift; 2937 my $svgPropertyType = shift; 2938 my $svgPropertyOrListPropertyType = shift; 2939 my $svgListPropertyType = shift; 2940 2941 my $argsIndex = 0; 2942 my $hasOptionalArguments = 0; 2943 my $raisesException = $function->signature->extendedAttributes->{"RaisesException"}; 2944 2945 my @arguments; 2946 my $functionName; 2947 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"}; 2948 if ($implementedBy) { 2949 AddToImplIncludes("${implementedBy}.h"); 2950 unshift(@arguments, "impl") if !$function->isStatic; 2951 $functionName = "${implementedBy}::${functionImplementationName}"; 2952 } elsif ($function->isStatic) { 2953 $functionName = "${interfaceName}::${functionImplementationName}"; 2954 } elsif ($svgPropertyOrListPropertyType and !$svgListPropertyType) { 2955 $functionName = "podImpl.${functionImplementationName}"; 2956 } else { 2957 $functionName = "impl->${functionImplementationName}"; 2958 } 2959 2960 if (!$function->signature->extendedAttributes->{"Constructor"}) { 2961 push(@arguments, GenerateCallWith($function->signature->extendedAttributes->{"CallWith"}, \@$outputArray, "JSValue::encode(jsUndefined())", $function)); 2962 } 2963 2964 $implIncludes{"ExceptionCode.h"} = 1; 2965 $implIncludes{"JSDOMBinding.h"} = 1; 2966 2967 foreach my $parameter (@{$function->parameters}) { 2968 my $argType = $parameter->type; 2969 2970 # Optional arguments with [Optional] should generate an early call with fewer arguments. 2971 # Optional arguments with [Optional=...] should not generate the early call. 2972 # Optional Dictionary arguments always considered to have default of empty dictionary. 2973 my $optional = $parameter->isOptional; 2974 my $defaultAttribute = $parameter->extendedAttributes->{"Default"}; 2975 if ($optional && !$defaultAttribute && $argType ne "Dictionary" && !$codeGenerator->IsCallbackInterface($parameter->type)) { 2976 # Generate early call if there are enough parameters. 2977 if (!$hasOptionalArguments) { 2978 push(@$outputArray, "\n size_t argsCount = exec->argumentCount();\n"); 2979 $hasOptionalArguments = 1; 2980 } 2981 push(@$outputArray, " if (argsCount <= $argsIndex) {\n"); 2982 2983 my @optionalCallbackArguments = @arguments; 2984 push(@optionalCallbackArguments, "ec") if $raisesException; 2985 my $functionString = "$functionName(" . join(", ", @optionalCallbackArguments) . ")"; 2986 GenerateImplementationFunctionCall($function, $functionString, " " x 2, $svgPropertyType, $interfaceName); 2987 push(@$outputArray, " }\n\n"); 2988 } 2989 2990 my $name = $parameter->name; 2991 2992 if ($argType eq "XPathNSResolver") { 2993 push(@$outputArray, " RefPtr<XPathNSResolver> customResolver;\n"); 2994 push(@$outputArray, " XPathNSResolver* resolver = toXPathNSResolver(exec->argument($argsIndex));\n"); 2995 push(@$outputArray, " if (!resolver) {\n"); 2996 push(@$outputArray, " customResolver = JSCustomXPathNSResolver::create(exec, exec->argument($argsIndex));\n"); 2997 push(@$outputArray, " if (exec->hadException())\n"); 2998 push(@$outputArray, " return JSValue::encode(jsUndefined());\n"); 2999 push(@$outputArray, " resolver = customResolver.get();\n"); 3000 push(@$outputArray, " }\n"); 3001 } elsif ($codeGenerator->IsCallbackInterface($parameter->type)) { 3002 my $callbackClassName = GetCallbackClassName($argType); 3003 $implIncludes{"$callbackClassName.h"} = 1; 3004 if ($optional) { 3005 push(@$outputArray, " RefPtr<$argType> $name;\n"); 3006 push(@$outputArray, " if (exec->argumentCount() > $argsIndex && !exec->argument($argsIndex).isUndefinedOrNull()) {\n"); 3007 push(@$outputArray, " if (!exec->argument($argsIndex).isFunction())\n"); 3008 push(@$outputArray, " return throwVMTypeError(exec);\n"); 3009 if ($function->isStatic) { 3010 AddToImplIncludes("CallbackFunction.h"); 3011 push(@$outputArray, " $name = createFunctionOnlyCallback<${callbackClassName}>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument($argsIndex));\n"); 3012 } else { 3013 push(@$outputArray, " $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n"); 3014 } 3015 push(@$outputArray, " }\n"); 3016 } else { 3017 push(@$outputArray, " if (exec->argumentCount() <= $argsIndex || !exec->argument($argsIndex).isFunction())\n"); 3018 push(@$outputArray, " return throwVMTypeError(exec);\n"); 3019 if ($function->isStatic) { 3020 AddToImplIncludes("CallbackFunction.h"); 3021 push(@$outputArray, " RefPtr<$argType> $name = createFunctionOnlyCallback<${callbackClassName}>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument($argsIndex));\n"); 3022 } else { 3023 push(@$outputArray, " RefPtr<$argType> $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n"); 3024 } 3025 } 3026 } elsif ($parameter->extendedAttributes->{"Clamp"}) { 3027 my $nativeValue = "${name}NativeValue"; 3028 push(@$outputArray, " $argType $name = 0;\n"); 3029 push(@$outputArray, " double $nativeValue = exec->argument($argsIndex).toNumber(exec);\n"); 3030 push(@$outputArray, " if (exec->hadException())\n"); 3031 push(@$outputArray, " return JSValue::encode(jsUndefined());\n\n"); 3032 push(@$outputArray, " if (!std::isnan($nativeValue))\n"); 3033 push(@$outputArray, " $name = clampTo<$argType>($nativeValue);\n\n"); 3034 } elsif ($parameter->isVariadic) { 3035 my $nativeElementType; 3036 if ($argType eq "DOMString") { 3037 $nativeElementType = "String"; 3038 } else { 3039 $nativeElementType = GetNativeType($argType); 3040 if ($nativeElementType =~ />$/) { 3041 $nativeElementType .= " "; 3042 } 3043 } 3044 3045 if (!IsNativeType($argType)) { 3046 push(@$outputArray, " Vector<$nativeElementType> $name;\n"); 3047 push(@$outputArray, " for (unsigned i = $argsIndex; i < exec->argumentCount(); ++i) {\n"); 3048 push(@$outputArray, " if (!exec->argument(i).inherits(&JS${argType}::s_info))\n"); 3049 push(@$outputArray, " return throwVMTypeError(exec);\n"); 3050 push(@$outputArray, " $name.append(to$argType(exec->argument(i)));\n"); 3051 push(@$outputArray, " }\n") 3052 } else { 3053 push(@$outputArray, " Vector<$nativeElementType> $name = toNativeArguments<$nativeElementType>(exec, $argsIndex);\n"); 3054 # Check if the type conversion succeeded. 3055 push(@$outputArray, " if (exec->hadException())\n"); 3056 push(@$outputArray, " return JSValue::encode(jsUndefined());\n"); 3057 } 3058 3059 } elsif ($codeGenerator->IsEnumType($argType)) { 3060 $implIncludes{"<runtime/Error.h>"} = 1; 3061 3062 my $argValue = "exec->argument($argsIndex)"; 3063 push(@$outputArray, " const String ${name}(${argValue}.isEmpty() ? String() : ${argValue}.toString(exec)->value(exec));\n"); 3064 push(@$outputArray, " if (exec->hadException())\n"); 3065 push(@$outputArray, " return JSValue::encode(jsUndefined());\n"); 3066 3067 my @enumValues = $codeGenerator->ValidEnumValues($argType); 3068 my @enumChecks = (); 3069 foreach my $enumValue (@enumValues) { 3070 push(@enumChecks, "${name} != \"$enumValue\""); 3071 } 3072 push (@$outputArray, " if (" . join(" && ", @enumChecks) . ")\n"); 3073 push (@$outputArray, " return throwVMTypeError(exec);\n"); 3074 } else { 3075 # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an 3076 # interface type, then if the incoming value does not implement that interface, a TypeError 3077 # is thrown rather than silently passing NULL to the C++ code. 3078 # Per the Web IDL and ECMAScript semantics, incoming values can always be converted to both 3079 # strings and numbers, so do not throw TypeError if the argument is of these types. 3080 if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) { 3081 $implIncludes{"<runtime/Error.h>"} = 1; 3082 3083 my $argValue = "exec->argument($argsIndex)"; 3084 if (!IsNativeType($argType)) { 3085 push(@$outputArray, " if (exec->argumentCount() > $argsIndex && !${argValue}.isUndefinedOrNull() && !${argValue}.inherits(&JS${argType}::s_info))\n"); 3086 push(@$outputArray, " return throwVMTypeError(exec);\n"); 3087 } 3088 } 3089 3090 push(@$outputArray, " " . GetNativeTypeFromSignature($parameter) . " $name(" . JSValueToNative($parameter, $optional && $defaultAttribute && $defaultAttribute eq "NullString" ? "argumentOrNull(exec, $argsIndex)" : "exec->argument($argsIndex)") . ");\n"); 3091 3092 # If a parameter is "an index" and it's negative it should throw an INDEX_SIZE_ERR exception. 3093 # But this needs to be done in the bindings, because the type is unsigned and the fact that it 3094 # was negative will be lost by the time we're inside the DOM. 3095 if ($parameter->extendedAttributes->{"IsIndex"}) { 3096 push(@$outputArray, " if ($name < 0) {\n"); 3097 push(@$outputArray, " setDOMException(exec, INDEX_SIZE_ERR);\n"); 3098 push(@$outputArray, " return JSValue::encode(jsUndefined());\n"); 3099 push(@$outputArray, " }\n"); 3100 } 3101 3102 # Check if the type conversion succeeded. 3103 push(@$outputArray, " if (exec->hadException())\n"); 3104 push(@$outputArray, " return JSValue::encode(jsUndefined());\n"); 3105 3106 if ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) { 3107 push(@$outputArray, " if (!$name) {\n"); 3108 push(@$outputArray, " setDOMException(exec, TYPE_MISMATCH_ERR);\n"); 3109 push(@$outputArray, " return JSValue::encode(jsUndefined());\n"); 3110 push(@$outputArray, " }\n"); 3111 } 3112 } 3113 3114 if ($argType eq "NodeFilter") { 3115 push @arguments, "$name.get()"; 3116 } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $interfaceName =~ /List$/) { 3117 push @arguments, "$name->propertyReference()"; 3118 } else { 3119 push @arguments, $name; 3120 } 3121 $argsIndex++; 3122 } 3123 3124 push(@arguments, "ec") if $raisesException; 3125 3126 return ("$functionName(" . join(", ", @arguments) . ")", scalar @arguments); 3127} 3128 3129sub GenerateCallbackHeader 3130{ 3131 my $object = shift; 3132 my $interface = shift; 3133 3134 my $interfaceName = $interface->name; 3135 my $className = "JS$interfaceName"; 3136 3137 # - Add default header template and header protection 3138 push(@headerContentHeader, GenerateHeaderContentHeader($interface)); 3139 3140 $headerIncludes{"ActiveDOMCallback.h"} = 1; 3141 $headerIncludes{"$interfaceName.h"} = 1; 3142 $headerIncludes{"JSCallbackData.h"} = 1; 3143 $headerIncludes{"<wtf/Forward.h>"} = 1; 3144 3145 push(@headerContent, "\nnamespace WebCore {\n\n"); 3146 push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n"); 3147 push(@headerContent, "public:\n"); 3148 3149 # The static create() method. 3150 push(@headerContent, " static PassRefPtr<$className> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)\n"); 3151 push(@headerContent, " {\n"); 3152 push(@headerContent, " return adoptRef(new $className(callback, globalObject));\n"); 3153 push(@headerContent, " }\n\n"); 3154 3155 # ScriptExecutionContext 3156 push(@headerContent, " virtual ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }\n\n"); 3157 3158 # Destructor 3159 push(@headerContent, " virtual ~$className();\n"); 3160 3161 # Functions 3162 my $numFunctions = @{$interface->functions}; 3163 if ($numFunctions > 0) { 3164 push(@headerContent, "\n // Functions\n"); 3165 foreach my $function (@{$interface->functions}) { 3166 my @params = @{$function->parameters}; 3167 if (!$function->signature->extendedAttributes->{"Custom"} && 3168 !(GetNativeType($function->signature->type) eq "bool")) { 3169 push(@headerContent, " COMPILE_ASSERT(false)"); 3170 } 3171 3172 push(@headerContent, " virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "("); 3173 3174 my @args = (); 3175 foreach my $param (@params) { 3176 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name); 3177 } 3178 push(@headerContent, join(", ", @args)); 3179 3180 push(@headerContent, ");\n"); 3181 } 3182 } 3183 3184 push(@headerContent, "\nprivate:\n"); 3185 3186 # Constructor 3187 push(@headerContent, " $className(JSC::JSObject* callback, JSDOMGlobalObject*);\n\n"); 3188 3189 # Private members 3190 push(@headerContent, " JSCallbackData* m_data;\n"); 3191 push(@headerContent, "};\n\n"); 3192 3193 push(@headerContent, "} // namespace WebCore\n\n"); 3194 my $conditionalString = $codeGenerator->GenerateConditionalString($interface); 3195 push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString; 3196 push(@headerContent, "#endif\n"); 3197} 3198 3199sub GenerateCallbackImplementation 3200{ 3201 my ($object, $interface) = @_; 3202 3203 my $interfaceName = $interface->name; 3204 my $className = "JS$interfaceName"; 3205 3206 # - Add default header template 3207 push(@implContentHeader, GenerateImplementationContentHeader($interface)); 3208 3209 $implIncludes{"ScriptExecutionContext.h"} = 1; 3210 $implIncludes{"<runtime/JSLock.h>"} = 1; 3211 3212 @implContent = (); 3213 3214 push(@implContent, "\nusing namespace JSC;\n\n"); 3215 push(@implContent, "namespace WebCore {\n\n"); 3216 3217 # Constructor 3218 push(@implContent, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n"); 3219 push(@implContent, " : ActiveDOMCallback(globalObject->scriptExecutionContext())\n"); 3220 push(@implContent, " , m_data(new JSCallbackData(callback, globalObject))\n"); 3221 push(@implContent, "{\n"); 3222 push(@implContent, "}\n\n"); 3223 3224 # Destructor 3225 push(@implContent, "${className}::~${className}()\n"); 3226 push(@implContent, "{\n"); 3227 push(@implContent, " ScriptExecutionContext* context = scriptExecutionContext();\n"); 3228 push(@implContent, " // When the context is destroyed, all tasks with a reference to a callback\n"); 3229 push(@implContent, " // should be deleted. So if the context is 0, we are on the context thread.\n"); 3230 push(@implContent, " if (!context || context->isContextThread())\n"); 3231 push(@implContent, " delete m_data;\n"); 3232 push(@implContent, " else\n"); 3233 push(@implContent, " context->postTask(DeleteCallbackDataTask::create(m_data));\n"); 3234 push(@implContent, "#ifndef NDEBUG\n"); 3235 push(@implContent, " m_data = 0;\n"); 3236 push(@implContent, "#endif\n"); 3237 push(@implContent, "}\n"); 3238 3239 # Functions 3240 my $numFunctions = @{$interface->functions}; 3241 if ($numFunctions > 0) { 3242 push(@implContent, "\n// Functions\n"); 3243 foreach my $function (@{$interface->functions}) { 3244 my @params = @{$function->parameters}; 3245 if ($function->signature->extendedAttributes->{"Custom"} || 3246 !(GetNativeType($function->signature->type) eq "bool")) { 3247 next; 3248 } 3249 3250 AddIncludesForTypeInImpl($function->signature->type); 3251 push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "("); 3252 3253 my @args = (); 3254 my @argsCheck = (); 3255 my $thisType = $function->signature->extendedAttributes->{"PassThisToCallback"}; 3256 foreach my $param (@params) { 3257 my $paramName = $param->name; 3258 AddIncludesForTypeInImpl($param->type, 1); 3259 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $paramName); 3260 if ($thisType and $thisType eq $param->type) { 3261 push(@argsCheck, <<END); 3262 ASSERT(${paramName}); 3263 3264END 3265 } 3266 } 3267 push(@implContent, join(", ", @args)); 3268 push(@implContent, ")\n"); 3269 3270 push(@implContent, "{\n"); 3271 push(@implContent, @argsCheck) if @argsCheck; 3272 push(@implContent, " if (!canInvokeCallback())\n"); 3273 push(@implContent, " return true;\n\n"); 3274 push(@implContent, " RefPtr<$className> protect(this);\n\n"); 3275 push(@implContent, " JSLockHolder lock(m_data->globalObject()->vm());\n\n"); 3276 if (@params) { 3277 push(@implContent, " ExecState* exec = m_data->globalObject()->globalExec();\n"); 3278 } 3279 push(@implContent, " MarkedArgumentBuffer args;\n"); 3280 3281 foreach my $param (@params) { 3282 my $paramName = $param->name; 3283 if ($param->type eq "DOMString") { 3284 push(@implContent, " args.append(jsStringWithCache(exec, ${paramName}));\n"); 3285 } elsif ($param->type eq "boolean") { 3286 push(@implContent, " args.append(jsBoolean(${paramName}));\n"); 3287 } elsif ($param->type eq "SerializedScriptValue") { 3288 push(@implContent, " args.append($paramName ? $paramName->deserialize(exec, m_data->globalObject(), 0) : jsNull());\n"); 3289 } else { 3290 push(@implContent, " args.append(toJS(exec, m_data->globalObject(), ${paramName}));\n"); 3291 } 3292 } 3293 3294 push(@implContent, "\n bool raisedException = false;\n"); 3295 if ($thisType) { 3296 foreach my $param (@params) { 3297 next if $param->type ne $thisType; 3298 my $paramName = $param->name; 3299 push(@implContent, <<END); 3300 JSValue js${paramName} = toJS(exec, m_data->globalObject(), ${paramName}); 3301 m_data->invokeCallback(js${paramName}, args, &raisedException); 3302 3303END 3304 last; 3305 } 3306 } else { 3307 push(@implContent, " m_data->invokeCallback(args, &raisedException);\n"); 3308 } 3309 push(@implContent, " return !raisedException;\n"); 3310 push(@implContent, "}\n"); 3311 } 3312 } 3313 3314 push(@implContent, "\n}\n"); 3315 my $conditionalString = $codeGenerator->GenerateConditionalString($interface); 3316 push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString; 3317} 3318 3319sub GenerateImplementationFunctionCall() 3320{ 3321 my $function = shift; 3322 my $functionString = shift; 3323 my $indent = shift; 3324 my $svgPropertyType = shift; 3325 my $interfaceName = shift; 3326 3327 my $raisesException = $function->signature->extendedAttributes->{"RaisesException"}; 3328 3329 if ($function->signature->type eq "void") { 3330 push(@implContent, $indent . "$functionString;\n"); 3331 push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException; 3332 3333 if ($svgPropertyType and !$function->isStatic) { 3334 if ($raisesException) { 3335 push(@implContent, $indent . "if (!ec)\n"); 3336 push(@implContent, $indent . " impl->commitChange();\n"); 3337 } else { 3338 push(@implContent, $indent . "impl->commitChange();\n"); 3339 } 3340 } 3341 3342 push(@implContent, $indent . "return JSValue::encode(jsUndefined());\n"); 3343 } else { 3344 my $thisObject = $function->isStatic ? 0 : "castedThis"; 3345 push(@implContent, "\n" . $indent . "JSC::JSValue result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n"); 3346 push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException; 3347 3348 if ($codeGenerator->ExtendedAttributeContains($function->signature->extendedAttributes->{"CallWith"}, "ScriptState")) { 3349 push(@implContent, $indent . "if (exec->hadException())\n"); 3350 push(@implContent, $indent . " return JSValue::encode(jsUndefined());\n"); 3351 } 3352 3353 push(@implContent, $indent . "return JSValue::encode(result);\n"); 3354 } 3355} 3356 3357sub GetNativeTypeFromSignature 3358{ 3359 my $signature = shift; 3360 my $type = $signature->type; 3361 3362 if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) { 3363 # Special-case index arguments because we need to check that they aren't < 0. 3364 return "int"; 3365 } 3366 3367 return GetNativeType($type); 3368} 3369 3370my %nativeType = ( 3371 "CompareHow" => "Range::CompareHow", 3372 "DOMString" => "const String&", 3373 "NodeFilter" => "RefPtr<NodeFilter>", 3374 "SerializedScriptValue" => "RefPtr<SerializedScriptValue>", 3375 "Date" => "double", 3376 "Dictionary" => "Dictionary", 3377 "any" => "ScriptValue", 3378 "boolean" => "bool", 3379 "double" => "double", 3380 "float" => "float", 3381 "short" => "short", 3382 "long" => "int", 3383 "unsigned long" => "unsigned", 3384 "unsigned short" => "unsigned short", 3385 "long long" => "long long", 3386 "unsigned long long" => "unsigned long long", 3387 "byte" => "int8_t", 3388 "octet" => "uint8_t", 3389 "MediaQueryListListener" => "RefPtr<MediaQueryListListener>", 3390 "DOMTimeStamp" => "DOMTimeStamp", 3391); 3392 3393sub GetNativeType 3394{ 3395 my $type = shift; 3396 3397 my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type); 3398 return "${svgNativeType}*" if $svgNativeType; 3399 return "RefPtr<DOMStringList>" if $type eq "DOMStringList"; 3400 return $nativeType{$type} if exists $nativeType{$type}; 3401 3402 my $arrayType = $codeGenerator->GetArrayType($type); 3403 my $sequenceType = $codeGenerator->GetSequenceType($type); 3404 my $arrayOrSequenceType = $arrayType || $sequenceType; 3405 3406 return "Vector<" . GetNativeVectorInnerType($arrayOrSequenceType) . ">" if $arrayOrSequenceType; 3407 3408 if ($codeGenerator->IsEnumType($type)) { 3409 return "const String"; 3410 } 3411 3412 # For all other types, the native type is a pointer with same type name as the IDL type. 3413 return "${type}*"; 3414} 3415 3416sub GetNativeVectorInnerType 3417{ 3418 my $arrayOrSequenceType = shift; 3419 3420 return "String" if $arrayOrSequenceType eq "DOMString"; 3421 return $nativeType{$arrayOrSequenceType} if exists $nativeType{$arrayOrSequenceType}; 3422 return "RefPtr<${arrayOrSequenceType}> "; 3423} 3424 3425sub GetNativeTypeForCallbacks 3426{ 3427 my $type = shift; 3428 return "PassRefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue"; 3429 return "PassRefPtr<DOMStringList>" if $type eq "DOMStringList"; 3430 3431 return GetNativeType($type); 3432} 3433 3434sub GetSVGPropertyTypes 3435{ 3436 my $implType = shift; 3437 3438 my $svgPropertyType; 3439 my $svgListPropertyType; 3440 my $svgNativeType; 3441 3442 return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/; 3443 3444 $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType); 3445 return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType; 3446 3447 # Append space to avoid compilation errors when using PassRefPtr<$svgNativeType> 3448 $svgNativeType = "$svgNativeType "; 3449 3450 my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType); 3451 if ($svgNativeType =~ /SVGPropertyTearOff/) { 3452 $svgPropertyType = $svgWrappedNativeType; 3453 $headerIncludes{"$svgWrappedNativeType.h"} = 1; 3454 $headerIncludes{"SVGAnimatedPropertyTearOff.h"} = 1; 3455 } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) { 3456 $svgListPropertyType = $svgWrappedNativeType; 3457 $headerIncludes{"$svgWrappedNativeType.h"} = 1; 3458 $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1; 3459 } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) { 3460 $svgListPropertyType = $svgWrappedNativeType; 3461 $headerIncludes{"$svgWrappedNativeType.h"} = 1; 3462 $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1; 3463 $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1; 3464 } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) { 3465 $svgListPropertyType = $svgWrappedNativeType; 3466 $headerIncludes{"$svgWrappedNativeType.h"} = 1; 3467 $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1; 3468 $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1; 3469 } 3470 3471 return ($svgPropertyType, $svgListPropertyType, $svgNativeType); 3472} 3473 3474sub IsNativeType 3475{ 3476 my $type = shift; 3477 return exists $nativeType{$type}; 3478} 3479 3480sub JSValueToNative 3481{ 3482 my $signature = shift; 3483 my $value = shift; 3484 3485 my $conditional = $signature->extendedAttributes->{"Conditional"}; 3486 my $type = $signature->type; 3487 3488 return "$value.toBoolean(exec)" if $type eq "boolean"; 3489 return "$value.toNumber(exec)" if $type eq "double"; 3490 return "$value.toFloat(exec)" if $type eq "float"; 3491 3492 my $intConversion = $signature->extendedAttributes->{"EnforceRange"} ? "EnforceRange" : "NormalConversion"; 3493 return "toInt8(exec, $value, $intConversion)" if $type eq "byte"; 3494 return "toUInt8(exec, $value, $intConversion)" if $type eq "octet"; 3495 return "toInt32(exec, $value, $intConversion)" if $type eq "long" or $type eq "short"; 3496 return "toUInt32(exec, $value, $intConversion)" if $type eq "unsigned long" or $type eq "unsigned short"; 3497 return "toInt64(exec, $value, $intConversion)" if $type eq "long long"; 3498 return "toUInt64(exec, $value, $intConversion)" if $type eq "unsigned long long"; 3499 3500 return "valueToDate(exec, $value)" if $type eq "Date"; 3501 return "static_cast<Range::CompareHow>($value.toInt32(exec))" if $type eq "CompareHow"; 3502 3503 if ($type eq "DOMString") { 3504 # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString], 3505 # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString]. 3506 if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") and ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString")) { 3507 return "valueToStringWithUndefinedOrNullCheck(exec, $value)" 3508 } 3509 if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") or $signature->extendedAttributes->{"Reflect"}) { 3510 return "valueToStringWithNullCheck(exec, $value)" 3511 } 3512 # FIXME: Add the case for 'if ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'. 3513 return "$value.isEmpty() ? String() : $value.toString(exec)->value(exec)"; 3514 } 3515 3516 if ($type eq "any") { 3517 return "exec->vm(), $value"; 3518 } 3519 3520 if ($type eq "NodeFilter") { 3521 AddToImplIncludes("JS$type.h", $conditional); 3522 return "to$type(exec->vm(), $value)"; 3523 } 3524 3525 if ($type eq "MediaQueryListListener") { 3526 AddToImplIncludes("MediaQueryListListener.h", $conditional); 3527 return "MediaQueryListListener::create(ScriptValue(exec->vm(), " . $value ."))"; 3528 } 3529 3530 if ($type eq "SerializedScriptValue") { 3531 AddToImplIncludes("SerializedScriptValue.h", $conditional); 3532 return "SerializedScriptValue::create(exec, $value, 0, 0)"; 3533 } 3534 3535 if ($type eq "Dictionary") { 3536 AddToImplIncludes("Dictionary.h", $conditional); 3537 return "exec, $value"; 3538 } 3539 3540 if ($type eq "DOMStringList" ) { 3541 AddToImplIncludes("JSDOMStringList.h", $conditional); 3542 return "toDOMStringList(exec, $value)"; 3543 } 3544 3545 AddToImplIncludes("HTMLOptionElement.h", $conditional) if $type eq "HTMLOptionElement"; 3546 AddToImplIncludes("Event.h", $conditional) if $type eq "Event"; 3547 3548 my $arrayType = $codeGenerator->GetArrayType($type); 3549 my $sequenceType = $codeGenerator->GetSequenceType($type); 3550 my $arrayOrSequenceType = $arrayType || $sequenceType; 3551 3552 if ($arrayOrSequenceType) { 3553 if ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) { 3554 AddToImplIncludes("JS${arrayOrSequenceType}.h"); 3555 return "(toRefPtrNativeArray<${arrayOrSequenceType}, JS${arrayOrSequenceType}>(exec, $value, &to${arrayOrSequenceType}))"; 3556 } 3557 return "toNativeArray<" . GetNativeVectorInnerType($arrayOrSequenceType) . ">(exec, $value)"; 3558 } 3559 3560 if ($codeGenerator->IsEnumType($type)) { 3561 return "$value.isEmpty() ? String() : $value.toString(exec)->value(exec)"; 3562 } 3563 3564 # Default, assume autogenerated type conversion routines 3565 AddToImplIncludes("JS$type.h", $conditional); 3566 return "to$type($value)"; 3567} 3568 3569sub NativeToJSValue 3570{ 3571 my $signature = shift; 3572 my $inFunctionCall = shift; 3573 my $interfaceName = shift; 3574 my $value = shift; 3575 my $thisValue = shift; 3576 3577 my $conditional = $signature->extendedAttributes->{"Conditional"}; 3578 my $type = $signature->type; 3579 3580 return "jsBoolean($value)" if $type eq "boolean"; 3581 3582 # Need to check Date type before IsPrimitiveType(). 3583 if ($type eq "Date") { 3584 return "jsDateOrNull(exec, $value)"; 3585 } 3586 3587 if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) { 3588 $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g; 3589 return "jsNumber(std::max(0, " . $value . "))"; 3590 } 3591 3592 if ($codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp") { 3593 return "jsNumber($value)"; 3594 } 3595 3596 if ($codeGenerator->IsEnumType($type)) { 3597 AddToImplIncludes("<runtime/JSString.h>", $conditional); 3598 return "jsStringWithCache(exec, $value)"; 3599 } 3600 3601 if ($codeGenerator->IsStringType($type)) { 3602 AddToImplIncludes("KURL.h", $conditional); 3603 my $conv = $signature->extendedAttributes->{"TreatReturnedNullStringAs"}; 3604 if (defined $conv) { 3605 return "jsStringOrNull(exec, $value)" if $conv eq "Null"; 3606 return "jsStringOrUndefined(exec, $value)" if $conv eq "Undefined"; 3607 3608 die "Unknown value for TreatReturnedNullStringAs extended attribute"; 3609 } 3610 AddToImplIncludes("<runtime/JSString.h>", $conditional); 3611 return "jsStringWithCache(exec, $value)"; 3612 } 3613 3614 my $globalObject; 3615 if ($thisValue) { 3616 $globalObject = "$thisValue->globalObject()"; 3617 } 3618 3619 if ($type eq "CSSStyleDeclaration") { 3620 AddToImplIncludes("StylePropertySet.h", $conditional); 3621 } 3622 3623 if ($type eq "NodeList") { 3624 AddToImplIncludes("NameNodeList.h", $conditional); 3625 } 3626 3627 my $arrayType = $codeGenerator->GetArrayType($type); 3628 my $sequenceType = $codeGenerator->GetSequenceType($type); 3629 my $arrayOrSequenceType = $arrayType || $sequenceType; 3630 3631 if ($arrayOrSequenceType) { 3632 if ($arrayType eq "DOMString") { 3633 AddToImplIncludes("JSDOMStringList.h", $conditional); 3634 AddToImplIncludes("DOMStringList.h", $conditional); 3635 3636 } elsif ($codeGenerator->IsRefPtrType($arrayOrSequenceType)) { 3637 AddToImplIncludes("JS${arrayOrSequenceType}.h", $conditional); 3638 AddToImplIncludes("${arrayOrSequenceType}.h", $conditional); 3639 } 3640 AddToImplIncludes("<runtime/JSArray.h>", $conditional); 3641 3642 return "jsArray(exec, $thisValue->globalObject(), $value)"; 3643 } 3644 3645 if ($type eq "any") { 3646 if ($interfaceName eq "Document") { 3647 AddToImplIncludes("JSCanvasRenderingContext2D.h", $conditional); 3648 } else { 3649 return "($value.hasNoValue() ? jsNull() : $value.jsValue())"; 3650 } 3651 } elsif ($type =~ /SVGPathSeg/) { 3652 AddToImplIncludes("JS$type.h", $conditional); 3653 my $joinedName = $type; 3654 $joinedName =~ s/Abs|Rel//; 3655 AddToImplIncludes("$joinedName.h", $conditional); 3656 } elsif ($type eq "SerializedScriptValue" or $type eq "any") { 3657 AddToImplIncludes("SerializedScriptValue.h", $conditional); 3658 return "$value ? $value->deserialize(exec, castedThis->globalObject(), 0) : jsNull()"; 3659 } else { 3660 # Default, include header with same name. 3661 AddToImplIncludes("JS$type.h", $conditional); 3662 if ($codeGenerator->IsTypedArrayType($type)) { 3663 AddToImplIncludes("<wtf/$type.h>", $conditional) if not $codeGenerator->SkipIncludeHeader($type); 3664 } else { 3665 AddToImplIncludes("$type.h", $conditional) if not $codeGenerator->SkipIncludeHeader($type); 3666 } 3667 } 3668 3669 return $value if $codeGenerator->IsSVGAnimatedType($type); 3670 3671 if ($signature->extendedAttributes->{"ReturnNewObject"}) { 3672 return "toJSNewlyCreated(exec, $globalObject, WTF::getPtr($value))"; 3673 } 3674 3675 if ($codeGenerator->IsSVGAnimatedType($interfaceName) or $interfaceName eq "SVGViewSpec") { 3676 # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked. 3677 $value = "static_cast<" . GetNativeType($type) . ">($value)"; 3678 } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($type) and not $interfaceName =~ /List$/) { 3679 my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($type); 3680 if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($type) and $inFunctionCall eq 0 and not defined $signature->extendedAttributes->{"Immutable"}) { 3681 my $getter = $value; 3682 $getter =~ s/impl\.//; 3683 $getter =~ s/impl->//; 3684 $getter =~ s/\(\)//; 3685 my $updateMethod = "&${interfaceName}::update" . $codeGenerator->WK_ucfirst($getter); 3686 3687 my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($interfaceName); 3688 if ($selfIsTearOffType) { 3689 AddToImplIncludes("SVGMatrixTearOff.h", $conditional); 3690 # FIXME: Blink: Don't create a new one everytime we access the matrix property. This means, e.g, === won't work. 3691 $value = "SVGMatrixTearOff::create(castedThis->impl(), $value)"; 3692 3693 if ($value =~ /matrix/ and $interfaceName eq "SVGTransform") { 3694 # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform 3695 # and a svgMatrix() method returning a SVGMatrix, used for the bindings. 3696 $value =~ s/matrix/svgMatrix/; 3697 } 3698 } else { 3699 AddToImplIncludes("SVGStaticPropertyTearOff.h", $conditional); 3700 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$interfaceName, /; 3701 $value = "${tearOffType}::create(impl, $value, $updateMethod)"; 3702 } 3703 } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) { 3704 $value = "${tearOffType}::create(impl, $value)"; 3705 } elsif (not $tearOffType =~ /SVG(Point|PathSeg)List/) { 3706 $value = "${tearOffType}::create($value)"; 3707 } 3708 } 3709 if ($globalObject) { 3710 return "toJS(exec, $globalObject, WTF::getPtr($value))"; 3711 } else { 3712 return "toJS(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), WTF::getPtr($value))"; 3713 } 3714} 3715 3716sub ceilingToPowerOf2 3717{ 3718 my ($size) = @_; 3719 3720 my $powerOf2 = 1; 3721 while ($size > $powerOf2) { 3722 $powerOf2 <<= 1; 3723 } 3724 3725 return $powerOf2; 3726} 3727 3728# Internal Helper 3729sub GenerateHashTable 3730{ 3731 my $object = shift; 3732 3733 my $name = shift; 3734 my $size = shift; 3735 my $keys = shift; 3736 my $specials = shift; 3737 my $value1 = shift; 3738 my $value2 = shift; 3739 my $conditionals = shift; 3740 3741 # Generate size data for compact' size hash table 3742 3743 my @table = (); 3744 my @links = (); 3745 3746 my $compactSize = ceilingToPowerOf2($size * 2); 3747 3748 my $maxDepth = 0; 3749 my $collisions = 0; 3750 my $numEntries = $compactSize; 3751 3752 my $i = 0; 3753 foreach (@{$keys}) { 3754 my $depth = 0; 3755 my $h = Hasher::GenerateHashValue($_) % $numEntries; 3756 3757 while (defined($table[$h])) { 3758 if (defined($links[$h])) { 3759 $h = $links[$h]; 3760 $depth++; 3761 } else { 3762 $collisions++; 3763 $links[$h] = $compactSize; 3764 $h = $compactSize; 3765 $compactSize++; 3766 } 3767 } 3768 3769 $table[$h] = $i; 3770 3771 $i++; 3772 $maxDepth = $depth if ($depth > $maxDepth); 3773 } 3774 3775 # Start outputing the hashtables 3776 my $nameEntries = "${name}Values"; 3777 $nameEntries =~ s/:/_/g; 3778 3779 if (($name =~ /Prototype/) or ($name =~ /Constructor/)) { 3780 my $type = $name; 3781 my $implClass; 3782 3783 if ($name =~ /Prototype/) { 3784 $type =~ s/Prototype.*//; 3785 $implClass = $type; $implClass =~ s/Wrapper$//; 3786 push(@implContent, "/* Hash table for prototype */\n"); 3787 } else { 3788 $type =~ s/Constructor.*//; 3789 $implClass = $type; $implClass =~ s/Constructor$//; 3790 push(@implContent, "/* Hash table for constructor */\n"); 3791 } 3792 } else { 3793 push(@implContent, "/* Hash table */\n"); 3794 } 3795 3796 # Dump the hash table 3797 push(@implContent, "\nstatic const HashTableValue $nameEntries\[\] =\n\{\n"); 3798 $i = 0; 3799 foreach my $key (@{$keys}) { 3800 my $conditional; 3801 my $targetType; 3802 3803 if ($conditionals) { 3804 $conditional = $conditionals->{$key}; 3805 } 3806 if ($conditional) { 3807 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional); 3808 push(@implContent, "#if ${conditionalString}\n"); 3809 } 3810 3811 if ("@$specials[$i]" =~ m/Function/) { 3812 $targetType = "static_cast<NativeFunction>"; 3813 } else { 3814 $targetType = "static_cast<PropertySlot::GetValueFunc>"; 3815 } 3816 push(@implContent, " { \"$key\", @$specials[$i], (intptr_t)" . $targetType . "(@$value1[$i]), (intptr_t)@$value2[$i], NoIntrinsic },\n"); 3817 push(@implContent, "#endif\n") if $conditional; 3818 ++$i; 3819 } 3820 push(@implContent, " { 0, 0, 0, 0, NoIntrinsic }\n"); 3821 push(@implContent, "};\n\n"); 3822 my $compactSizeMask = $numEntries - 1; 3823 push(@implContent, "static const HashTable $name = { $compactSize, $compactSizeMask, $nameEntries, 0 };\n"); 3824} 3825 3826sub WriteData 3827{ 3828 my $object = shift; 3829 my $interface = shift; 3830 my $outputDir = shift; 3831 3832 my $name = $interface->name; 3833 my $prefix = FileNamePrefix; 3834 my $headerFileName = "$outputDir/$prefix$name.h"; 3835 my $implFileName = "$outputDir/$prefix$name.cpp"; 3836 my $depsFileName = "$outputDir/$prefix$name.dep"; 3837 3838 # Update a .cpp file if the contents are changed. 3839 my $contents = join "", @implContentHeader; 3840 3841 my @includes = (); 3842 my %implIncludeConditions = (); 3843 foreach my $include (keys %implIncludes) { 3844 my $condition = $implIncludes{$include}; 3845 my $checkType = $include; 3846 $checkType =~ s/\.h//; 3847 next if $codeGenerator->IsSVGAnimatedType($checkType); 3848 3849 $include = "\"$include\"" unless $include =~ /^["<]/; # " 3850 3851 if ($condition eq 1) { 3852 push @includes, $include; 3853 } else { 3854 push @{$implIncludeConditions{$condition}}, $include; 3855 } 3856 } 3857 foreach my $include (sort @includes) { 3858 $contents .= "#include $include\n"; 3859 } 3860 foreach my $condition (sort keys %implIncludeConditions) { 3861 $contents .= "\n#if " . $codeGenerator->GenerateConditionalStringFromAttributeValue($condition) . "\n"; 3862 foreach my $include (sort @{$implIncludeConditions{$condition}}) { 3863 $contents .= "#include $include\n"; 3864 } 3865 $contents .= "#endif\n"; 3866 } 3867 3868 $contents .= join "", @implContent; 3869 $codeGenerator->UpdateFile($implFileName, $contents); 3870 3871 @implContentHeader = (); 3872 @implContent = (); 3873 %implIncludes = (); 3874 3875 # Update a .h file if the contents are changed. 3876 $contents = join "", @headerContentHeader; 3877 3878 @includes = (); 3879 foreach my $include (keys %headerIncludes) { 3880 $include = "\"$include\"" unless $include =~ /^["<]/; # " 3881 push @includes, $include; 3882 } 3883 foreach my $include (sort @includes) { 3884 # "JSClassName.h" is already included right after config.h. 3885 next if $include eq "\"$prefix$name.h\""; 3886 $contents .= "#include $include\n"; 3887 } 3888 3889 $contents .= join "", @headerContent; 3890 3891 @includes = (); 3892 foreach my $include (keys %headerTrailingIncludes) { 3893 $include = "\"$include\"" unless $include =~ /^["<]/; # " 3894 push @includes, $include; 3895 } 3896 foreach my $include (sort @includes) { 3897 $contents .= "#include $include\n"; 3898 } 3899 $codeGenerator->UpdateFile($headerFileName, $contents); 3900 3901 @headerContentHeader = (); 3902 @headerContent = (); 3903 %headerIncludes = (); 3904 %headerTrailingIncludes = (); 3905 3906 if (@depsContent) { 3907 # Update a .dep file if the contents are changed. 3908 $contents = join "", @depsContent; 3909 $codeGenerator->UpdateFile($depsFileName, $contents); 3910 3911 @depsContent = (); 3912 } 3913} 3914 3915sub GenerateConstructorDeclaration 3916{ 3917 my $outputArray = shift; 3918 my $className = shift; 3919 my $interface = shift; 3920 my $interfaceName = shift; 3921 3922 my $constructorClassName = "${className}Constructor"; 3923 3924 push(@$outputArray, "class ${constructorClassName} : public DOMConstructorObject {\n"); 3925 push(@$outputArray, "private:\n"); 3926 push(@$outputArray, " ${constructorClassName}(JSC::Structure*, JSDOMGlobalObject*);\n"); 3927 push(@$outputArray, " void finishCreation(JSC::ExecState*, JSDOMGlobalObject*);\n\n"); 3928 3929 push(@$outputArray, "public:\n"); 3930 push(@$outputArray, " typedef DOMConstructorObject Base;\n"); 3931 push(@$outputArray, " static $constructorClassName* create(JSC::ExecState* exec, JSC::Structure* structure, JSDOMGlobalObject* globalObject)\n"); 3932 push(@$outputArray, " {\n"); 3933 push(@$outputArray, " $constructorClassName* ptr = new (NotNull, JSC::allocateCell<$constructorClassName>(*exec->heap())) $constructorClassName(structure, globalObject);\n"); 3934 push(@$outputArray, " ptr->finishCreation(exec, globalObject);\n"); 3935 push(@$outputArray, " return ptr;\n"); 3936 push(@$outputArray, " }\n\n"); 3937 3938 push(@$outputArray, " static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n"); 3939 push(@$outputArray, " static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertyDescriptor&);\n"); 3940 push(@$outputArray, " static const JSC::ClassInfo s_info;\n"); 3941 3942 push(@$outputArray, " static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n"); 3943 push(@$outputArray, " {\n"); 3944 push(@$outputArray, " return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n"); 3945 push(@$outputArray, " }\n"); 3946 3947 push(@$outputArray, "protected:\n"); 3948 push(@$outputArray, " static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | JSC::ImplementsHasInstance | DOMConstructorObject::StructureFlags;\n"); 3949 3950 if (IsConstructable($interface) && !$interface->extendedAttributes->{"NamedConstructor"}) { 3951 push(@$outputArray, " static JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState*);\n"); 3952 3953 if (!HasCustomConstructor($interface)) { 3954 my @constructors = @{$interface->constructors}; 3955 if (@constructors > 1) { 3956 foreach my $constructor (@constructors) { 3957 my $overloadedIndex = "" . $constructor->{overloadedIndex}; 3958 push(@$outputArray, " static JSC::EncodedJSValue JSC_HOST_CALL construct${className}${overloadedIndex}(JSC::ExecState*);\n"); 3959 } 3960 } 3961 } 3962 3963 my $conditionalString = $codeGenerator->GenerateConstructorConditionalString($interface); 3964 push(@$outputArray, "#if $conditionalString\n") if $conditionalString; 3965 push(@$outputArray, " static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&);\n"); 3966 push(@$outputArray, "#endif // $conditionalString\n") if $conditionalString; 3967 } 3968 push(@$outputArray, "};\n\n"); 3969 3970 if ($codeGenerator->IsConstructorTemplate($interface, "Event")) { 3971 push(@$outputArray, "bool fill${interfaceName}Init(${interfaceName}Init&, JSDictionary&);\n\n"); 3972 } 3973 3974 if ($interface->extendedAttributes->{"NamedConstructor"}) { 3975 push(@$outputArray, <<END); 3976class JS${interfaceName}NamedConstructor : public DOMConstructorWithDocument { 3977public: 3978 typedef DOMConstructorWithDocument Base; 3979 3980 static JS${interfaceName}NamedConstructor* create(JSC::ExecState* exec, JSC::Structure* structure, JSDOMGlobalObject* globalObject) 3981 { 3982 JS${interfaceName}NamedConstructor* constructor = new (NotNull, JSC::allocateCell<JS${interfaceName}NamedConstructor>(*exec->heap())) JS${interfaceName}NamedConstructor(structure, globalObject); 3983 constructor->finishCreation(exec, globalObject); 3984 return constructor; 3985 } 3986 3987 static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) 3988 { 3989 return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info); 3990 } 3991 3992 static const JSC::ClassInfo s_info; 3993 3994private: 3995 JS${interfaceName}NamedConstructor(JSC::Structure*, JSDOMGlobalObject*); 3996 static JSC::EncodedJSValue JSC_HOST_CALL constructJS${interfaceName}(JSC::ExecState*); 3997 static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&); 3998 void finishCreation(JSC::ExecState*, JSDOMGlobalObject*); 3999}; 4000 4001END 4002 } 4003} 4004 4005sub GenerateConstructorDefinitions 4006{ 4007 my $outputArray = shift; 4008 my $className = shift; 4009 my $protoClassName = shift; 4010 my $interfaceName = shift; 4011 my $visibleInterfaceName = shift; 4012 my $interface = shift; 4013 my $generatingNamedConstructor = shift; 4014 4015 if (IsConstructable($interface)) { 4016 my @constructors = @{$interface->constructors}; 4017 if (@constructors > 1) { 4018 foreach my $constructor (@constructors) { 4019 GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructor); 4020 } 4021 GenerateOverloadedConstructorDefinition($outputArray, $className, $interface); 4022 } elsif (@constructors == 1) { 4023 GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor, $constructors[0]); 4024 } else { 4025 GenerateConstructorDefinition($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor); 4026 } 4027 } 4028 4029 GenerateConstructorHelperMethods($outputArray, $className, $protoClassName, $interfaceName, $visibleInterfaceName, $interface, $generatingNamedConstructor); 4030} 4031 4032sub GenerateOverloadedConstructorDefinition 4033{ 4034 my $outputArray = shift; 4035 my $className = shift; 4036 my $interface = shift; 4037 4038 my $functionName = "${className}Constructor::construct${className}"; 4039 push(@$outputArray, <<END); 4040EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec) 4041{ 4042 size_t argsCount = exec->argumentCount(); 4043END 4044 4045 my %fetchedArguments = (); 4046 my $leastNumMandatoryParams = 255; 4047 4048 my @constructors = @{$interface->constructors}; 4049 foreach my $overload (@constructors) { 4050 my ($numMandatoryParams, $parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload); 4051 $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams); 4052 4053 foreach my $parameterIndex (@neededArguments) { 4054 next if exists $fetchedArguments{$parameterIndex}; 4055 push(@$outputArray, " JSValue arg$parameterIndex(exec->argument($parameterIndex));\n"); 4056 $fetchedArguments{$parameterIndex} = 1; 4057 } 4058 4059 push(@$outputArray, " if ($parametersCheck)\n"); 4060 push(@$outputArray, " return ${functionName}$overload->{overloadedIndex}(exec);\n"); 4061 } 4062 4063 if ($leastNumMandatoryParams >= 1) { 4064 push(@$outputArray, " if (argsCount < $leastNumMandatoryParams)\n"); 4065 push(@$outputArray, " return throwVMError(exec, createNotEnoughArgumentsError(exec));\n"); 4066 } 4067 push(@$outputArray, <<END); 4068 return throwVMTypeError(exec); 4069} 4070 4071END 4072} 4073 4074sub GenerateConstructorDefinition 4075{ 4076 my $outputArray = shift; 4077 my $className = shift; 4078 my $protoClassName = shift; 4079 my $interfaceName = shift; 4080 my $visibleInterfaceName = shift; 4081 my $interface = shift; 4082 my $generatingNamedConstructor = shift; 4083 my $function = shift; 4084 4085 my $constructorClassName = $generatingNamedConstructor ? "${className}NamedConstructor" : "${className}Constructor"; 4086 4087 if (IsConstructable($interface)) { 4088 if ($codeGenerator->IsConstructorTemplate($interface, "Event")) { 4089 $implIncludes{"JSDictionary.h"} = 1; 4090 $implIncludes{"<runtime/Error.h>"} = 1; 4091 4092 push(@$outputArray, <<END); 4093EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}(ExecState* exec) 4094{ 4095 ${constructorClassName}* jsConstructor = jsCast<${constructorClassName}*>(exec->callee()); 4096 4097 ScriptExecutionContext* executionContext = jsConstructor->scriptExecutionContext(); 4098 if (!executionContext) 4099 return throwVMError(exec, createReferenceError(exec, "Constructor associated execution context is unavailable")); 4100 4101 AtomicString eventType = exec->argument(0).toString(exec)->value(exec); 4102 if (exec->hadException()) 4103 return JSValue::encode(jsUndefined()); 4104 4105 ${interfaceName}Init eventInit; 4106 4107 JSValue initializerValue = exec->argument(1); 4108 if (!initializerValue.isUndefinedOrNull()) { 4109 // Given the above test, this will always yield an object. 4110 JSObject* initializerObject = initializerValue.toObject(exec); 4111 4112 // Create the dictionary wrapper from the initializer object. 4113 JSDictionary dictionary(exec, initializerObject); 4114 4115 // Attempt to fill in the EventInit. 4116 if (!fill${interfaceName}Init(eventInit, dictionary)) 4117 return JSValue::encode(jsUndefined()); 4118 } 4119 4120 RefPtr<${interfaceName}> event = ${interfaceName}::create(eventType, eventInit); 4121 return JSValue::encode(toJS(exec, jsConstructor->globalObject(), event.get())); 4122} 4123 4124bool fill${interfaceName}Init(${interfaceName}Init& eventInit, JSDictionary& dictionary) 4125{ 4126END 4127 4128 foreach my $interfaceBase (@{$interface->parents}) { 4129 push(@implContent, <<END); 4130 if (!fill${interfaceBase}Init(eventInit, dictionary)) 4131 return false; 4132 4133END 4134 } 4135 4136 for (my $index = 0; $index < @{$interface->attributes}; $index++) { 4137 my $attribute = @{$interface->attributes}[$index]; 4138 if ($attribute->signature->extendedAttributes->{"InitializedByEventConstructor"}) { 4139 my $attributeName = $attribute->signature->name; 4140 push(@implContent, <<END); 4141 if (!dictionary.tryGetProperty("${attributeName}", eventInit.${attributeName})) 4142 return false; 4143END 4144 } 4145 } 4146 4147 push(@$outputArray, <<END); 4148 return true; 4149} 4150 4151END 4152 } elsif ($codeGenerator->IsConstructorTemplate($interface, "TypedArray")) { 4153 $implIncludes{"JSArrayBufferViewHelper.h"} = 1; 4154 my $viewType = $interface->extendedAttributes->{"TypedArray"}; 4155 push(@$outputArray, "EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}(ExecState* exec)\n"); 4156 push(@$outputArray, "{\n"); 4157 push(@$outputArray, " ${constructorClassName}* jsConstructor = jsCast<${constructorClassName}*>(exec->callee());\n"); 4158 push(@$outputArray, " RefPtr<$interfaceName> array = constructArrayBufferView<$interfaceName, $viewType>(exec);\n"); 4159 push(@$outputArray, " if (!array.get())\n"); 4160 push(@$outputArray, " // Exception has already been thrown.\n"); 4161 push(@$outputArray, " return JSValue::encode(JSValue());\n"); 4162 push(@$outputArray, " return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), array.get())));\n"); 4163 push(@$outputArray, "}\n\n"); 4164 4165 push(@$outputArray, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, ${interfaceName}* object)\n"); 4166 push(@$outputArray, "{\n"); 4167 push(@$outputArray, " return toJSArrayBufferView<${className}>(exec, globalObject, object);\n"); 4168 push(@$outputArray, "}\n\n"); 4169 4170 if ($interface->extendedAttributes->{"CustomIndexedSetter"}) { 4171 push(@$outputArray, "void ${className}::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value)\n"); 4172 push(@$outputArray, "{\n"); 4173 push(@$outputArray, " impl()->set(index, value.toNumber(exec));\n"); 4174 push(@$outputArray, "}\n\n"); 4175 } 4176 } elsif (!HasCustomConstructor($interface) && (!$interface->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor)) { 4177 my $overloadedIndexString = ""; 4178 if ($function->{overloadedIndex} && $function->{overloadedIndex} > 0) { 4179 $overloadedIndexString .= $function->{overloadedIndex}; 4180 } 4181 4182 push(@$outputArray, "EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}${overloadedIndexString}(ExecState* exec)\n"); 4183 push(@$outputArray, "{\n"); 4184 push(@$outputArray, " ${constructorClassName}* castedThis = jsCast<${constructorClassName}*>(exec->callee());\n"); 4185 4186 my @constructorArgList; 4187 4188 $implIncludes{"<runtime/Error.h>"} = 1; 4189 4190 GenerateArgumentsCountCheck($outputArray, $function, $interface); 4191 4192 if ($function->signature->extendedAttributes->{"RaisesException"} || $interface->extendedAttributes->{"ConstructorRaisesException"}) { 4193 $implIncludes{"ExceptionCode.h"} = 1; 4194 push(@$outputArray, " ExceptionCode ec = 0;\n"); 4195 } 4196 4197 # FIXME: For now, we do not support SVG constructors. 4198 # FIXME: Currently [Constructor(...)] does not yet support optional arguments without [Default=...] 4199 my $numParameters = @{$function->parameters}; 4200 my ($dummy, $paramIndex) = GenerateParametersCheck($outputArray, $function, $interface, $numParameters, $interfaceName, "constructorCallback", undef, undef, undef); 4201 4202 if ($codeGenerator->ExtendedAttributeContains($interface->extendedAttributes->{"ConstructorCallWith"}, "ScriptExecutionContext")) { 4203 push(@constructorArgList, "context"); 4204 push(@$outputArray, " ScriptExecutionContext* context = castedThis->scriptExecutionContext();\n"); 4205 push(@$outputArray, " if (!context)\n"); 4206 push(@$outputArray, " return throwVMError(exec, createReferenceError(exec, \"${interfaceName} constructor associated document is unavailable\"));\n"); 4207 } 4208 if ($generatingNamedConstructor) { 4209 push(@constructorArgList, "castedThis->document()"); 4210 } 4211 4212 my $index = 0; 4213 foreach my $parameter (@{$function->parameters}) { 4214 last if $index eq $paramIndex; 4215 push(@constructorArgList, $parameter->name); 4216 $index++; 4217 } 4218 4219 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 4220 push(@constructorArgList, "ec"); 4221 } 4222 my $constructorArg = join(", ", @constructorArgList); 4223 if ($generatingNamedConstructor) { 4224 push(@$outputArray, " RefPtr<${interfaceName}> object = ${interfaceName}::createForJSConstructor(${constructorArg});\n"); 4225 } else { 4226 push(@$outputArray, " RefPtr<${interfaceName}> object = ${interfaceName}::create(${constructorArg});\n"); 4227 } 4228 4229 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 4230 push(@$outputArray, " if (ec) {\n"); 4231 push(@$outputArray, " setDOMException(exec, ec);\n"); 4232 push(@$outputArray, " return JSValue::encode(JSValue());\n"); 4233 push(@$outputArray, " }\n"); 4234 } 4235 4236 push(@$outputArray, " return JSValue::encode(asObject(toJS(exec, castedThis->globalObject(), object.get())));\n"); 4237 push(@$outputArray, "}\n\n"); 4238 } 4239 } 4240} 4241 4242sub GenerateConstructorHelperMethods 4243{ 4244 my $outputArray = shift; 4245 my $className = shift; 4246 my $protoClassName = shift; 4247 my $interfaceName = shift; 4248 my $visibleInterfaceName = shift; 4249 my $interface = shift; 4250 my $generatingNamedConstructor = shift; 4251 4252 my $constructorClassName = $generatingNamedConstructor ? "${className}NamedConstructor" : "${className}Constructor"; 4253 my $leastConstructorLength = 0; 4254 if ($codeGenerator->IsConstructorTemplate($interface, "Event") || $codeGenerator->IsConstructorTemplate($interface, "TypedArray")) { 4255 $leastConstructorLength = 1; 4256 } elsif ($interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"CustomConstructor"}) { 4257 my @constructors = @{$interface->constructors}; 4258 my @customConstructors = @{$interface->customConstructors}; 4259 $leastConstructorLength = 255; 4260 foreach my $constructor (@constructors, @customConstructors) { 4261 my $constructorLength = GetFunctionLength($constructor); 4262 $leastConstructorLength = $constructorLength if ($constructorLength < $leastConstructorLength); 4263 } 4264 } else { 4265 $leastConstructorLength = 0; 4266 } 4267 4268 if ($generatingNamedConstructor) { 4269 push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, 0, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n"); 4270 push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n"); 4271 push(@$outputArray, " : DOMConstructorWithDocument(structure, globalObject)\n"); 4272 push(@$outputArray, "{\n"); 4273 push(@$outputArray, "}\n\n"); 4274 } else { 4275 if ($interface->extendedAttributes->{"JSNoStaticTables"}) { 4276 push(@$outputArray, "static const HashTable* get${constructorClassName}Table(ExecState* exec)\n"); 4277 push(@$outputArray, "{\n"); 4278 push(@$outputArray, " return getHashTableForGlobalData(exec->vm(), &${constructorClassName}Table);\n"); 4279 push(@$outputArray, "}\n\n"); 4280 push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, 0, get${constructorClassName}Table, CREATE_METHOD_TABLE($constructorClassName) };\n\n"); 4281 } else { 4282 push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleInterfaceName}Constructor\", &Base::s_info, &${constructorClassName}Table, 0, CREATE_METHOD_TABLE($constructorClassName) };\n\n"); 4283 } 4284 4285 push(@$outputArray, "${constructorClassName}::${constructorClassName}(Structure* structure, JSDOMGlobalObject* globalObject)\n"); 4286 push(@$outputArray, " : DOMConstructorObject(structure, globalObject)\n"); 4287 push(@$outputArray, "{\n}\n\n"); 4288 } 4289 4290 push(@$outputArray, "void ${constructorClassName}::finishCreation(ExecState* exec, JSDOMGlobalObject* globalObject)\n"); 4291 push(@$outputArray, "{\n"); 4292 if ($interfaceName eq "DOMWindow") { 4293 push(@$outputArray, " Base::finishCreation(exec->vm());\n"); 4294 push(@$outputArray, " ASSERT(inherits(&s_info));\n"); 4295 push(@$outputArray, " putDirect(exec->vm(), exec->propertyNames().prototype, globalObject->prototype(), DontDelete | ReadOnly);\n"); 4296 } elsif ($generatingNamedConstructor) { 4297 push(@$outputArray, " Base::finishCreation(globalObject);\n"); 4298 push(@$outputArray, " ASSERT(inherits(&s_info));\n"); 4299 push(@$outputArray, " putDirect(exec->vm(), exec->propertyNames().prototype, ${className}Prototype::self(exec, globalObject), None);\n"); 4300 } else { 4301 push(@$outputArray, " Base::finishCreation(exec->vm());\n"); 4302 push(@$outputArray, " ASSERT(inherits(&s_info));\n"); 4303 push(@$outputArray, " putDirect(exec->vm(), exec->propertyNames().prototype, ${protoClassName}::self(exec, globalObject), DontDelete | ReadOnly);\n"); 4304 } 4305 push(@$outputArray, " putDirect(exec->vm(), exec->propertyNames().length, jsNumber(${leastConstructorLength}), ReadOnly | DontDelete | DontEnum);\n") if defined $leastConstructorLength; 4306 push(@$outputArray, "}\n\n"); 4307 4308 if (!$generatingNamedConstructor) { 4309 my $hasStaticFunctions = 0; 4310 foreach my $function (@{$interface->functions}) { 4311 if ($function->isStatic) { 4312 $hasStaticFunctions = 1; 4313 last; 4314 } 4315 } 4316 4317 my $kind = $hasStaticFunctions ? "Property" : "Value"; 4318 4319 push(@$outputArray, "bool ${constructorClassName}::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n"); 4320 push(@$outputArray, "{\n"); 4321 push(@$outputArray, " return getStatic${kind}Slot<${constructorClassName}, JSDOMWrapper>(exec, " . constructorHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $constructorClassName) . ", jsCast<${constructorClassName}*>(cell), propertyName, slot);\n"); 4322 push(@$outputArray, "}\n\n"); 4323 4324 push(@$outputArray, "bool ${constructorClassName}::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)\n"); 4325 push(@$outputArray, "{\n"); 4326 push(@$outputArray, " return getStatic${kind}Descriptor<${constructorClassName}, JSDOMWrapper>(exec, " . constructorHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $constructorClassName) . ", jsCast<${constructorClassName}*>(object), propertyName, descriptor);\n"); 4327 push(@$outputArray, "}\n\n"); 4328 } 4329 4330 if (IsConstructable($interface)) { 4331 if (!$interface->extendedAttributes->{"NamedConstructor"} || $generatingNamedConstructor) { 4332 my $conditionalString = $codeGenerator->GenerateConstructorConditionalString($interface); 4333 push(@$outputArray, "#if $conditionalString\n") if $conditionalString; 4334 push(@$outputArray, "ConstructType ${constructorClassName}::getConstructData(JSCell*, ConstructData& constructData)\n"); 4335 push(@$outputArray, "{\n"); 4336 push(@$outputArray, " constructData.native.function = construct${className};\n"); 4337 push(@$outputArray, " return ConstructTypeHost;\n"); 4338 push(@$outputArray, "}\n"); 4339 push(@$outputArray, "#endif // $conditionalString\n") if $conditionalString; 4340 push(@$outputArray, "\n"); 4341 } 4342 } 4343} 4344 4345sub HasCustomConstructor 4346{ 4347 my $interface = shift; 4348 4349 return $interface->extendedAttributes->{"CustomConstructor"}; 4350} 4351 4352sub HasCustomGetter 4353{ 4354 my $attrExt = shift; 4355 return $attrExt->{"Custom"} || $attrExt->{"CustomGetter"} ; 4356} 4357 4358sub HasCustomSetter 4359{ 4360 my $attrExt = shift; 4361 return $attrExt->{"Custom"} || $attrExt->{"CustomSetter"}; 4362} 4363 4364sub HasCustomMethod 4365{ 4366 my $attrExt = shift; 4367 return $attrExt->{"Custom"}; 4368} 4369 4370sub IsConstructable 4371{ 4372 my $interface = shift; 4373 4374 return HasCustomConstructor($interface) || $interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"NamedConstructor"} || $interface->extendedAttributes->{"ConstructorTemplate"}; 4375} 4376 43771; 4378