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
+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.
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
runtime/ConsoleClient.cpp
runtime/ConsolePrototype.cpp
runtime/ConstructData.cpp
+ runtime/CustomGetterSetter.cpp
runtime/DataView.cpp
runtime/DataView.h
runtime/DateConstructor.cpp
+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.
<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" />
<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>
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);
# Type constants.
const StringType = 5
-const ObjectType = 17
-const FinalObjectType = 18
+const ObjectType = 18
+const FinalObjectType = 19
# Type flags constants.
const MasqueradesAsUndefined = 1
: m_vm(&vm)
, m_object(object)
{
+ if (!m_object->structure(vm)->isDictionary())
+ m_object->convertToDictionary(vm);
}
~BatchedTransitionOptimizer()
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#include "BooleanConstructor.h"
#include "BooleanPrototype.h"
+#include "CustomGetterSetter.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "GetterSetter.h"
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;
bool isString() const;
bool isPrimitive() const;
bool isGetterSetter() const;
+ bool isCustomGetterSetter() const;
bool isObject() const;
bool inherits(const ClassInfo*) const;
return isCell() && asCell()->isGetterSetter();
}
+inline bool JSValue::isCustomGetterSetter() const
+{
+ return isCell() && asCell()->isCustomGetterSetter();
+}
+
inline bool JSValue::isObject() const
{
return isCell() && asCell()->isObject();
bool isString() const;
bool isObject() const;
bool isGetterSetter() const;
+ bool isCustomGetterSetter() const;
bool isProxy() const;
bool inherits(const ClassInfo*) const;
bool isAPIValueWrapper() 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;
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
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);
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:
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());
#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
#include "CopyVisitorInlines.h"
+#include "CustomGetterSetter.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "Executable.h"
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.
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);
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();
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));
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;
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.
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);
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);
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;
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);
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;
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.
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));
}
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));
}
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));
}
{
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());
#include "JSPromiseConstructor.h"
#include "JSPromiseDeferred.h"
#include "NumberObject.h"
+#include "StructureInlines.h"
namespace JSC {
// The CompoundType value must come before any JSType that may have children.
CompoundType,
GetterSetterType,
+ CustomGetterSetterType,
APIValueWrapperType,
EvalExecutableType,
#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"
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
#include "JSGlobalObject.h"
#include "JSMap.h"
#include "MapPrototype.h"
+#include "StructureInlines.h"
namespace JSC {
#include "JSGlobalObject.h"
#include "JSMapIterator.h"
#include "MapIteratorPrototype.h"
+#include "StructureInlines.h"
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;
#include "JSSet.h"
#include "MapData.h"
#include "SetPrototype.h"
+#include "StructureInlines.h"
namespace JSC {
#include "JSGlobalObject.h"
#include "JSSetIterator.h"
#include "SetIteratorPrototype.h"
+#include "StructureInlines.h"
namespace JSC {
, 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)
, 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)
, 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)
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();
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);
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*);
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;
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);
if (!is__proto__)
m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
}
+
+ bool hasCustomGetterSetterProperties() const { return m_hasCustomGetterSetterProperties; }
+ void setHasCustomGetterSetterProperties() { m_hasCustomGetterSetterProperties = true; }
+
void setContainsReadOnlyProperties()
{
m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
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;
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;
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
#include "CodeCache.h"
#include "CommonIdentifiers.h"
#include "CommonSlowPaths.h"
+#include "CustomGetterSetter.h"
#include "DFGLongLivedState.h"
#include "DFGWorklist.h"
#include "DebuggerActivation.h"
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()));
Strong<Structure> notAnObjectStructure;
Strong<Structure> propertyNameIteratorStructure;
Strong<Structure> getterSetterStructure;
+ Strong<Structure> customGetterSetterStructure;
Strong<Structure> apiWrapperStructure;
Strong<Structure> JSScopeStructure;
Strong<Structure> executableStructure;
#include "JSCellInlines.h"
#include "JSGlobalObject.h"
#include "JSWeakMap.h"
+#include "StructureInlines.h"
#include "WeakMapPrototype.h"
namespace JSC {
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()
{
+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
my $noStaticTables = shift;
my $className = shift;
if ($noStaticTables) {
- return "get${className}PrototypeTable(exec->vm())";
+ return "get${className}PrototypeTable(vm)";
} else {
return "${className}PrototypeTable";
}
my $interface = shift;
my $attribute = shift;
my $interfaceName = $interface->name;
- return 1 if ($attribute->signature->name =~ "touch");
return 0;
}
|| $interface->extendedAttributes->{"CustomGetOwnPropertySlot"}
|| $hasImpureNamedGetter;
- return $numInstanceAttributes > 0 || !$interface->extendedAttributes->{"NoInterfaceObject"} || $hasComplexGetter;
+ return $numInstanceAttributes > 0 || $hasComplexGetter;
}
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;
}
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"}) {