Fast-path for casting JS wrappers to JSElement.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Apr 2014 04:42:21 +0000 (04:42 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Apr 2014 04:42:21 +0000 (04:42 +0000)
<https://webkit.org/b/131210>

Add an extended JSType for Element wrappers so we can avoid walking
the ClassInfo chain in those bindings as well.

Generalized the code to select a casting helper in the bindings
generator into a function (GetCastingHelperForThisObject.)
Updated all the jsDynamicCast call sites to go through this, in case
there's an optimized cast available for the desired type.

Reviewed by Benjamin Poulain.

* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMWrapper.h:
* bindings/js/JSElementCustom.h: Added.
(WebCore::jsElementCast):
* bindings/js/JSNodeCustom.h:
(WebCore::jsNodeCast):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
(GetCastingHelperForThisObject):
(GenerateImplementation):
* dom/Element.idl:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@166765 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSDOMWrapper.h
Source/WebCore/bindings/js/JSElementCustom.h [new file with mode: 0644]
Source/WebCore/bindings/js/JSNodeCustom.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/dom/Element.idl

index 14d4e6b..3f89bb6 100644 (file)
@@ -1,5 +1,32 @@
 2014-04-03  Andreas Kling  <akling@apple.com>
 
+        Fast-path for casting JS wrappers to JSElement.
+        <https://webkit.org/b/131210>
+
+        Add an extended JSType for Element wrappers so we can avoid walking
+        the ClassInfo chain in those bindings as well.
+
+        Generalized the code to select a casting helper in the bindings
+        generator into a function (GetCastingHelperForThisObject.)
+        Updated all the jsDynamicCast call sites to go through this, in case
+        there's an optimized cast available for the desired type.
+
+        Reviewed by Benjamin Poulain.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMWrapper.h:
+        * bindings/js/JSElementCustom.h: Added.
+        (WebCore::jsElementCast):
+        * bindings/js/JSNodeCustom.h:
+        (WebCore::jsNodeCast):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        (GetCastingHelperForThisObject):
+        (GenerateImplementation):
+        * dom/Element.idl:
+
+2014-04-03  Andreas Kling  <akling@apple.com>
+
         Rebaseline a bindings test.
 
         * bindings/scripts/test/JS/JSTestNode.h:
index be2ca96..66b9eb4 100644 (file)
                AD726FEE16DA11BC003A4E6D /* JSStyleSheetCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = AD726FEC16D9F4B9003A4E6D /* JSStyleSheetCustom.h */; settings = {ATTRIBUTES = (Private, ); }; };
                AD726FEF16DA11F5003A4E6D /* JSCSSRuleCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = AD726FE916D9F40A003A4E6D /* JSCSSRuleCustom.h */; settings = {ATTRIBUTES = (Private, ); }; };
                ADDF1AD71257CD9A0003A759 /* RenderSVGPath.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF1AD51257CD9A0003A759 /* RenderSVGPath.h */; };
+               ADEC78F818EE5308001315C2 /* JSElementCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = ADEC78F718EE5308001315C2 /* JSElementCustom.h */; settings = {ATTRIBUTES = (Private, ); }; };
                B10B6980140C174000BC1C26 /* WebVTTToken.h in Headers */ = {isa = PBXBuildFile; fileRef = B10B697D140C174000BC1C26 /* WebVTTToken.h */; };
                B10B6981140C174000BC1C26 /* WebVTTTokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B10B697E140C174000BC1C26 /* WebVTTTokenizer.cpp */; };
                B10B6982140C174000BC1C26 /* WebVTTTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = B10B697F140C174000BC1C26 /* WebVTTTokenizer.h */; };
                ADDF1AD51257CD9A0003A759 /* RenderSVGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGPath.h; sourceTree = "<group>"; };
                ADE11F4A18D8311B0078983B /* ElementDescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementDescendantIterator.h; sourceTree = "<group>"; };
                ADE16736181050C300463A2E /* RenderPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderPtr.h; sourceTree = "<group>"; };
+               ADEC78F718EE5308001315C2 /* JSElementCustom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSElementCustom.h; sourceTree = "<group>"; };
                B10B697D140C174000BC1C26 /* WebVTTToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTToken.h; sourceTree = "<group>"; };
                B10B697E140C174000BC1C26 /* WebVTTTokenizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebVTTTokenizer.cpp; sourceTree = "<group>"; };
                B10B697F140C174000BC1C26 /* WebVTTTokenizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTTokenizer.h; sourceTree = "<group>"; };
                                BCD9C25E0C17AA67005C90A2 /* JSDOMWindowCustom.cpp */,
                                652FBBBB0DE27CB60001D386 /* JSDOMWindowCustom.h */,
                                BC2ED5540C6B9BD300920BFF /* JSElementCustom.cpp */,
+                               ADEC78F718EE5308001315C2 /* JSElementCustom.h */,
                                BCEFAF4D0C317E6900FA81F6 /* JSEventCustom.cpp */,
                                2E7582ED12764F260062628B /* JSFileReaderCustom.cpp */,
                                FE80D7A60E9C1ED2000D6F75 /* JSGeolocationCustom.cpp */,
                                2E43464D0F546A8200B0F1BA /* WorkerLocation.h in Headers */,
                                2E4346500F546A8200B0F1BA /* WorkerMessagingProxy.h in Headers */,
                                CD52481B18E200ED0008A07D /* DisplaySleepDisabler.h in Headers */,
+                               ADEC78F818EE5308001315C2 /* JSElementCustom.h in Headers */,
                                E1271A0B0EEEC77A00F61213 /* WorkerNavigator.h in Headers */,
                                1ABC7109170E5E1B00F9A9D6 /* WorkerNavigatorStorageQuota.h in Headers */,
                                2E4346510F546A8200B0F1BA /* WorkerObjectProxy.h in Headers */,
index a14c681..9656f3c 100644 (file)
@@ -30,6 +30,7 @@ namespace WebCore {
 class ScriptExecutionContext;
 
 static const uint8_t JSNodeType = JSC::LastJSCObjectType + 1;
+static const uint8_t JSElementType = JSC::LastJSCObjectType + 2;
 
 class JSDOMWrapper : public JSC::JSDestructibleObject {
 public:
diff --git a/Source/WebCore/bindings/js/JSElementCustom.h b/Source/WebCore/bindings/js/JSElementCustom.h
new file mode 100644 (file)
index 0000000..2a1ba01
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSElementCustom_h
+#define JSElementCustom_h
+
+#include "JSDOMBinding.h"
+#include "JSElement.h"
+
+namespace WebCore {
+
+ALWAYS_INLINE JSElement* jsElementCast(JSC::JSValue value)
+{
+    if (UNLIKELY(!value.isCell()))
+        return nullptr;
+    return value.asCell()->type() >= JSElementType ? JSC::jsCast<JSElement*>(value) : nullptr;
+}
+
+} // namespace WebCore
+
+#endif // JSElementCustom_h
index 79d4471..fc00cfc 100644 (file)
@@ -82,7 +82,7 @@ ALWAYS_INLINE JSNode* jsNodeCast(JSC::JSValue value)
 {
     if (UNLIKELY(!value.isCell()))
         return nullptr;
-    return value.asCell()->type() == JSNodeType ? JSC::jsCast<JSNode*>(value) : nullptr;
+    return value.asCell()->type() >= JSNodeType ? JSC::jsCast<JSNode*>(value) : nullptr;
 }
 
 } // namespace WebCore
index defd1a6..c893065 100644 (file)
@@ -959,6 +959,8 @@ sub GenerateHeader
     push(@headerContent, "    {\n");
     if (IsDOMGlobalObject($interface)) {
         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info());\n");
+    } elsif ($codeGenerator->InheritsInterface($interface, "Element")) {
+        push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSElementType), StructureFlags), info());\n");
     } elsif ($codeGenerator->InheritsInterface($interface, "Node")) {
         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSNodeType), StructureFlags), info());\n");
     } else {
@@ -1693,6 +1695,19 @@ sub GetRuntimeEnableFunctionName
     return "RuntimeEnabledFeatures::sharedFeatures()." . ToMethodName($signature->name) . "Enabled";
 }
 
+sub GetCastingHelperForThisObject
+{
+    my $interface = shift;
+
+    if ($interface->name eq "Node") {
+        return "jsNodeCast";
+    }
+    if ($interface->name eq "Element") {
+        return "jsElementCast";
+    }
+    return "jsDynamicCast<JS" . $interface->name . "*>";
+}
+
 sub GenerateImplementation
 {
     my ($object, $interface) = @_;
@@ -2132,11 +2147,7 @@ sub GenerateImplementation
                     push(@implContent, "    ${className}* castedThis = to${className}(JSValue::decode(thisValue));\n");
                     push(@implContent, "    UNUSED_PARAM(slotBase);\n");
                 } else {
-                    if ($interfaceName eq "Node") {
-                        push(@implContent, "    JSNode* castedThis = jsNodeCast(JSValue::decode(thisValue));\n");
-                    } else {
-                        push(@implContent, "    ${className}* castedThis = jsDynamicCast<$className*>(JSValue::decode(thisValue));\n");
-                    }
+                    push(@implContent, "    ${className}* castedThis = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
                     push(@implContent, "    UNUSED_PARAM(slotBase);\n");
                 }
                 $implIncludes{"ScriptExecutionContext.h"} = 1;
@@ -2354,7 +2365,7 @@ sub GenerateImplementation
             if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
                 push(@implContent, "    ${className}* domObject = to${className}(JSValue::decode(thisValue));\n");
             } else {
-                push(@implContent, "    ${className}* domObject = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n") if ConstructorShouldBeOnInstance($interface);
+                push(@implContent, "    ${className}* domObject = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n") if ConstructorShouldBeOnInstance($interface);
                 push(@implContent, "    ${className}Prototype* domObject = jsDynamicCast<${className}Prototype*>(baseValue);\n") if !ConstructorShouldBeOnInstance($interface);
             }
             push(@implContent, "    if (!domObject)\n");
@@ -2379,7 +2390,7 @@ sub GenerateImplementation
             if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
                 push(@implContent, "    ${className}* castedThis = to${className}(JSValue::decode(thisValue));\n");
             } else {
-                push(@implContent, "    ${className}* castedThis = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n");
+                push(@implContent, "    ${className}* castedThis = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
             }
             push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
             push(@implContent, "        throwVMTypeError(exec);\n");
@@ -2486,7 +2497,7 @@ sub GenerateImplementation
                     if ($interface->extendedAttributes->{"CustomProxyToJSObject"}) {
                         push(@implContent, "    ${className}* castedThis = to${className}(JSValue::decode(thisValue));\n");
                     } else {
-                        push(@implContent, "    ${className}* castedThis = jsDynamicCast<${className}*>(JSValue::decode(thisValue));\n");
+                        push(@implContent, "    ${className}* castedThis = " . GetCastingHelperForThisObject($interface) . "(JSValue::decode(thisValue));\n");
                     }
                     push(@implContent, "    if (UNLIKELY(!castedThis)) {\n");
                     push(@implContent, "        throwVMTypeError(exec, makeDOMBindingsTypeErrorString(\"The \", \"$interfaceName\", \".\", \"$name\", \" setter can only be used on instances of \", \"$interfaceName\"));\n");
@@ -2721,7 +2732,7 @@ sub GenerateImplementation
                     push(@implContent, "        return throwVMTypeError(exec);\n");
                 } else {
                     push(@implContent, "    JSValue thisValue = exec->thisValue();\n");
-                    push(@implContent, "    $className* castedThis = jsDynamicCast<$className*>(thisValue);\n");
+                    push(@implContent, "    $className* castedThis = " . GetCastingHelperForThisObject($interface) . "(thisValue);\n");
                     my $domFunctionName = $function->signature->name;
                     push(@implContent, "    if (UNLIKELY(!castedThis))\n");
                     push(@implContent, "        return throwVMTypeError(exec, makeDOMBindingsTypeErrorString(\"Can only call \", \"$interfaceName\", \".\", \"$domFunctionName\", \" on instances of \", \"$interfaceName\"));\n");
index f8e91ca..9778616 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 [
+    JSCustomHeader,
     JSGenerateToNativeObject,
 ] interface Element : Node {