+2012-06-28 Kentaro Hara <haraken@chromium.org>
+
+ [V8] Optimize Integer::New() by caching persistent handles for small integers
+ https://bugs.webkit.org/show_bug.cgi?id=90043
+
+ Reviewed by Adam Barth.
+
+ The patch improves performance of Dromaeo/dom-query.html by 3.6%,
+ and Bindings/scroll-top.html by 17.3%.
+
+ The performance results in my Chromium/Linux:
+
+ [Dromaeo/dom-query.html]
+ 796310.4 runs/s => 824745.4 runs/s (+3.6%)
+
+ [Bindings/scroll-top.html]
+ 204.68 runs/s => 240.15 runs/s (+17.3%)
+
+ This patch introduces V8BindingPerIsolateData::IntegerCache (just like
+ V8BindingPerIsolateData::StringCache) to cache persistent handles
+ for small integers.
+
+ No new tests. No change in behavior.
+
+ * bindings/v8/V8Binding.h: Implemented v8Integer() and v8UnsignedInteger(),
+ which returns cached persistent handles for integers smaller than 64.
+ (WebCore):
+ (IntegerCache):
+ (WebCore::IntegerCache::IntegerCache):
+ (WebCore::IntegerCache::v8Integer):
+ (WebCore::IntegerCache::v8UnsignedInteger):
+ (WebCore::V8BindingPerIsolateData::integerCache):
+ (V8BindingPerIsolateData):
+ (WebCore::v8Integer):
+ (WebCore::v8UnsignedInteger):
+ * bindings/v8/V8Binding.cpp:
+ (WebCore):
+ (WebCore::IntegerCache::createSmallIntegers):
+ * bindings/v8/WorkerScriptController.cpp:
+ (~WorkerScriptController): ~V8BindingPerIsolateData() should be called before
+ isolate->Exit(), since ~V8BindingPerIsolateData() calls V8 APIs that requires
+ the current isolate.
+
+ * bindings/scripts/CodeGeneratorV8.pm: Replaced Integer::New() and Integer::NewFromUnsigned()
+ with v8Integer() and v8UnsignedInteger().
+ (GenerateNormalAttrGetter):
+ (NativeToJSValue):
+
+ * bindings/scripts/test/V8/V8TestActiveDOMObject.cpp: Updated run-bindings-tests results.
+ (WebCore::TestActiveDOMObjectV8Internal::excitingAttrAttrGetter):
+ * bindings/scripts/test/V8/V8TestObj.cpp: Ditto.
+ (WebCore::TestObjV8Internal::readOnlyIntAttrAttrGetter):
+ (WebCore::TestObjV8Internal::shortAttrAttrGetter):
+ (WebCore::TestObjV8Internal::unsignedShortAttrAttrGetter):
+ (WebCore::TestObjV8Internal::intAttrAttrGetter):
+ (WebCore::TestObjV8Internal::reflectedIntegralAttrAttrGetter):
+ (WebCore::TestObjV8Internal::reflectedUnsignedIntegralAttrAttrGetter):
+ (WebCore::TestObjV8Internal::reflectedCustomIntegralAttrAttrGetter):
+ (WebCore::TestObjV8Internal::attrWithGetterExceptionAttrGetter):
+ (WebCore::TestObjV8Internal::attrWithSetterExceptionAttrGetter):
+ (WebCore::TestObjV8Internal::withScriptStateAttributeAttrGetter):
+ (WebCore::TestObjV8Internal::conditionalAttr1AttrGetter):
+ (WebCore::TestObjV8Internal::conditionalAttr2AttrGetter):
+ (WebCore::TestObjV8Internal::conditionalAttr3AttrGetter):
+ (WebCore::TestObjV8Internal::enabledAtRuntimeAttr1AttrGetter):
+ (WebCore::TestObjV8Internal::enabledAtRuntimeAttr2AttrGetter):
+ (WebCore::TestObjV8Internal::enabledAtContextAttr1AttrGetter):
+ (WebCore::TestObjV8Internal::enabledAtContextAttr2AttrGetter):
+ (WebCore::TestObjV8Internal::strawberryAttrGetter):
+ (WebCore::TestObjV8Internal::descriptionAttrGetter):
+ (WebCore::TestObjV8Internal::idAttrGetter):
+ (WebCore::TestObjV8Internal::intMethodCallback):
+ (WebCore::TestObjV8Internal::intMethodWithArgsCallback):
+ (WebCore::TestObjV8Internal::classMethodWithOptionalCallback):
+ * bindings/scripts/test/V8/V8TestSerializedScriptValueInterface.cpp: Ditto.
+ (WebCore::TestSerializedScriptValueInterfaceV8Internal::portsAttrGetter):
+
2012-06-28 Kent Tamura <tkent@chromium.org>
Classify form control states by their owner forms
{
INC_STATS("DOM.TestObj.readOnlyIntAttr._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->readOnlyIntAttr());
+ return v8Integer(imp->readOnlyIntAttr(), info.GetIsolate());
}
static v8::Handle<v8::Value> readOnlyStringAttrAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.shortAttr._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->shortAttr());
+ return v8Integer(imp->shortAttr(), info.GetIsolate());
}
static void shortAttrAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.unsignedShortAttr._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->unsignedShortAttr());
+ return v8Integer(imp->unsignedShortAttr(), info.GetIsolate());
}
static void unsignedShortAttrAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.intAttr._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->intAttr());
+ return v8Integer(imp->intAttr(), info.GetIsolate());
}
static void intAttrAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.reflectedIntegralAttr._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->getIntegralAttribute(WebCore::HTMLNames::reflectedintegralattrAttr));
+ return v8Integer(imp->getIntegralAttribute(WebCore::HTMLNames::reflectedintegralattrAttr), info.GetIsolate());
}
static void reflectedIntegralAttrAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.reflectedUnsignedIntegralAttr._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::NewFromUnsigned(std::max(0, imp->getIntegralAttribute(WebCore::HTMLNames::reflectedunsignedintegralattrAttr)));
+ return v8UnsignedInteger(std::max(0, imp->getIntegralAttribute(WebCore::HTMLNames::reflectedunsignedintegralattrAttr)), info.GetIsolate());
}
static void reflectedUnsignedIntegralAttrAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.reflectedCustomIntegralAttr._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->getIntegralAttribute(WebCore::HTMLNames::customContentIntegralAttrAttr));
+ return v8Integer(imp->getIntegralAttribute(WebCore::HTMLNames::customContentIntegralAttrAttr), info.GetIsolate());
}
static void reflectedCustomIntegralAttrAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
int v = imp->attrWithGetterException(ec);
if (UNLIKELY(ec))
return V8Proxy::setDOMException(ec, info.GetIsolate());
- return v8::Integer::New(v);
+ return v8Integer(v, info.GetIsolate());
}
static void attrWithGetterExceptionAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.attrWithSetterException._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->attrWithSetterException());
+ return v8Integer(imp->attrWithSetterException(), info.GetIsolate());
}
static void attrWithSetterExceptionAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
ScriptState* state = ScriptState::current();
if (!state)
return v8::Undefined();
- return v8::Integer::New(imp->withScriptStateAttribute(state));
+ return v8Integer(imp->withScriptStateAttribute(state), info.GetIsolate());
}
static void withScriptStateAttributeAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.conditionalAttr1._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->conditionalAttr1());
+ return v8Integer(imp->conditionalAttr1(), info.GetIsolate());
}
#endif // ENABLE(Condition1)
{
INC_STATS("DOM.TestObj.conditionalAttr2._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->conditionalAttr2());
+ return v8Integer(imp->conditionalAttr2(), info.GetIsolate());
}
#endif // ENABLE(Condition1) && ENABLE(Condition2)
{
INC_STATS("DOM.TestObj.conditionalAttr3._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->conditionalAttr3());
+ return v8Integer(imp->conditionalAttr3(), info.GetIsolate());
}
#endif // ENABLE(Condition1) || ENABLE(Condition2)
{
INC_STATS("DOM.TestObj.enabledAtRuntimeAttr1._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->enabledAtRuntimeAttr1());
+ return v8Integer(imp->enabledAtRuntimeAttr1(), info.GetIsolate());
}
static void enabledAtRuntimeAttr1AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.enabledAtRuntimeAttr2._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->enabledAtRuntimeAttr2());
+ return v8Integer(imp->enabledAtRuntimeAttr2(), info.GetIsolate());
}
static void enabledAtRuntimeAttr2AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.enabledAtContextAttr1._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->enabledAtContextAttr1());
+ return v8Integer(imp->enabledAtContextAttr1(), info.GetIsolate());
}
static void enabledAtContextAttr1AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.enabledAtContextAttr2._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->enabledAtContextAttr2());
+ return v8Integer(imp->enabledAtContextAttr2(), info.GetIsolate());
}
static void enabledAtContextAttr2AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.strawberry._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->blueberry());
+ return v8Integer(imp->blueberry(), info.GetIsolate());
}
static void strawberryAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.description._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->description());
+ return v8Integer(imp->description(), info.GetIsolate());
}
static v8::Handle<v8::Value> idAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.id._get");
TestObj* imp = V8TestObj::toNative(info.Holder());
- return v8::Integer::New(imp->id());
+ return v8Integer(imp->id(), info.GetIsolate());
}
static void idAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.TestObj.intMethod");
TestObj* imp = V8TestObj::toNative(args.Holder());
- return v8::Integer::New(imp->intMethod());
+ return v8Integer(imp->intMethod(), args.GetIsolate());
}
static v8::Handle<v8::Value> intMethodWithArgsCallback(const v8::Arguments& args)
EXCEPTION_BLOCK(int, intArg, toInt32(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)));
STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, strArg, MAYBE_MISSING_PARAMETER(args, 1, DefaultIsUndefined));
EXCEPTION_BLOCK(TestObj*, objArg, V8TestObj::HasInstance(MAYBE_MISSING_PARAMETER(args, 2, DefaultIsUndefined)) ? V8TestObj::toNative(v8::Handle<v8::Object>::Cast(MAYBE_MISSING_PARAMETER(args, 2, DefaultIsUndefined))) : 0);
- return v8::Integer::New(imp->intMethodWithArgs(intArg, strArg, objArg));
+ return v8Integer(imp->intMethodWithArgs(intArg, strArg, objArg), args.GetIsolate());
}
static v8::Handle<v8::Value> objMethodCallback(const v8::Arguments& args)
{
INC_STATS("DOM.TestObj.classMethodWithOptional");
if (args.Length() <= 0) {
- return v8::Integer::New(TestObj::classMethodWithOptional());
+ return v8Integer(TestObj::classMethodWithOptional(), args.GetIsolate());
}
EXCEPTION_BLOCK(int, arg, toInt32(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)));
- return v8::Integer::New(TestObj::classMethodWithOptional(arg));
+ return v8Integer(TestObj::classMethodWithOptional(arg), args.GetIsolate());
}
#if ENABLE(Condition1)
RefPtr<StringImpl> m_lastStringImpl;
};
+ const int numberOfCachedSmallIntegers = 64;
+
+ class IntegerCache {
+ public:
+ IntegerCache() : m_initialized(false) { };
+ ~IntegerCache();
+
+ v8::Handle<v8::Integer> v8Integer(int value)
+ {
+ if (!m_initialized)
+ createSmallIntegers();
+ if (0 <= value && value < numberOfCachedSmallIntegers)
+ return m_smallIntegers[value];
+ return v8::Integer::New(value);
+ }
+
+ v8::Handle<v8::Integer> v8UnsignedInteger(unsigned value)
+ {
+ if (!m_initialized)
+ createSmallIntegers();
+ if (value < static_cast<unsigned>(numberOfCachedSmallIntegers))
+ return m_smallIntegers[value];
+ return v8::Integer::NewFromUnsigned(value);
+ }
+
+ private:
+ void createSmallIntegers();
+
+ v8::Persistent<v8::Integer> m_smallIntegers[numberOfCachedSmallIntegers];
+ bool m_initialized;
+ };
+
class ScriptGCEventListener;
class GCEventData {
}
StringCache* stringCache() { return &m_stringCache; }
+ IntegerCache* integerCache() { return &m_integerCache; }
+
#if ENABLE(INSPECTOR)
void visitExternalStrings(ExternalStringVisitor*);
#endif
v8::Persistent<v8::FunctionTemplate> m_toStringTemplate;
v8::Persistent<v8::FunctionTemplate> m_lazyEventListenerToStringTemplate;
StringCache m_stringCache;
+ IntegerCache m_integerCache;
DOMDataList m_domDataList;
DOMDataStore* m_domDataStore;
return v8ExternalString(string, isolate);
}
+ inline v8::Handle<v8::Integer> v8Integer(int value, v8::Isolate* isolate = 0)
+ {
+ V8BindingPerIsolateData* data = V8BindingPerIsolateData::current(isolate);
+ return data->integerCache()->v8Integer(value);
+ }
+
+ inline v8::Handle<v8::Integer> v8UnsignedInteger(unsigned value, v8::Isolate* isolate = 0)
+ {
+ V8BindingPerIsolateData* data = V8BindingPerIsolateData::current(isolate);
+ return data->integerCache()->v8UnsignedInteger(value);
+ }
+
template<typename T>
v8::Handle<v8::Value> v8Array(const Vector<T>& iterator, v8::Isolate* isolate)
{