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