Commit 3412bb43 authored by weinig@apple.com's avatar weinig@apple.com

JavaScriptCore:

2008-09-01  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Darin Adler.

        First cut at inline caching for access to vanilla JavaScript properties.
        
        SunSpider says 4% faster. Tests heavy on dictionary-like access have
        regressed a bit -- we have a lot of room to improve in this area,
        but this patch is over-ripe as-is.
        
        JSCells now have a StructureID that uniquely identifies their layout,
        and holds their prototype.
        
        JSValue::put takes a PropertySlot& argument, so it can fill in details
        about where it put a value, for the sake of caching.

        * VM/CodeGenerator.cpp:
        (KJS::CodeGenerator::CodeGenerator): Avoid calling removeDirect if we
        can, since it disables inline caching in the global object. This can
        probably improve in the future.

        * kjs/JSGlobalObject.cpp: Nixed reset(), since it complicates caching, and
        wasn't really necessary.

        * kjs/JSObject.cpp: Tweaked getter / setter behavior not to rely on the
        IsGetterSetter flag, since the flag was buggy. This is necessary in order
        to avoid accidentally accessing a getter / setter as a normal property.
        
        Also changed getter / setter creation to honor ReadOnly, matching Mozilla.
        
        * kjs/PropertyMap.cpp: Nixed clear(), since it complicates caching and
        isn't necessary.

        * kjs/Shell.cpp: Moved SamplingTool dumping outside the loop. This allows
        you to aggregate sampling of multiple files (or the same file repeatedly),
        which helped me track down regressions.

        * kjs/ustring.h: Moved IdentifierRepHash here to share it.

WebCore:

2008-09-01  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Darin Adler.

        First cut at inline caching for access to vanilla JavaScript properties.

        Updated for JavaScriptCore changes. Mostly mechanical addition of StructureIDs
        to WebCore classes, and PutPropertySlot& arguments to put functions.

        (WebCore::JSCSSStyleDeclaration::customPut): Be sure to play nice with
        inline caching for global properties, so global assignment can be optimized.

        * ForwardingHeaders/kjs/StructureID.h: Added.
        * bindings/js/JSDOMBinding.h:
        (WebCore::DOMObject::DOMObject):
        * bindings/js/JSDOMWindowBase.cpp:
        (WebCore::JSDOMWindowBase::put):
        * bindings/js/JSDOMWindowBase.h:
        * bindings/js/JSDOMWindowCustom.h:
        (WebCore::JSDOMWindow::customPut):
        * bindings/js/JSDOMWindowShell.cpp:
        (WebCore::JSDOMWindowShell::JSDOMWindowShell):
        (WebCore::JSDOMWindowShell::put):
        * bindings/js/JSDOMWindowShell.h:
        * bindings/js/JSEventTargetBase.h:
        (WebCore::JSEventTargetBase::put):
        * bindings/js/JSEventTargetNode.h:
        (WebCore::JSEventTargetNode::put):
        * bindings/js/JSHTMLAppletElementCustom.cpp:
        (WebCore::JSHTMLAppletElement::customPut):
        * bindings/js/JSHTMLEmbedElementCustom.cpp:
        (WebCore::JSHTMLEmbedElement::customPut):
        * bindings/js/JSHTMLInputElementBase.cpp:
        (WebCore::JSHTMLInputElementBase::put):
        * bindings/js/JSHTMLInputElementBase.h:
        * bindings/js/JSHTMLObjectElementCustom.cpp:
        (WebCore::JSHTMLObjectElement::customPut):
        * bindings/js/JSHistoryCustom.cpp:
        (WebCore::JSHistory::customPut):
        * bindings/js/JSInspectedObjectWrapper.cpp:
        (WebCore::JSInspectedObjectWrapper::wrap):
        (WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
        * bindings/js/JSInspectedObjectWrapper.h:
        * bindings/js/JSInspectorCallbackWrapper.cpp:
        (WebCore::JSInspectorCallbackWrapper::wrap):
        (WebCore::JSInspectorCallbackWrapper::JSInspectorCallbackWrapper):
        * bindings/js/JSInspectorCallbackWrapper.h:
        * bindings/js/JSLocationCustom.cpp:
        (WebCore::JSLocation::customPut):
        * bindings/js/JSPluginElementFunctions.cpp:
        (WebCore::runtimeObjectCustomPut):
        * bindings/js/JSPluginElementFunctions.h:
        * bindings/js/JSQuarantinedObjectWrapper.cpp:
        (WebCore::JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper):
        (WebCore::JSQuarantinedObjectWrapper::put):
        * bindings/js/JSQuarantinedObjectWrapper.h:
        * bindings/js/JSStorageCustom.cpp:
        (WebCore::JSStorage::customPut):
        * bindings/objc/WebScriptObject.mm:
        (-[WebScriptObject setValue:forKey:]):
        * bindings/scripts/CodeGeneratorJS.pm:
        * bridge/NP_jsobject.cpp:
        (_NPN_SetProperty):
        * bridge/jni/jni_jsobject.mm:
        (JavaJSObject::setMember):
        * bridge/objc/objc_class.mm:
        (KJS::Bindings::ObjcClass::fallbackObject):
        * bridge/objc/objc_runtime.h:
        * bridge/objc/objc_runtime.mm:
        (ObjcFallbackObjectImp::ObjcFallbackObjectImp):
        (ObjcFallbackObjectImp::put):
        * bridge/runtime.cpp:
        (KJS::Bindings::Instance::createRuntimeObject):
        * bridge/runtime_array.cpp:
        (RuntimeArray::put):
        * bridge/runtime_array.h:
        * bridge/runtime_object.cpp:
        (RuntimeObjectImp::RuntimeObjectImp):
        (RuntimeObjectImp::put):
        * bridge/runtime_object.h:

LayoutTests:

2008-09-01  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Darin Adler.

        First cut at inline caching for access to vanilla JavaScript properties.
        
        Tests for things I broke along the way.
        
        * fast/dom/getter-on-window-object2-expected.txt:
        * fast/js/pic: Added.
        * fast/js/pic/cached-deleted-properties-expected.txt: Added.
        * fast/js/pic/cached-deleted-properties.html: Added.
        * fast/js/pic/cached-getter-dictionary-and-proto-expected.txt: Added.
        * fast/js/pic/cached-getter-dictionary-and-proto.html: Added.
        * fast/js/pic/cached-getter-setter-expected.txt: Added.
        * fast/js/pic/cached-getter-setter.html: Added.
        * fast/js/pic/cached-prototype-setter-expected.txt: Added.
        * fast/js/pic/cached-prototype-setter.html: Added.
        * fast/js/pic/cached-single-entry-transition-expected.txt: Added.
        * fast/js/pic/cached-single-entry-transition.html: Added.
        * fast/js/pic/get-empty-string-expected.txt: Added.
        * fast/js/pic/get-empty-string.html: Added.
        * fast/js/pic/get-set-proxy-object-expected.txt: Added.
        * fast/js/pic/get-set-proxy-object.html: Added.
        * fast/js/pic/rehash-poisons-structure-expected.txt: Added.
        * fast/js/pic/rehash-poisons-structure.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36016 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 6976c61b
......@@ -36,8 +36,8 @@ namespace KJS {
template <class Base>
class JSCallbackObject : public Base {
public:
JSCallbackObject(ExecState*, JSClassRef, JSValue* prototype, void* data);
JSCallbackObject(JSClassRef);
JSCallbackObject(ExecState*, JSClassRef, JSObject* prototype, void* data);
JSCallbackObject(JSGlobalData*, JSClassRef);
virtual ~JSCallbackObject();
void setPrivate(void* data);
......@@ -54,8 +54,7 @@ private:
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned, PropertySlot&);
virtual void put(ExecState*, const Identifier&, JSValue*);
virtual void put(ExecState*, unsigned, JSValue*);
virtual void put(ExecState*, const Identifier&, JSValue*, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier&);
virtual bool deleteProperty(ExecState*, unsigned);
......
......@@ -40,7 +40,7 @@
namespace KJS {
template <class Base>
JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSValue* prototype, void* data)
JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSObject* prototype, void* data)
: Base(prototype)
, m_callbackObjectData(new JSCallbackObjectData(data, jsClass))
{
......@@ -50,8 +50,9 @@ JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JS
// Global object constructor.
// FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one.
template <class Base>
JSCallbackObject<Base>::JSCallbackObject(JSClassRef jsClass)
: m_callbackObjectData(new JSCallbackObjectData(0, jsClass))
JSCallbackObject<Base>::JSCallbackObject(JSGlobalData* globalData, JSClassRef jsClass)
: Base(globalData)
, m_callbackObjectData(new JSCallbackObjectData(0, jsClass))
{
ASSERT(Base::isGlobalObject());
init(static_cast<JSGlobalObject*>(this)->globalExec());
......@@ -152,7 +153,7 @@ bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, unsigned proper
}
template <class Base>
void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)
{
JSContextRef ctx = toRef(exec);
JSObjectRef thisRef = toRef(this);
......@@ -193,13 +194,7 @@ void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName
}
}
return Base::put(exec, propertyName, value);
}
template <class Base>
void JSCallbackObject<Base>::put(ExecState* exec, unsigned propertyName, JSValue* value)
{
return put(exec, Identifier::from(exec, propertyName), value);
return Base::put(exec, propertyName, value, slot);
}
template <class Base>
......
......@@ -67,16 +67,16 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass
RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::create();
if (!globalObjectClass) {
JSGlobalObject* globalObject = new (globalData.get()) JSGlobalObject;
JSGlobalObject* globalObject = new (globalData.get()) JSGlobalObject(globalData.get());
return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec()));
}
JSGlobalObject* globalObject = new (globalData.get()) JSCallbackObject<JSGlobalObject>(globalObjectClass);
JSGlobalObject* globalObject = new (globalData.get()) JSCallbackObject<JSGlobalObject>(globalData.get(), globalObjectClass);
ExecState* exec = globalObject->globalExec();
JSValue* prototype = globalObjectClass->prototype(exec);
if (!prototype)
prototype = jsNull();
globalObject->reset(prototype);
globalObject->resetPrototype(prototype);
return JSGlobalContextRetain(toGlobalRef(exec));
}
......
......@@ -74,7 +74,7 @@ JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
if (!jsClass)
return toRef(new (exec) JSObject(exec->lexicalGlobalObject()->objectPrototype())); // slightly more efficient
JSValue* jsPrototype = jsClass->prototype(exec);
JSObject* jsPrototype = jsClass->prototype(exec);
if (!jsPrototype)
jsPrototype = exec->lexicalGlobalObject()->objectPrototype();
......@@ -141,7 +141,7 @@ void JSObjectSetPrototype(JSContextRef, JSObjectRef object, JSValueRef value)
JSObject* jsObject = toJS(object);
JSValue* jsValue = toJS(value);
jsObject->setPrototype(jsValue);
jsObject->setPrototype(jsValue->isObject() ? jsValue : jsNull());
}
bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
......@@ -184,8 +184,10 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope
if (attributes && !jsObject->hasProperty(exec, name))
jsObject->putWithAttributes(exec, name, jsValue, attributes);
else
jsObject->put(exec, name, jsValue);
else {
PutPropertySlot slot;
jsObject->put(exec, name, jsValue, slot);
}
if (exec->hadException()) {
if (exception)
......
2008-09-01 Geoffrey Garen <ggaren@apple.com>
Reviewed by Darin Adler.
First cut at inline caching for access to vanilla JavaScript properties.
SunSpider says 4% faster. Tests heavy on dictionary-like access have
regressed a bit -- we have a lot of room to improve in this area,
but this patch is over-ripe as-is.
JSCells now have a StructureID that uniquely identifies their layout,
and holds their prototype.
JSValue::put takes a PropertySlot& argument, so it can fill in details
about where it put a value, for the sake of caching.
* VM/CodeGenerator.cpp:
(KJS::CodeGenerator::CodeGenerator): Avoid calling removeDirect if we
can, since it disables inline caching in the global object. This can
probably improve in the future.
* kjs/JSGlobalObject.cpp: Nixed reset(), since it complicates caching, and
wasn't really necessary.
* kjs/JSObject.cpp: Tweaked getter / setter behavior not to rely on the
IsGetterSetter flag, since the flag was buggy. This is necessary in order
to avoid accidentally accessing a getter / setter as a normal property.
Also changed getter / setter creation to honor ReadOnly, matching Mozilla.
* kjs/PropertyMap.cpp: Nixed clear(), since it complicates caching and
isn't necessary.
* kjs/Shell.cpp: Moved SamplingTool dumping outside the loop. This allows
you to aggregate sampling of multiple files (or the same file repeatedly),
which helped me track down regressions.
* kjs/ustring.h: Moved IdentifierRepHash here to share it.
2008-09-01 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
......
......@@ -105,8 +105,11 @@ __ZN3KJS11ProfileNode4sortEPFbRKN3WTF6RefPtrIS0_EES5_E
__ZN3KJS11ProgramNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm16EEEPNS6_INS5_6RefPtrINS_12FuncDeclNodeEEELm16EEEPNS_14SourceProviderEbbi
__ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierE
__ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierERb
__ZN3KJS11PropertyMap3putERKNS_10IdentifierEPNS_7JSValueEjb
__ZN3KJS11PropertyMap3putERKNS_10IdentifierEPNS_7JSValueEjbPNS_8JSObjectERNS_15PutPropertySlotE
__ZN3KJS11PropertyMapD1Ev
__ZN3KJS11StructureID21addPropertyTransitionEPS0_RKNS_10IdentifierE
__ZN3KJS11StructureID25changePrototypeTransitionEPS0_PNS_7JSValueE
__ZN3KJS11StructureIDD1Ev
__ZN3KJS12DateInstance4infoE
__ZN3KJS12JSGlobalData6createEv
__ZN3KJS12JSGlobalDataD1Ev
......@@ -119,7 +122,7 @@ __ZN3KJS12StringObject14toThisJSStringEPNS_9ExecStateE
__ZN3KJS12StringObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3KJS12StringObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3KJS12StringObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3KJS12StringObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueE
__ZN3KJS12StringObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueERNS_15PutPropertySlotE
__ZN3KJS12StringObject4infoE
__ZN3KJS12StringObjectC2EPNS_9ExecStateEPNS_8JSObjectERKNS_7UStringE
__ZN3KJS13CodeGenerator21setDumpsGeneratedCodeEb
......@@ -132,7 +135,7 @@ __ZN3KJS14JSGlobalObject14setTimeoutTimeEj
__ZN3KJS14JSGlobalObject16stopTimeoutCheckEv
__ZN3KJS14JSGlobalObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEj
__ZN3KJS14JSGlobalObject17startTimeoutCheckEv
__ZN3KJS14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueE
__ZN3KJS14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueERNS_15PutPropertySlotE
__ZN3KJS14JSGlobalObject4initEPNS_8JSObjectE
__ZN3KJS14JSGlobalObject4markEv
__ZN3KJS14JSGlobalObjectD2Ev
......@@ -178,7 +181,7 @@ __ZN3KJS6JSCell14toThisJSStringEPNS_9ExecStateE
__ZN3KJS6JSCell16getConstructDataERNS_13ConstructDataE
__ZN3KJS6JSCell18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3KJS6JSCell18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3KJS6JSCell3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueE
__ZN3KJS6JSCell3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueERNS_15PutPropertySlotE
__ZN3KJS6JSCell3putEPNS_9ExecStateEjPNS_7JSValueE
__ZN3KJS6JSCell9getObjectEv
__ZN3KJS6JSCellnwEmPNS_9ExecStateE
......@@ -219,14 +222,16 @@ __ZN3KJS8JSObject12lookupGetterEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS8JSObject12lookupSetterEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateEj
__ZN3KJS8JSObject14setStructureIDEN3WTF10PassRefPtrINS_11StructureIDEEE
__ZN3KJS8JSObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3KJS8JSObject17createInheritorIDEv
__ZN3KJS8JSObject17putDirectFunctionEPNS_9ExecStateEPNS_16InternalFunctionEj
__ZN3KJS8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEj
__ZN3KJS8JSObject17putWithAttributesEPNS_9ExecStateEjPNS_7JSValueEj
__ZN3KJS8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3KJS8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRPNS_7JSValueE
__ZN3KJS8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPPNS_7JSValueE
__ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueE
__ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueERNS_15PutPropertySlotE
__ZN3KJS8JSObject3putEPNS_9ExecStateEjPNS_7JSValueE
__ZN3KJS8JSObject4markEv
__ZN3KJS8Profiler13stopProfilingEPNS_9ExecStateERKNS_7UStringE
......@@ -234,6 +239,8 @@ __ZN3KJS8Profiler14startProfilingEPNS_9ExecStateERKNS_7UStringEPNS_14ProfilerCli
__ZN3KJS8Profiler21didFinishAllExecutionEPNS_9ExecStateE
__ZN3KJS8Profiler8profilerEv
__ZN3KJS8jsStringEPNS_9ExecStateERKNS_7UStringE
__ZN3KJS9CodeBlockD1Ev
__ZN3KJS9CodeBlockD2Ev
__ZN3KJS9constructEPNS_9ExecStateEPNS_7JSValueENS_13ConstructTypeERKNS_13ConstructDataERKNS_7ArgListE
__ZN3KJSeqERKNS_7UStringEPKc
__ZN3KJSgtERKNS_7UStringES2_
......@@ -325,6 +332,7 @@ __ZNK3KJS8JSObject8toObjectEPNS_9ExecStateE
__ZNK3KJS8JSObject8toStringEPNS_9ExecStateE
__ZNK3KJS8JSObject9classNameEv
__ZNK3KJS8JSObject9toBooleanEPNS_9ExecStateE
__ZNK3KJS9CodeBlock17derefStructureIDsEPNS_11InstructionE
__ZNK3KJS9HashTable11createTableEPNS_12JSGlobalDataE
__ZNK3WTF8Collator7collateEPKtmS2_m
__ZTVN3KJS12JSNumberCellE
......
......@@ -276,6 +276,8 @@
BCD2034A0E17135E002C7E82 /* DateConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD203460E17135E002C7E82 /* DateConstructor.h */; };
BCD2034C0E17135E002C7E82 /* DatePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD203480E17135E002C7E82 /* DatePrototype.h */; };
BCD203E80E1718F4002C7E82 /* DatePrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */; };
BCDE3AB80E6C82F5001453A7 /* StructureID.h in Headers */ = {isa = PBXBuildFile; fileRef = BCDE3AB10E6C82CF001453A7 /* StructureID.h */; settings = {ATTRIBUTES = (Private, ); }; };
BCDE3B430E6C832D001453A7 /* StructureID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCDE3AB00E6C82CF001453A7 /* StructureID.cpp */; };
BCF605140E203EF800B9A64D /* ArgList.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF605120E203EF800B9A64D /* ArgList.h */; settings = {ATTRIBUTES = (Private, ); }; };
C0A272630E50A06300E96E15 /* NotFound.h in Headers */ = {isa = PBXBuildFile; fileRef = C0A2723F0E509F1E00E96E15 /* NotFound.h */; settings = {ATTRIBUTES = (Private, ); }; };
E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -708,6 +710,8 @@
BCD203470E17135E002C7E82 /* DatePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatePrototype.cpp; sourceTree = "<group>"; };
BCD203480E17135E002C7E82 /* DatePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatePrototype.h; sourceTree = "<group>"; };
BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatePrototype.lut.h; sourceTree = "<group>"; };
BCDE3AB00E6C82CF001453A7 /* StructureID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureID.cpp; sourceTree = "<group>"; };
BCDE3AB10E6C82CF001453A7 /* StructureID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureID.h; sourceTree = "<group>"; };
BCF605110E203EF800B9A64D /* ArgList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArgList.cpp; sourceTree = "<group>"; };
BCF605120E203EF800B9A64D /* ArgList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgList.h; sourceTree = "<group>"; };
BCF6553B0A2048DE0038A194 /* MathExtras.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MathExtras.h; sourceTree = "<group>"; };
......@@ -1133,10 +1137,10 @@
BCD203460E17135E002C7E82 /* DateConstructor.h */,
BC1166000E1997B1008066DD /* DateInstance.cpp */,
BC1166010E1997B1008066DD /* DateInstance.h */,
BCD203470E17135E002C7E82 /* DatePrototype.cpp */,
BCD203480E17135E002C7E82 /* DatePrototype.h */,
D21202280AD4310C00ED79B6 /* DateMath.cpp */,
D21202290AD4310C00ED79B6 /* DateMath.h */,
BCD203470E17135E002C7E82 /* DatePrototype.cpp */,
BCD203480E17135E002C7E82 /* DatePrototype.h */,
651F6412039D5B5F0078395C /* dtoa.cpp */,
651F6413039D5B5F0078395C /* dtoa.h */,
BC337BEA0E1B00CB0076918A /* Error.cpp */,
......@@ -1153,11 +1157,11 @@
BC2680C10E16D4E900A06E92 /* FunctionConstructor.h */,
F692A85C0255597D01FF60F7 /* FunctionPrototype.cpp */,
F692A85D0255597D01FF60F7 /* FunctionPrototype.h */,
933A3499038AE7C6008635CE /* grammar.y */,
BC02E9B80E184545000F9297 /* GetterSetter.cpp */,
BC337BDE0E1AF0B80076918A /* GetterSetter.h */,
BC257DED0E1F52ED0016B6C9 /* GlobalEvalFunction.cpp */,
BC257DEE0E1F52ED0016B6C9 /* GlobalEvalFunction.h */,
933A3499038AE7C6008635CE /* grammar.y */,
933A349D038AE80F008635CE /* identifier.cpp */,
933A349A038AE7C6008635CE /* identifier.h */,
BC257DE90E1F52BA0016B6C9 /* IndexToNameMap.cpp */,
......@@ -1192,8 +1196,8 @@
BC7F8FB80E19D1C3008632C0 /* JSNumberCell.h */,
BC22A3980E16E14800AF21C8 /* JSObject.cpp */,
BC22A3990E16E14800AF21C8 /* JSObject.h */,
A7E42C180E3938830065A544 /* JSStaticScopeObject.h */,
A7E42C190E3938830065A544 /* JSStaticScopeObject.cpp */,
A7E42C180E3938830065A544 /* JSStaticScopeObject.h */,
BC02E9B60E1842FA000F9297 /* JSString.cpp */,
F692A8620255597D01FF60F7 /* JSString.h */,
14ABB454099C2A0F00E2A24F /* JSType.h */,
......@@ -1232,9 +1236,9 @@
65400C100A69BAF200509887 /* PropertyNameArray.h */,
65621E6B089E859700760F35 /* PropertySlot.cpp */,
65621E6C089E859700760F35 /* PropertySlot.h */,
65C02FBB0637462A003E7EE6 /* protect.h */,
BC257DF10E1F53740016B6C9 /* PrototypeFunction.cpp */,
BC257DF20E1F53740016B6C9 /* PrototypeFunction.h */,
65C02FBB0637462A003E7EE6 /* protect.h */,
F692A87D0255597D01FF60F7 /* regexp.cpp */,
F692A87E0255597D01FF60F7 /* regexp.h */,
BCD202BD0E1706A7002C7E82 /* RegExpConstructor.cpp */,
......@@ -1257,6 +1261,8 @@
BC18C3C40E16EE3300B34460 /* StringObjectThatMasqueradesAsUndefined.h */,
BC18C3C50E16EE3300B34460 /* StringPrototype.cpp */,
BC18C3C60E16EE3300B34460 /* StringPrototype.h */,
BCDE3AB00E6C82CF001453A7 /* StructureID.cpp */,
BCDE3AB10E6C82CF001453A7 /* StructureID.h */,
14A396A60CD2933100B5B4FF /* SymbolTable.h */,
5D53726D0E1C546B0021E549 /* Tracing.d */,
5D53726E0E1C54880021E549 /* Tracing.h */,
......@@ -1538,6 +1544,7 @@
E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
9534AAFB0E5B7A9600B8A45B /* JSProfilerPrivate.h in Headers */,
933040040E6A749400786E6A /* SmallStrings.h in Headers */,
BCDE3AB80E6C82F5001453A7 /* StructureID.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -1845,6 +1852,7 @@
E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */,
95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */,
9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */,
BCDE3B430E6C832D001453A7 /* StructureID.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -37,7 +37,7 @@
namespace KJS {
#if !defined(NDEBUG) || ENABLE_SAMPLING_TOOL
#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
static UString escapeQuotes(const UString& str)
{
......@@ -65,6 +65,9 @@ static CString registerName(int r)
{
if (r < 0)
return (UString("lr") + UString::from(-r)).UTF8String();
if (r == missingThisObjectMarker())
return "<null>";
return (UString("tr") + UString::from(r)).UTF8String();
}
......@@ -97,6 +100,13 @@ static CString regexpName(int re, RegExp* regexp)
return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
}
static UString pointerToSourceString(void* p)
{
char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
snprintf(buffer, sizeof(buffer), "%p", p);
return buffer;
}
NEVER_INLINE static const char* debugHookName(int debugHookID)
{
switch (static_cast<DebugHookID>(debugHookID)) {
......@@ -146,6 +156,62 @@ static void printConditionalJump(const Vector<Instruction>::const_iterator& begi
printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, jumpTarget(begin, it, offset));
}
static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
{
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int id0 = (++it)->u.operand;
printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
it += 4;
}
static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
{
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
it += 2;
}
void CodeBlock::printStructureID(const char* name, const Instruction* vPC, int operand) const
{
printf(" [%4d] %s: %s\n", vPC - instructions.begin(), name, pointerToSourceString(vPC[operand].u.structureID).UTF8String().c_str());
}
void CodeBlock::printStructureIDs(const Instruction* vPC) const
{
Machine* machine = globalData->machine;
if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id)) {
printStructureID("get_by_id", vPC, 4);
return;
}
if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
printStructureID("get_by_id_self", vPC, 4);
return;
}
if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
printf(" [%4d] %s: %s, %s\n", vPC - instructions.begin(), "get_by_id_proto", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureID).UTF8String().c_str());
return;
}
if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
printf(" [%4d] %s: %s, %s\n", vPC - instructions.begin(), "get_by_id_chain", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureIDChain).UTF8String().c_str());
return;
}
if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id)) {
printStructureID("put_by_id", vPC, 4);
return;
}
if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
printStructureID("put_by_id_replace", vPC, 4);
return;
}
// These instructions doesn't ref StructureIDs.
ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic));
}
void CodeBlock::dump(ExecState* exec) const
{
Vector<Instruction>::const_iterator begin = instructions.begin();
......@@ -200,56 +266,69 @@ void CodeBlock::dump(ExecState* exec) const
} while (i < regexps.size());
}
if (structureIDInstructions.size()) {
printf("\nStructureIDs:\n");
size_t i = 0;
do {
printStructureIDs(&instructions[structureIDInstructions[i]]);
++i;
} while (i < structureIDInstructions.size());
}
if (exceptionHandlers.size()) {
printf("\nException Handlers:\n");
unsigned i = 0;
do {
printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i+1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
++i;
} while (i < exceptionHandlers.size());
}
if (immediateSwitchJumpTables.size()) {
printf("immediate switch jump tables:\n");
printf("Immediate Switch Jump Tables:\n");
unsigned i = 0;
do {
printf("\t{\n");
printf(" %1d = {\n", i);
int entry = 0;
Vector<int32_t>::const_iterator end = immediateSwitchJumpTables[i].branchOffsets.end();
for (Vector<int32_t>::const_iterator iter = immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry)
if (*iter)
printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
printf("\t}\n");
for (Vector<int32_t>::const_iterator iter = immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
if (!*iter)
continue;
printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
}
printf(" }\n");
++i;
} while (i < immediateSwitchJumpTables.size());
}
if (characterSwitchJumpTables.size()) {
printf("\ncharacter switch jump tables:\n");
printf("\nCharacter Switch Jump Tables:\n");
unsigned i = 0;
do {
printf("\t{\n");
printf(" %1d = {\n", i);
int entry = 0;
Vector<int32_t>::const_iterator end = characterSwitchJumpTables[i].branchOffsets.end();
for (Vector<int32_t>::const_iterator iter = characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
if (!*iter)
continue;
ASSERT(!((i + characterSwitchJumpTables[i].min) & ~0xFFFF));
UChar ch = static_cast<UChar>(i + characterSwitchJumpTables[i].min);
UChar ch = static_cast<UChar>(entry + characterSwitchJumpTables[i].min);
printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
}
printf("\t}\n");
printf(" }\n");
++i;
} while (i < characterSwitchJumpTables.size());
}
if (stringSwitchJumpTables.size()) {
printf("\nstring switch jump tables:\n");
printf("\nString Switch Jump Tables:\n");
unsigned i = 0;
do {
printf("\t{\n");
printf(" %1d = {\n", i);
StringJumpTable::const_iterator end = stringSwitchJumpTables[i].end();
for (StringJumpTable::const_iterator iter = stringSwitchJumpTables[i].begin(); iter != end; ++iter)
printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second);
printf("\t}\n");
printf(" }\n");
++i;
} while (i < stringSwitchJumpTables.size());
}
......@@ -422,14 +501,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int index = (++it)->u.operand;
int skipLevels = (++it)->u.operand;
printf("[%4d] get_scoped_var\t\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
break;
}
case op_put_scoped_var: {
int index = (++it)->u.operand;
int skipLevels = (++it)->u.operand;
int r0 = (++it)->u.operand;
printf("[%4d] put_scoped_var\t\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
break;
}
case op_resolve_base: {
......@@ -453,17 +532,35 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
break;
}
case op_get_by_id: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int id0 = (++it)->u.operand;
printf("[%4d] get_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
printGetByIdOp(location, it, identifiers, "get_by_id");
break;
}
case op_get_by_id_self: {
printGetByIdOp(location, it, identifiers, "get_by_id_self");
break;
}
case op_get_by_id_proto: {
printGetByIdOp(location, it, identifiers, "get_by_id_proto");
break;
}
case op_get_by_id_chain: {
printGetByIdOp(location, it, identifiers, "get_by_id_chain");
break;
}
case op_get_by_id_generic: {
printGetByIdOp(location, it, identifiers, "get_by_id_generic");
break;
}
case op_put_by_id: {
int r0 = (++it)->u.operand;
int id0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
printf("[%4d] put_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
printPutByIdOp(location, it, identifiers, "put_by_id");
break;
}
case op_put_by_id_replace: {
printPutByIdOp(location, it, identifiers, "put_by_id_replace");
break;
}
case op_put_by_id_generic: {
printPutByIdOp(location, it, identifiers, "put_by_id_generic");
break;
}
case op_put_getter: {
......@@ -548,7 +645,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;