Eagerly reify DOM prototype attributes
authormhahnenberg@apple.com <mhahnenberg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 Jun 2014 18:53:32 +0000 (18:53 +0000)
committermhahnenberg@apple.com <mhahnenberg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 Jun 2014 18:53:32 +0000 (18:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133558

Reviewed by Oliver Hunt.

Source/JavaScriptCore:
This allows us to get rid of a lot of the additional overhead of pushing DOM attributes up into the prototype.
By eagerly reifying the custom getters and setters into the actual JSObject we avoid having to override
getOwnPropertySlot for all of the DOM prototypes, which is a lot of the overhead of doing property lookups on
DOM wrappers.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LowLevelInterpreter.asm:
* runtime/BatchedTransitionOptimizer.h:
(JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer):
* runtime/CustomGetterSetter.cpp: Added.
(JSC::callCustomSetter):
* runtime/CustomGetterSetter.h: Added.
(JSC::CustomGetterSetter::create):
(JSC::CustomGetterSetter::getter):
(JSC::CustomGetterSetter::setter):
(JSC::CustomGetterSetter::createStructure):
(JSC::CustomGetterSetter::CustomGetterSetter):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::putToPrimitive):
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::isCustomGetterSetter):
* runtime/JSCell.h:
* runtime/JSCellInlines.h:
(JSC::JSCell::isCustomGetterSetter):
(JSC::JSCell::canUseFastGetOwnProperty):
* runtime/JSFunction.cpp:
(JSC::JSFunction::isHostOrBuiltinFunction): Deleted.
(JSC::JSFunction::isBuiltinFunction): Deleted.
* runtime/JSFunction.h:
* runtime/JSFunctionInlines.h: Inlined some random functions that appeared hot during profiling.
(JSC::JSFunction::isBuiltinFunction):
(JSC::JSFunction::isHostOrBuiltinFunction):
* runtime/JSObject.cpp:
(JSC::JSObject::put):
(JSC::JSObject::putDirectCustomAccessor):
(JSC::JSObject::fillGetterPropertySlot):
(JSC::JSObject::fillCustomGetterPropertySlot):
(JSC::JSObject::getOwnPropertySlotSlow): Deleted.
* runtime/JSObject.h:
(JSC::JSObject::hasCustomGetterSetterProperties):
(JSC::JSObject::convertToDictionary):
(JSC::JSObject::inlineGetOwnPropertySlot):
(JSC::JSObject::getOwnPropertySlotSlow): Inlined because it looked hot during profiling.
(JSC::JSObject::putOwnDataProperty):
(JSC::JSObject::putDirect):
(JSC::JSObject::putDirectWithoutTransition):
* runtime/JSType.h:
* runtime/Lookup.h:
(JSC::reifyStaticProperties):
* runtime/PropertyDescriptor.h:
(JSC::PropertyDescriptor::PropertyDescriptor):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::nextOutOfLineStorageCapacity): Deleted.
(JSC::Structure::suggestedNewOutOfLineStorageCapacity): Deleted.
(JSC::Structure::get): Deleted.
* runtime/Structure.h:
(JSC::Structure::hasCustomGetterSetterProperties):
(JSC::Structure::setHasCustomGetterSetterProperties):
* runtime/StructureInlines.h:
(JSC::Structure::get): Inlined due to hotness.
(JSC::nextOutOfLineStorageCapacity): Inlined due to hotness.
(JSC::Structure::suggestedNewOutOfLineStorageCapacity): Inlined due to hotness.
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
* runtime/WriteBarrier.h:
(JSC::WriteBarrierBase<Unknown>::isCustomGetterSetter):

Source/WebCore:
No new tests.

This allows us to get rid of a lot of the additional overhead of pushing DOM attributes up into the prototype.
By eagerly reifying the custom getters and setters into the actual JSObject we avoid having to override
getOwnPropertySlot for all of the DOM prototypes, which is a lot of the overhead of doing property lookups on
DOM wrappers.

* bindings/scripts/CodeGeneratorJS.pm:
(prototypeHashTableAccessor): Changed to pass along the VM.
(AttributeShouldBeOnInstanceForCompatibility): We were being overly conservative in regard to touch events.
This caused us to store the touch event handler getters and setters on the JSElement instance, which caused
us to override getOwnPropertySlot for every JSElement subclass.
(InstanceOverridesGetOwnPropertySlot): This was being overly paranoid about generate a getOwnPropertySlot if
there was going to be a "constructor" property, even though we handled this in another place already.
(GenerateHeader): Generate a finishCreation for prototypes unless it's the JSDOMWindow. We can't correctly
handle the DOMWindow in this version of the patch because reifying the static properties requires a global object,
which hasn't been created yet when the prototype for the window object is being created.
(GenerateImplementation): Generate the finishCreation calls to reifyStaticProperties.

LayoutTests:
Updating a test expectation after this fix.

* js/dom/constructor-attributes-expected.txt:

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

38 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/constructor-attributes-expected.txt
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/llint/LLIntData.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
Source/JavaScriptCore/runtime/CustomGetterSetter.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/CustomGetterSetter.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSCJSValue.cpp
Source/JavaScriptCore/runtime/JSCJSValue.h
Source/JavaScriptCore/runtime/JSCJSValueInlines.h
Source/JavaScriptCore/runtime/JSCell.h
Source/JavaScriptCore/runtime/JSCellInlines.h
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/JSFunctionInlines.h
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp
Source/JavaScriptCore/runtime/JSType.h
Source/JavaScriptCore/runtime/Lookup.h
Source/JavaScriptCore/runtime/MapConstructor.cpp
Source/JavaScriptCore/runtime/MapIteratorConstructor.cpp
Source/JavaScriptCore/runtime/PropertyDescriptor.h
Source/JavaScriptCore/runtime/SetConstructor.cpp
Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureInlines.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/runtime/WeakMapConstructor.cpp
Source/JavaScriptCore/runtime/WriteBarrier.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

index 8a48d39..ab3cca2 100644 (file)
@@ -1,3 +1,14 @@
+2014-06-05  Mark Hahnenberg  <mhahnenberg@apple.com>
+
+        Eagerly reify DOM prototype attributes
+        https://bugs.webkit.org/show_bug.cgi?id=133558
+
+        Reviewed by Oliver Hunt.
+
+        Updating a test expectation after this fix.
+
+        * js/dom/constructor-attributes-expected.txt:
+
 2014-06-09  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r169693.
index 9af5db7..c4726a8 100644 (file)
@@ -78,7 +78,7 @@ PASS x = URIError.prototype; delete x.constructor; x.hasOwnProperty('constructor
 PASS document.createTextNode('').__proto__.hasOwnProperty('constructor') is true
 PASS canEnum(document.createTextNode('').__proto__, 'constructor') is false
 FAIL x = document.createTextNode('').__proto__; x.constructor = 4; x.constructor should be 4 (of type number). Was [object TextConstructor] (of type object).
-FAIL x = document.createTextNode('').__proto__; delete x.constructor; x.hasOwnProperty('constructor') should be false. Was true.
+PASS x = document.createTextNode('').__proto__; delete x.constructor; x.hasOwnProperty('constructor') is false
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 34995fb..1df935d 100644 (file)
@@ -366,6 +366,7 @@ set(JavaScriptCore_SOURCES
     runtime/ConsoleClient.cpp
     runtime/ConsolePrototype.cpp
     runtime/ConstructData.cpp
+    runtime/CustomGetterSetter.cpp
     runtime/DataView.cpp
     runtime/DataView.h
     runtime/DateConstructor.cpp
index 9cdde91..6da7551 100644 (file)
@@ -1,3 +1,85 @@
+2014-06-05  Mark Hahnenberg  <mhahnenberg@apple.com>
+
+        Eagerly reify DOM prototype attributes
+        https://bugs.webkit.org/show_bug.cgi?id=133558
+
+        Reviewed by Oliver Hunt.
+
+        This allows us to get rid of a lot of the additional overhead of pushing DOM attributes up into the prototype. 
+        By eagerly reifying the custom getters and setters into the actual JSObject we avoid having to override 
+        getOwnPropertySlot for all of the DOM prototypes, which is a lot of the overhead of doing property lookups on 
+        DOM wrappers.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/BatchedTransitionOptimizer.h:
+        (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer):
+        * runtime/CustomGetterSetter.cpp: Added.
+        (JSC::callCustomSetter):
+        * runtime/CustomGetterSetter.h: Added.
+        (JSC::CustomGetterSetter::create):
+        (JSC::CustomGetterSetter::getter):
+        (JSC::CustomGetterSetter::setter):
+        (JSC::CustomGetterSetter::createStructure):
+        (JSC::CustomGetterSetter::CustomGetterSetter):
+        * runtime/JSCJSValue.cpp:
+        (JSC::JSValue::putToPrimitive):
+        * runtime/JSCJSValue.h:
+        * runtime/JSCJSValueInlines.h:
+        (JSC::JSValue::isCustomGetterSetter):
+        * runtime/JSCell.h:
+        * runtime/JSCellInlines.h:
+        (JSC::JSCell::isCustomGetterSetter):
+        (JSC::JSCell::canUseFastGetOwnProperty):
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::isHostOrBuiltinFunction): Deleted.
+        (JSC::JSFunction::isBuiltinFunction): Deleted.
+        * runtime/JSFunction.h:
+        * runtime/JSFunctionInlines.h: Inlined some random functions that appeared hot during profiling.
+        (JSC::JSFunction::isBuiltinFunction):
+        (JSC::JSFunction::isHostOrBuiltinFunction):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::put):
+        (JSC::JSObject::putDirectCustomAccessor):
+        (JSC::JSObject::fillGetterPropertySlot):
+        (JSC::JSObject::fillCustomGetterPropertySlot):
+        (JSC::JSObject::getOwnPropertySlotSlow): Deleted.
+        * runtime/JSObject.h:
+        (JSC::JSObject::hasCustomGetterSetterProperties):
+        (JSC::JSObject::convertToDictionary):
+        (JSC::JSObject::inlineGetOwnPropertySlot):
+        (JSC::JSObject::getOwnPropertySlotSlow): Inlined because it looked hot during profiling.
+        (JSC::JSObject::putOwnDataProperty):
+        (JSC::JSObject::putDirect):
+        (JSC::JSObject::putDirectWithoutTransition):
+        * runtime/JSType.h:
+        * runtime/Lookup.h:
+        (JSC::reifyStaticProperties):
+        * runtime/PropertyDescriptor.h:
+        (JSC::PropertyDescriptor::PropertyDescriptor):
+        * runtime/Structure.cpp:
+        (JSC::Structure::Structure):
+        (JSC::nextOutOfLineStorageCapacity): Deleted.
+        (JSC::Structure::suggestedNewOutOfLineStorageCapacity): Deleted.
+        (JSC::Structure::get): Deleted.
+        * runtime/Structure.h:
+        (JSC::Structure::hasCustomGetterSetterProperties):
+        (JSC::Structure::setHasCustomGetterSetterProperties):
+        * runtime/StructureInlines.h:
+        (JSC::Structure::get): Inlined due to hotness.
+        (JSC::nextOutOfLineStorageCapacity): Inlined due to hotness.
+        (JSC::Structure::suggestedNewOutOfLineStorageCapacity): Inlined due to hotness.
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+        * runtime/WriteBarrier.h:
+        (JSC::WriteBarrierBase<Unknown>::isCustomGetterSetter):
+
 2014-06-07  Mark Lam  <mark.lam@apple.com>
 
         Structure should initialize its previousID in its constructor.
index f57d1aa..d841dd7 100644 (file)
     <ClCompile Include="..\runtime\ConsoleClient.cpp" />
     <ClCompile Include="..\runtime\ConsolePrototype.cpp" />
     <ClCompile Include="..\runtime\ConstructData.cpp" />
+    <ClCompile Include="..\runtime\CustomGetterSetter.cpp" />
     <ClCompile Include="..\runtime\DataView.cpp" />
     <ClCompile Include="..\runtime\DateConstructor.cpp" />
     <ClCompile Include="..\runtime\DateConversion.cpp" />
     <ClInclude Include="..\runtime\ConsoleTypes.h" />
     <ClInclude Include="..\runtime\ConstantMode.h" />
     <ClInclude Include="..\runtime\ConstructData.h" />
+    <ClInclude Include="..\runtime\CustomGetterSetter.h" />
     <ClInclude Include="..\runtime\DataView.h" />
     <ClInclude Include="..\runtime\DateConstructor.h" />
     <ClInclude Include="..\runtime\DateConversion.h" />
index c19b027..bae0ed1 100644 (file)
     <ClCompile Include="..\runtime\ConstructData.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
+    <ClCompile Include="..\runtime\CustomGetterSetter.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
     <ClCompile Include="..\runtime\DateConstructor.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
     <ClInclude Include="..\runtime\ConstructData.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\CustomGetterSetter.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\DateConstructor.h">
       <Filter>runtime</Filter>
     </ClInclude>
index e6914e7..4dbe3e5 100644 (file)
@@ -134,8 +134,8 @@ void Data::performAssertions(VM& vm)
     ASSERT(maxFrameExtentForSlowPathCall == 40);
 #endif
     ASSERT(StringType == 5);
-    ASSERT(ObjectType == 17);
-    ASSERT(FinalObjectType == 18);
+    ASSERT(ObjectType == 18);
+    ASSERT(FinalObjectType == 19);
     ASSERT(MasqueradesAsUndefined == 1);
     ASSERT(ImplementsHasInstance == 2);
     ASSERT(ImplementsDefaultHasInstance == 8);
index ffd1383..d28687a 100644 (file)
@@ -149,8 +149,8 @@ const SlowPutArrayStorageShape = 30
 
 # Type constants.
 const StringType = 5
-const ObjectType = 17
-const FinalObjectType = 18
+const ObjectType = 18
+const FinalObjectType = 19
 
 # Type flags constants.
 const MasqueradesAsUndefined = 1
index 01e9bbe..951a328 100644 (file)
@@ -38,6 +38,8 @@ public:
         : m_vm(&vm)
         , m_object(object)
     {
+        if (!m_object->structure(vm)->isDictionary())
+            m_object->convertToDictionary(vm);
     }
 
     ~BatchedTransitionOptimizer()
diff --git a/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp b/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp
new file mode 100644 (file)
index 0000000..92b0219
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+#include "CustomGetterSetter.h"
+
+#include "JSCJSValueInlines.h"
+#include "SlotVisitorInlines.h"
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(CustomGetterSetter);
+
+const ClassInfo CustomGetterSetter::s_info = { "CustomGetterSetter", 0, 0, 0, CREATE_METHOD_TABLE(CustomGetterSetter) };
+
+void callCustomSetter(ExecState* exec, JSValue customGetterSetter, JSObject* base, JSValue thisValue, JSValue value)
+{
+    CustomGetterSetter::CustomSetter setter = jsCast<CustomGetterSetter*>(customGetterSetter)->setter();
+    if (!setter)
+        return;
+    setter(exec, base, JSValue::encode(thisValue), JSValue::encode(value));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CustomGetterSetter.h b/Source/JavaScriptCore/runtime/CustomGetterSetter.h
new file mode 100644 (file)
index 0000000..4de7ded
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 CustomGetterSetter_h
+#define CustomGetterSetter_h
+
+#include "JSCell.h"
+#include "PropertySlot.h"
+#include "PutPropertySlot.h"
+#include "Structure.h"
+
+namespace JSC {
+
+class CustomGetterSetter : public JSCell {
+public:
+    typedef JSCell Base;
+
+    typedef PropertySlot::GetValueFunc CustomGetter;
+    typedef PutPropertySlot::PutValueFunc CustomSetter;
+
+    static CustomGetterSetter* create(VM& vm, CustomGetter customGetter, CustomSetter customSetter)
+    {
+        CustomGetterSetter* customGetterSetter = new (NotNull, allocateCell<CustomGetterSetter>(vm.heap)) CustomGetterSetter(vm, customGetter, customSetter);
+        customGetterSetter->finishCreation(vm);
+        return customGetterSetter;
+    }
+
+    CustomGetterSetter::CustomGetter getter() const { return m_getter; }
+    CustomGetterSetter::CustomSetter setter() const { return m_setter; }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(CustomGetterSetterType, StructureFlags), info());
+    }
+        
+    DECLARE_EXPORT_INFO;
+
+private:
+    CustomGetterSetter(VM& vm, CustomGetter getter, CustomSetter setter)
+        : JSCell(vm, vm.customGetterSetterStructure.get())
+        , m_getter(getter)
+        , m_setter(setter)
+    {
+    }
+
+    CustomGetter m_getter;
+    CustomSetter m_setter;
+};
+
+void callCustomSetter(ExecState*, JSValue customGetterSetter, JSObject* base, JSValue thisValue, JSValue value);
+
+} // namespace JSC
+
+#endif // CustomGetterSetter_h
index 329c84a..7d7b7bd 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "BooleanConstructor.h"
 #include "BooleanPrototype.h"
+#include "CustomGetterSetter.h"
 #include "Error.h"
 #include "ExceptionHelpers.h"
 #include "GetterSetter.h"
@@ -154,6 +155,11 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
                 return;
             }
 
+            if (gs.isCustomGetterSetter()) {
+                callCustomSetter(exec, gs, obj, slot.thisValue(), value);
+                return;
+            }
+
             // If there's an existing property on the object or one of its 
             // prototypes it should be replaced, so break here.
             break;
index 7e921ae..5f1304f 100644 (file)
@@ -214,6 +214,7 @@ public:
     bool isString() const;
     bool isPrimitive() const;
     bool isGetterSetter() const;
+    bool isCustomGetterSetter() const;
     bool isObject() const;
     bool inherits(const ClassInfo*) const;
         
index 7e46840..4afea8d 100644 (file)
@@ -550,6 +550,11 @@ inline bool JSValue::isGetterSetter() const
     return isCell() && asCell()->isGetterSetter();
 }
 
+inline bool JSValue::isCustomGetterSetter() const
+{
+    return isCell() && asCell()->isCustomGetterSetter();
+}
+
 inline bool JSValue::isObject() const
 {
     return isCell() && asCell()->isObject();
index 997f789..abf4557 100644 (file)
@@ -90,6 +90,7 @@ public:
     bool isString() const;
     bool isObject() const;
     bool isGetterSetter() const;
+    bool isCustomGetterSetter() const;
     bool isProxy() const;
     bool inherits(const ClassInfo*) const;
     bool isAPIValueWrapper() const;
index 27bc9ee..ed111c6 100644 (file)
@@ -156,6 +156,11 @@ inline bool JSCell::isGetterSetter() const
     return m_type == GetterSetterType;
 }
 
+inline bool JSCell::isCustomGetterSetter() const
+{
+    return m_type == CustomGetterSetterType;
+}
+
 inline bool JSCell::isProxy() const
 {
     return m_type == ImpureProxyType || m_type == PureForwardingProxyType;
@@ -221,7 +226,9 @@ ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(VM& vm, Structure& structure, c
 
 inline bool JSCell::canUseFastGetOwnProperty(const Structure& structure)
 {
-    return !structure.hasGetterSetterProperties() && !structure.typeInfo().overridesGetOwnPropertySlot();
+    return !structure.hasGetterSetterProperties() 
+        && !structure.hasCustomGetterSetterProperties()
+        && !structure.typeInfo().overridesGetOwnPropertySlot();
 }
 
 inline bool JSCell::toBoolean(ExecState* exec) const
index f9f889a..0f47ac9 100644 (file)
@@ -174,16 +174,6 @@ const SourceCode* JSFunction::sourceCode() const
     return &jsExecutable()->source();
 }
     
-bool JSFunction::isHostOrBuiltinFunction() const
-{
-    return isHostFunction() || isBuiltinFunction();
-}
-
-bool JSFunction::isBuiltinFunction() const
-{
-    return !isHostFunction() && jsExecutable()->isBuiltinFunction();
-}
-
 void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
     JSFunction* thisObject = jsCast<JSFunction*>(cell);
index 2ebe00f..f7b7f16 100644 (file)
@@ -148,8 +148,8 @@ namespace JSC {
             return m_allocationProfileWatchpoint;
         }
 
-        JS_EXPORT_PRIVATE bool isHostOrBuiltinFunction() const;
-        JS_EXPORT_PRIVATE bool isBuiltinFunction() const;
+        bool isHostOrBuiltinFunction() const;
+        bool isBuiltinFunction() const;
         JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
 
     protected:
index 69f0d4f..ad5b56b 100644 (file)
@@ -51,6 +51,16 @@ inline bool JSFunction::isHostFunction() const
     return m_executable->isHostFunction();
 }
 
+inline bool JSFunction::isBuiltinFunction() const
+{
+    return !isHostFunction() && jsExecutable()->isBuiltinFunction();
+}
+
+inline bool JSFunction::isHostOrBuiltinFunction() const
+{
+    return isHostFunction() || isBuiltinFunction();
+}
+
 inline NativeFunction JSFunction::nativeFunction()
 {
     ASSERT(isHostFunctionNonInline());
index 4d88109..0e27312 100644 (file)
@@ -28,6 +28,7 @@
 #include "CopiedSpaceInlines.h"
 #include "CopyVisitor.h"
 #include "CopyVisitorInlines.h"
+#include "CustomGetterSetter.h"
 #include "DatePrototype.h"
 #include "ErrorConstructor.h"
 #include "Executable.h"
@@ -387,8 +388,13 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
                 if (!thisObject->structure()->isDictionary())
                     slot.setCacheableSetter(obj, offset);
                 return;
-            } else
-                ASSERT(!(attributes & Accessor));
+            }
+            if (gs.isCustomGetterSetter()) {
+                callCustomSetter(exec, gs, obj, slot.thisValue(), value);
+                slot.setCustomProperty(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
+                return;
+            }
+            ASSERT(!(attributes & Accessor));
 
             // If there's an existing property on the object or one of its 
             // prototypes it should be replaced, so break here.
@@ -1224,6 +1230,21 @@ void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSV
     putDirectNonIndexAccessor(exec->vm(), propertyName, value, attributes);
 }
 
+void JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+    ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
+
+    PutPropertySlot slot(this);
+    putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
+
+    ASSERT(slot.type() == PutPropertySlot::NewProperty);
+
+    Structure* structure = this->structure(vm);
+    if (attributes & ReadOnly)
+        structure->setContainsReadOnlyProperties();
+    structure->setHasCustomGetterSetterProperties();
+}
+
 void JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
 {
     PutPropertySlot slot(this);
@@ -1666,10 +1687,18 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue g
         slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter));
         return;
     }
-
     slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset);
 }
 
+NEVER_INLINE void JSObject::fillCustomGetterPropertySlot(PropertySlot& slot, JSValue customGetterSetter, unsigned attributes)
+{
+    if (structure()->isDictionary()) {
+        slot.setCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
+        return;
+    }
+    slot.setCacheableCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
+}
+
 void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, const PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
 {
     VM& vm = exec->vm();
@@ -2660,14 +2689,6 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName
     return object->defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
 }
 
-bool JSObject::getOwnPropertySlotSlow(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
-    unsigned i = propertyName.asIndex();
-    if (i != PropertyName::NotAnIndex)
-        return getOwnPropertySlotByIndex(this, exec, i, slot);
-    return false;
-}
-
 JSObject* throwTypeError(ExecState* exec, const String& message)
 {
     return exec->vm().throwException(exec, createTypeError(exec, message));
index ab092d7..80bcfb8 100644 (file)
@@ -467,6 +467,7 @@ public:
     void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0);
     void putDirectNonIndexAccessor(VM&, PropertyName, JSValue, unsigned attributes);
     void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes);
+    JS_EXPORT_PRIVATE void putDirectCustomAccessor(VM&, PropertyName, JSValue, unsigned attributes);
 
     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const;
     JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
@@ -573,6 +574,7 @@ public:
     bool removeDirect(VM&, PropertyName); // Return true if anything is removed.
     bool hasCustomProperties() { return structure()->didTransition(); }
     bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
+    bool hasCustomGetterSetterProperties() { return structure()->hasCustomGetterSetterProperties(); }
 
     // putOwnDataProperty has 'put' like semantics, however this method:
     //  - assumes the object contains no own getter/setter properties.
@@ -587,7 +589,7 @@ public:
     void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); }
 
     JS_EXPORT_PRIVATE void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
-    JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
+    JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
     JSFunction* putDirectBuiltinFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
     void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
 
@@ -623,6 +625,11 @@ public:
     void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*);
     void setStructureAndReallocateStorageIfNecessary(VM&, Structure*);
 
+    void convertToDictionary(VM& vm)
+    {
+        setStructure(vm, Structure::toCacheableDictionaryTransition(vm, structure(vm)));
+    }
+
     void flattenDictionaryObject(VM& vm)
     {
         structure(vm)->flattenDictionaryStructure(vm, this);
@@ -952,6 +959,7 @@ private:
 
     bool inlineGetOwnPropertySlot(ExecState*, VM&, Structure&, PropertyName, PropertySlot&);
     JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset);
+    JS_EXPORT_PRIVATE void fillCustomGetterPropertySlot(PropertySlot&, JSValue, unsigned);
 
     const HashTableValue* findPropertyHashEntry(VM&, PropertyName) const;
         
@@ -964,7 +972,7 @@ private:
     unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
     unsigned getNewVectorLength(unsigned desiredLength);
 
-    JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
+    bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
         
     ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength);
         
@@ -1213,6 +1221,8 @@ ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, VM& vm, S
         JSValue value = getDirect(offset);
         if (structure.hasGetterSetterProperties() && value.isGetterSetter())
             fillGetterPropertySlot(slot, value, attributes, offset);
+        else if (structure.hasCustomGetterSetterProperties() && value.isCustomGetterSetter())
+            fillCustomGetterPropertySlot(slot, value, attributes);
         else
             slot.setValue(this, attributes, value, offset);
         return true;
@@ -1221,6 +1231,14 @@ ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, VM& vm, S
     return getOwnPropertySlotSlow(exec, propertyName, slot);
 }
 
+inline bool JSObject::getOwnPropertySlotSlow(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+    unsigned i = propertyName.asIndex();
+    if (i != PropertyName::NotAnIndex)
+        return getOwnPropertySlotByIndex(this, exec, i, slot);
+    return false;
+}
+
 // It may seem crazy to inline a function this large, especially a virtual function,
 // but it makes a big difference to property lookup that derived classes can inline their
 // base class call to this.
@@ -1440,6 +1458,7 @@ inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSVa
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
     ASSERT(!structure()->hasGetterSetterProperties());
+    ASSERT(!structure()->hasCustomGetterSetterProperties());
 
     return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value));
 }
@@ -1447,6 +1466,7 @@ inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSVa
 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
 {
     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
+    ASSERT(!value.isCustomGetterSetter());
     PutPropertySlot slot(this);
     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
 }
@@ -1454,6 +1474,7 @@ inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value
 inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
 {
     ASSERT(!value.isGetterSetter());
+    ASSERT(!value.isCustomGetterSetter());
     putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot, getCallableObject(value));
 }
 
@@ -1461,6 +1482,7 @@ inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyNa
 {
     DeferGC deferGC(vm.heap);
     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
+    ASSERT(!value.isCustomGetterSetter());
     Butterfly* newButterfly = m_butterfly.get();
     if (structure()->putWillGrowOutOfLineStorage())
         newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
index 139d280..b8d82f2 100644 (file)
@@ -35,6 +35,7 @@
 #include "JSPromiseConstructor.h"
 #include "JSPromiseDeferred.h"
 #include "NumberObject.h"
+#include "StructureInlines.h"
 
 namespace JSC {
 
index 30761c0..fb855e9 100644 (file)
@@ -35,6 +35,7 @@ enum JSType : uint8_t {
     // The CompoundType value must come before any JSType that may have children.
     CompoundType,
     GetterSetterType,
+    CustomGetterSetterType,
     APIValueWrapperType,
 
     EvalExecutableType,
index 0491f55..b3a1421 100644 (file)
 #ifndef Lookup_h
 #define Lookup_h
 
+#include "BatchedTransitionOptimizer.h"
 #include "CallFrame.h"
+#include "CustomGetterSetter.h"
+#include "IdentifierInlines.h"
 #include "Intrinsic.h"
 #include "Identifier.h"
 #include "JSGlobalObject.h"
@@ -290,6 +293,34 @@ namespace JSC {
         putEntry(exec, entry, base, propertyName, value, slot);
         return true;
     }
+
+    inline void reifyStaticProperties(VM& vm, const HashTable& table, JSObject* thisObj)
+    {
+        BatchedTransitionOptimizer transitionOptimizer(vm, thisObj);
+        for (auto iter = table.begin(vm); iter != table.end(vm); ++iter) {
+            Identifier propertyName(&vm, iter.key());
+            const HashTableValue* entry = iter.value();
+            if (iter->attributes() & Builtin) {
+                thisObj->putDirectBuiltinFunction(vm, thisObj->globalObject(), propertyName, entry->builtinGenerator()(vm), entry->attributes());
+                continue;
+            }
+
+            if (iter->attributes() & Function) {
+                thisObj->putDirectNativeFunction(vm, thisObj->globalObject(), propertyName, entry->functionLength(),
+                    entry->function(), entry->intrinsic(), entry->attributes());
+                continue;
+            }
+
+            if (iter->attributes() & Accessor) {
+                RELEASE_ASSERT_NOT_REACHED();
+                continue;
+            }
+
+            CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, entry->propertyGetter(), entry->propertyPutter());
+            thisObj->putDirectCustomAccessor(vm, propertyName, customGetterSetter, entry->attributes());
+        }
+    }
+
 } // namespace JSC
 
 #endif // Lookup_h
index 9e3a4bf..04f17d9 100644 (file)
@@ -32,6 +32,7 @@
 #include "JSGlobalObject.h"
 #include "JSMap.h"
 #include "MapPrototype.h"
+#include "StructureInlines.h"
 
 namespace JSC {
 
index fbc6c8b..40cc239 100644 (file)
@@ -31,6 +31,7 @@
 #include "JSGlobalObject.h"
 #include "JSMapIterator.h"
 #include "MapIteratorPrototype.h"
+#include "StructureInlines.h"
 
 namespace JSC {
 
index 84e2700..df74d9e 100644 (file)
@@ -48,6 +48,7 @@ namespace JSC {
         {
             ASSERT(m_value);
             ASSERT(!m_value.isGetterSetter());
+            ASSERT(!m_value.isCustomGetterSetter());
         }
         JS_EXPORT_PRIVATE bool writable() const;
         JS_EXPORT_PRIVATE bool enumerable() const;
index b203888..8ad7e54 100644 (file)
@@ -33,6 +33,7 @@
 #include "JSSet.h"
 #include "MapData.h"
 #include "SetPrototype.h"
+#include "StructureInlines.h"
 
 namespace JSC {
 
index c16ff9b..19d716e 100644 (file)
@@ -31,6 +31,7 @@
 #include "JSGlobalObject.h"
 #include "JSSetIterator.h"
 #include "SetIteratorPrototype.h"
+#include "StructureInlines.h"
 
 namespace JSC {
 
index c3352c7..69224e1 100644 (file)
@@ -168,6 +168,7 @@ Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, co
     , m_dictionaryKind(NoneDictionaryKind)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties(vm))
+    , m_hasCustomGetterSetterProperties(false)
     , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties(vm))
     , m_hasNonEnumerableProperties(false)
     , m_attributesInPrevious(0)
@@ -195,6 +196,7 @@ Structure::Structure(VM& vm)
     , m_dictionaryKind(NoneDictionaryKind)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties(vm))
+    , m_hasCustomGetterSetterProperties(false)
     , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties(vm))
     , m_hasNonEnumerableProperties(false)
     , m_attributesInPrevious(0)
@@ -221,6 +223,7 @@ Structure::Structure(VM& vm, Structure* previous)
     , m_dictionaryKind(previous->m_dictionaryKind)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
+    , m_hasCustomGetterSetterProperties(previous->m_hasCustomGetterSetterProperties)
     , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto)
     , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
     , m_attributesInPrevious(0)
@@ -316,18 +319,6 @@ void Structure::materializePropertyMap(VM& vm)
     checkOffsetConsistency();
 }
 
-inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
-{
-    if (!currentCapacity)
-        return initialOutOfLineCapacity;
-    return currentCapacity * outOfLineGrowthFactor;
-}
-
-size_t Structure::suggestedNewOutOfLineStorageCapacity()
-{
-    return nextOutOfLineStorageCapacity(outOfLineCapacity());
-}
 void Structure::despecifyDictionaryFunction(VM& vm, PropertyName propertyName)
 {
     StringImpl* rep = propertyName.uid();
@@ -895,25 +886,6 @@ PropertyOffset Structure::getConcurrently(VM&, StringImpl* uid, unsigned& attrib
     return invalidOffset;
 }
 
-PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
-{
-    ASSERT(!isCompilationThread());
-    ASSERT(structure()->classInfo() == info());
-
-    DeferGC deferGC(vm.heap);
-    materializePropertyMapIfNecessary(vm, deferGC);
-    if (!propertyTable())
-        return invalidOffset;
-
-    PropertyMapEntry* entry = propertyTable()->get(propertyName.uid());
-    if (!entry)
-        return invalidOffset;
-
-    attributes = entry->attributes;
-    specificValue = entry->specificValue.get();
-    return entry->offset;
-}
-
 bool Structure::despecifyFunction(VM& vm, PropertyName propertyName)
 {
     DeferGC deferGC(vm.heap);
index 41f86be..023d25a 100644 (file)
@@ -118,7 +118,7 @@ public:
     JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
     JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&, Structure*, PropertyName);
     static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
-    static Structure* toCacheableDictionaryTransition(VM&, Structure*);
+    JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*);
     static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
     static Structure* sealTransition(VM&, Structure*);
     static Structure* freezeTransition(VM&, Structure*);
@@ -130,9 +130,9 @@ public:
     bool isExtensible() const { return !m_preventExtensions; }
     bool didTransition() const { return m_didTransition; }
     bool putWillGrowOutOfLineStorage();
-    JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity(); 
+    size_t suggestedNewOutOfLineStorageCapacity(); 
 
-    Structure* flattenDictionaryStructure(VM&, JSObject*);
+    JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*);
 
     static const bool needsDestruction = true;
     static const bool hasImmortalStructure = true;
@@ -264,7 +264,7 @@ public:
 
     PropertyOffset get(VM&, PropertyName);
     PropertyOffset get(VM&, const WTF::String& name);
-    JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue);
+    PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue);
 
     PropertyOffset getConcurrently(VM&, StringImpl* uid);
     PropertyOffset getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue);
@@ -277,6 +277,10 @@ public:
         if (!is__proto__)
             m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
     }
+
+    bool hasCustomGetterSetterProperties() const { return m_hasCustomGetterSetterProperties; }
+    void setHasCustomGetterSetterProperties() { m_hasCustomGetterSetterProperties = true; }
+
     void setContainsReadOnlyProperties()
     {
         m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
@@ -522,6 +526,7 @@ private:
     unsigned m_dictionaryKind : 2;
     bool m_isPinnedPropertyTable : 1;
     bool m_hasGetterSetterProperties : 1;
+    bool m_hasCustomGetterSetterProperties : 1;
     bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1;
     bool m_hasNonEnumerableProperties : 1;
     unsigned m_attributesInPrevious : 14;
index b6be0ab..4098456 100644 (file)
@@ -99,6 +99,25 @@ inline PropertyOffset Structure::get(VM& vm, const WTF::String& name)
     return entry ? entry->offset : invalidOffset;
 }
     
+inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
+{
+    ASSERT(!isCompilationThread());
+    ASSERT(structure()->classInfo() == info());
+
+    DeferGC deferGC(vm.heap);
+    materializePropertyMapIfNecessary(vm, deferGC);
+    if (!propertyTable())
+        return invalidOffset;
+
+    PropertyMapEntry* entry = propertyTable()->get(propertyName.uid());
+    if (!entry)
+        return invalidOffset;
+
+    attributes = entry->attributes;
+    specificValue = entry->specificValue.get();
+    return entry->offset;
+}
+
 inline PropertyOffset Structure::getConcurrently(VM& vm, StringImpl* uid)
 {
     unsigned attributesIgnored;
@@ -246,6 +265,18 @@ ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
     return true;
 }
 
+inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
+{
+    if (!currentCapacity)
+        return initialOutOfLineCapacity;
+    return currentCapacity * outOfLineGrowthFactor;
+}
+
+inline size_t Structure::suggestedNewOutOfLineStorageCapacity()
+{
+    return nextOutOfLineStorageCapacity(outOfLineCapacity());
+}
+
 } // namespace JSC
 
 #endif // StructureInlines_h
index a185a3d..f10a92f 100644 (file)
@@ -37,6 +37,7 @@
 #include "CodeCache.h"
 #include "CommonIdentifiers.h"
 #include "CommonSlowPaths.h"
+#include "CustomGetterSetter.h"
 #include "DFGLongLivedState.h"
 #include "DFGWorklist.h"
 #include "DebuggerActivation.h"
@@ -250,6 +251,7 @@ VM::VM(VMType vmType, HeapType heapType)
     notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
     propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
     getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
+    customGetterSetterStructure.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull()));
     apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
     JSScopeStructure.set(*this, JSScope::createStructure(*this, 0, jsNull()));
     executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
index 07b49f3..ba9bc01 100644 (file)
@@ -262,6 +262,7 @@ namespace JSC {
         Strong<Structure> notAnObjectStructure;
         Strong<Structure> propertyNameIteratorStructure;
         Strong<Structure> getterSetterStructure;
+        Strong<Structure> customGetterSetterStructure;
         Strong<Structure> apiWrapperStructure;
         Strong<Structure> JSScopeStructure;
         Strong<Structure> executableStructure;
index f3540fa..03af73e 100644 (file)
@@ -30,6 +30,7 @@
 #include "JSCellInlines.h"
 #include "JSGlobalObject.h"
 #include "JSWeakMap.h"
+#include "StructureInlines.h"
 #include "WeakMapPrototype.h"
 
 namespace JSC {
index 6325dec..c5fe089 100644 (file)
@@ -152,6 +152,7 @@ public:
     bool isObject() const { return get().isObject(); }
     bool isNull() const { return get().isNull(); }
     bool isGetterSetter() const { return get().isGetterSetter(); }
+    bool isCustomGetterSetter() const { return get().isCustomGetterSetter(); }
     
     JSValue* slot()
     { 
index d0fcefe..4259267 100644 (file)
@@ -1,3 +1,29 @@
+2014-06-05  Mark Hahnenberg  <mhahnenberg@apple.com>
+
+        Eagerly reify DOM prototype attributes
+        https://bugs.webkit.org/show_bug.cgi?id=133558
+
+        Reviewed by Oliver Hunt.
+
+        No new tests.
+
+        This allows us to get rid of a lot of the additional overhead of pushing DOM attributes up into the prototype. 
+        By eagerly reifying the custom getters and setters into the actual JSObject we avoid having to override 
+        getOwnPropertySlot for all of the DOM prototypes, which is a lot of the overhead of doing property lookups on 
+        DOM wrappers.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (prototypeHashTableAccessor): Changed to pass along the VM.
+        (AttributeShouldBeOnInstanceForCompatibility): We were being overly conservative in regard to touch events. 
+        This caused us to store the touch event handler getters and setters on the JSElement instance, which caused
+        us to override getOwnPropertySlot for every JSElement subclass.
+        (InstanceOverridesGetOwnPropertySlot): This was being overly paranoid about generate a getOwnPropertySlot if
+        there was going to be a "constructor" property, even though we handled this in another place already.
+        (GenerateHeader): Generate a finishCreation for prototypes unless it's the JSDOMWindow. We can't correctly 
+        handle the DOMWindow in this version of the patch because reifying the static properties requires a global object,
+        which hasn't been created yet when the prototype for the window object is being created.
+        (GenerateImplementation): Generate the finishCreation calls to reifyStaticProperties.
+
 2014-06-09  Alexey Proskuryakov  <ap@apple.com>
 
         REGRESSION (r169681): Three tests are broken
index 1d7daca..58535e2 100644 (file)
@@ -350,7 +350,7 @@ sub prototypeHashTableAccessor
     my $noStaticTables = shift;
     my $className = shift;
     if ($noStaticTables) {
-        return "get${className}PrototypeTable(exec->vm())";
+        return "get${className}PrototypeTable(vm)";
     } else {
         return "${className}PrototypeTable";
     }
@@ -659,7 +659,6 @@ sub AttributeShouldBeOnInstanceForCompatibility
     my $interface = shift;
     my $attribute = shift;
     my $interfaceName = $interface->name;
-    return 1 if ($attribute->signature->name =~ "touch");
     return 0;
 }
 
@@ -746,7 +745,7 @@ sub InstanceOverridesGetOwnPropertySlot
         || $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
         || $hasImpureNamedGetter;
 
-    return $numInstanceAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"} || $hasComplexGetter;
+    return $numInstanceAttributes > 0 || $hasComplexGetter;
 
 }
 
@@ -1203,8 +1202,12 @@ sub GenerateHeader
 
     push(@headerContent, "    DECLARE_INFO;\n");
     if (PrototypeOverridesGetOwnPropertySlot($interface)) {
-        push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
-        $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
+        if (IsDOMGlobalObject($interface)) {
+            push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&);\n");
+            $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
+        } else {
+            push(@headerContent, "    void finishCreation(JSC::VM&);\n");
+        }
     }
     if ($interface->extendedAttributes->{"JSCustomMarkFunction"} or $needsVisitChildren) {
         $structureFlags{"JSC::OverridesVisitChildren"} = 1;
@@ -1952,21 +1955,36 @@ sub GenerateImplementation
     }
 
     if (PrototypeOverridesGetOwnPropertySlot($interface)) {
-        push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
-        push(@implContent, "{\n");
-        push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(object);\n");
-
         my $numPrototypeAttributes = PrototypeAttributeCount($interface);
-        if ($numConstants eq 0 && $numFunctions eq 0 && $numPrototypeAttributes eq 0) {
-            push(@implContent, "    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");        
-        } elsif ($numConstants eq 0 && $numPrototypeAttributes eq 0) {
-            push(@implContent, "    return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
-        } elsif ($numFunctions eq 0 && $numPrototypeAttributes eq 0) {
-            push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
+        if (IsDOMGlobalObject($interface)) {
+            push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)\n");
+            push(@implContent, "{\n");
+            push(@implContent, "    VM& vm = exec->vm();\n");
+            push(@implContent, "    UNUSED_PARAM(vm);\n");
+            push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(object);\n");
+
+            if ($numConstants eq 0 && $numFunctions eq 0 && $numPrototypeAttributes eq 0) {
+                push(@implContent, "    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");        
+            } elsif ($numConstants eq 0 && $numPrototypeAttributes eq 0) {
+                push(@implContent, "    return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
+            } elsif ($numFunctions eq 0 && $numPrototypeAttributes eq 0) {
+                push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
+            } else {
+                push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
+            }
+            push(@implContent, "}\n\n");
+        } elsif ($numConstants > 0 || $numFunctions > 0 || $numPrototypeAttributes > 0) {
+            push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
+            push(@implContent, "{\n");
+            push(@implContent, "    Base::finishCreation(vm);\n");
+            push(@implContent, "    reifyStaticProperties(vm, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", this);\n");
+            push(@implContent, "}\n\n");
         } else {
-            push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($interface->extendedAttributes->{"JSNoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
+            push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
+            push(@implContent, "{\n");
+            push(@implContent, "    Base::finishCreation(vm);\n");
+            push(@implContent, "}\n\n");
         }
-        push(@implContent, "}\n\n");
     }
 
     if ($interface->extendedAttributes->{"JSCustomNamedGetterOnPrototype"}) {