DFG should optimize ResolveGlobal
https://bugs.webkit.org/show_bug.cgi?id=89617

Reviewed by Oliver Hunt.
        
This adds inlining of ResolveGlobal accesses that are known monomorphic. It also
adds the specific function optimization to ResolveGlobal, when it is inlined. And,
it makes internal functions act like specific functions, since that will be the
most common use-case of this optimization.
        
This is only a slighy speed-up (sub 1%), since we don't yet do the obvious thing
with this optimization, which is to completely inline common "globally resolved"
function and constructor calls, like "new Array()".

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::globalResolveInfoForBytecodeOffset):
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::numberOfGlobalResolveInfos):
* bytecode/GlobalResolveInfo.h:
(JSC::getGlobalResolveInfoBytecodeOffset):
(JSC):
* bytecode/ResolveGlobalStatus.cpp: Added.
(JSC):
(JSC::computeForStructure):
(JSC::computeForLLInt):
(JSC::ResolveGlobalStatus::computeFor):
* bytecode/ResolveGlobalStatus.h: Added.
(JSC):
(ResolveGlobalStatus):
(JSC::ResolveGlobalStatus::ResolveGlobalStatus):
(JSC::ResolveGlobalStatus::state):
(JSC::ResolveGlobalStatus::isSet):
(JSC::ResolveGlobalStatus::operator!):
(JSC::ResolveGlobalStatus::isSimple):
(JSC::ResolveGlobalStatus::takesSlowPath):
(JSC::ResolveGlobalStatus::structure):
(JSC::ResolveGlobalStatus::offset):
(JSC::ResolveGlobalStatus::specificValue):
* dfg/DFGByteCodeParser.cpp:
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(DFG):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::parseBlock):
* runtime/JSObject.cpp:
(JSC::getCallableObjectSlow):
(JSC):
(JSC::JSObject::put):
(JSC::JSObject::putDirectVirtual):
(JSC::JSObject::putDirectAccessor):
* runtime/JSObject.h:
(JSC):
(JSC::getCallableObject):
(JSC::JSObject::putOwnDataProperty):
(JSC::JSObject::putDirect):
(JSC::JSObject::putDirectWithoutTransition):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@120897 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 45e19de..06139a4 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -54,6 +54,7 @@
     bytecode/PolymorphicPutByIdList.cpp
     bytecode/SpeculatedType.cpp
     bytecode/PutByIdStatus.cpp
+    bytecode/ResolveGlobalStatus.cpp
     bytecode/SamplingTool.cpp
     bytecode/StructureStubInfo.cpp
     bytecode/Watchpoint.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 273806a..97b53b7 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,70 @@
 2012-06-20  Filip Pizlo  <fpizlo@apple.com>
 
+        DFG should optimize ResolveGlobal
+        https://bugs.webkit.org/show_bug.cgi?id=89617
+
+        Reviewed by Oliver Hunt.
+        
+        This adds inlining of ResolveGlobal accesses that are known monomorphic. It also
+        adds the specific function optimization to ResolveGlobal, when it is inlined. And,
+        it makes internal functions act like specific functions, since that will be the
+        most common use-case of this optimization.
+        
+        This is only a slighy speed-up (sub 1%), since we don't yet do the obvious thing
+        with this optimization, which is to completely inline common "globally resolved"
+        function and constructor calls, like "new Array()".
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::globalResolveInfoForBytecodeOffset):
+        * bytecode/CodeBlock.h:
+        (CodeBlock):
+        (JSC::CodeBlock::numberOfGlobalResolveInfos):
+        * bytecode/GlobalResolveInfo.h:
+        (JSC::getGlobalResolveInfoBytecodeOffset):
+        (JSC):
+        * bytecode/ResolveGlobalStatus.cpp: Added.
+        (JSC):
+        (JSC::computeForStructure):
+        (JSC::computeForLLInt):
+        (JSC::ResolveGlobalStatus::computeFor):
+        * bytecode/ResolveGlobalStatus.h: Added.
+        (JSC):
+        (ResolveGlobalStatus):
+        (JSC::ResolveGlobalStatus::ResolveGlobalStatus):
+        (JSC::ResolveGlobalStatus::state):
+        (JSC::ResolveGlobalStatus::isSet):
+        (JSC::ResolveGlobalStatus::operator!):
+        (JSC::ResolveGlobalStatus::isSimple):
+        (JSC::ResolveGlobalStatus::takesSlowPath):
+        (JSC::ResolveGlobalStatus::structure):
+        (JSC::ResolveGlobalStatus::offset):
+        (JSC::ResolveGlobalStatus::specificValue):
+        * dfg/DFGByteCodeParser.cpp:
+        (ByteCodeParser):
+        (JSC::DFG::ByteCodeParser::handleGetByOffset):
+        (DFG):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * runtime/JSObject.cpp:
+        (JSC::getCallableObjectSlow):
+        (JSC):
+        (JSC::JSObject::put):
+        (JSC::JSObject::putDirectVirtual):
+        (JSC::JSObject::putDirectAccessor):
+        * runtime/JSObject.h:
+        (JSC):
+        (JSC::getCallableObject):
+        (JSC::JSObject::putOwnDataProperty):
+        (JSC::JSObject::putDirect):
+        (JSC::JSObject::putDirectWithoutTransition):
+
+2012-06-20  Filip Pizlo  <fpizlo@apple.com>
+
         Functions on global objects should be specializable
         https://bugs.webkit.org/show_bug.cgi?id=89615
 
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index 5fb73ac..84d6e60 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -126,6 +126,8 @@
 	Source/JavaScriptCore/bytecode/PutByIdStatus.cpp \
 	Source/JavaScriptCore/bytecode/PutByIdStatus.h \
 	Source/JavaScriptCore/bytecode/PutKind.h \
+	Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp \
+	Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h \
 	Source/JavaScriptCore/bytecode/SamplingTool.cpp \
 	Source/JavaScriptCore/bytecode/SamplingTool.h \
 	Source/JavaScriptCore/bytecode/StructureSet.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
index 365038c..c48ef49 100755
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
@@ -189,6 +189,7 @@
     ?get@Structure@JSC@@QAEIAAVJSGlobalData@2@VPropertyName@2@AAIAAPAVJSCell@2@@Z
     ?getCalculatedDisplayName@JSC@@YA?AVUString@1@PAVExecState@1@PAVJSObject@1@@Z
     ?getCallData@JSCell@JSC@@SA?AW4CallType@2@PAV12@AATCallData@2@@Z
+    ?getCallableObjectSlow@JSC@@YAPAVJSCell@1@PAV21@@Z
     ?getConstructData@JSCell@JSC@@SA?AW4ConstructType@2@PAV12@AATConstructData@2@@Z
     ?getCurrentLocalTime@WTF@@YAXPAUtm@@@Z
     ?getObject@JSCell@JSC@@QAEPAVJSObject@2@XZ
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index ecddc2d..a64a106 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -211,6 +211,8 @@
 		0FF4275715914A20004CB9FF /* LinkBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4275615914A20004CB9FF /* LinkBuffer.cpp */; };
 		0FF427641591A1CC004CB9FF /* DFGDisassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */; };
 		0FF427651591A1CE004CB9FF /* DFGDisassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF427621591A1C9004CB9FF /* DFGDisassembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		0FF42771159275D5004CB9FF /* ResolveGlobalStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4276E159275D2004CB9FF /* ResolveGlobalStatus.cpp */; };
+		0FF42772159275D8004CB9FF /* ResolveGlobalStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4276F159275D2004CB9FF /* ResolveGlobalStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0FF922D414F46B410041A24E /* LLIntOffsetsExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */; };
 		0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */; };
 		0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -933,6 +935,8 @@
 		0FF4275615914A20004CB9FF /* LinkBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinkBuffer.cpp; sourceTree = "<group>"; };
 		0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDisassembler.cpp; path = dfg/DFGDisassembler.cpp; sourceTree = "<group>"; };
 		0FF427621591A1C9004CB9FF /* DFGDisassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDisassembler.h; path = dfg/DFGDisassembler.h; sourceTree = "<group>"; };
+		0FF4276E159275D2004CB9FF /* ResolveGlobalStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResolveGlobalStatus.cpp; sourceTree = "<group>"; };
+		0FF4276F159275D2004CB9FF /* ResolveGlobalStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResolveGlobalStatus.h; sourceTree = "<group>"; };
 		0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; };
 		0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFAPhase.cpp; path = dfg/DFGCFAPhase.cpp; sourceTree = "<group>"; };
 		0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFAPhase.h; path = dfg/DFGCFAPhase.h; sourceTree = "<group>"; };
@@ -2347,6 +2351,8 @@
 				0F93329814CA7DC10085F3C6 /* MethodCallLinkStatus.h */,
 				0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
 				0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
+				0FF4276E159275D2004CB9FF /* ResolveGlobalStatus.cpp */,
+				0FF4276F159275D2004CB9FF /* ResolveGlobalStatus.h */,
 				0F93329B14CA7DC10085F3C6 /* StructureSet.h */,
 				0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */,
 				0F0B83B614BCF8DF00885B4F /* GlobalResolveInfo.h */,
@@ -2766,6 +2772,7 @@
 				0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */,
 				0FF4274B158EBE91004CB9FF /* udis86.h in Headers */,
 				0FF427651591A1CE004CB9FF /* DFGDisassembler.h in Headers */,
+				0FF42772159275D8004CB9FF /* ResolveGlobalStatus.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3353,6 +3360,7 @@
 				0FF4275715914A20004CB9FF /* LinkBuffer.cpp in Sources */,
 				C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */,
 				0FF427641591A1CC004CB9FF /* DFGDisassembler.cpp in Sources */,
+				0FF42771159275D5004CB9FF /* ResolveGlobalStatus.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index a811d07..2f47922 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -64,6 +64,7 @@
     bytecode/Opcode.cpp \
     bytecode/PolymorphicPutByIdList.cpp \
     bytecode/PutByIdStatus.cpp \
+    bytecode/ResolveGlobalStatus.cpp \
     bytecode/SamplingTool.cpp \
     bytecode/SpeculatedType.cpp \
     bytecode/StructureStubInfo.cpp \
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 60596d1..33f01ac 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -2258,6 +2258,10 @@
         return false;
     return true;
 }
+GlobalResolveInfo& CodeBlock::globalResolveInfoForBytecodeOffset(unsigned bytecodeOffset)
+{
+    return *(binarySearch<GlobalResolveInfo, unsigned, getGlobalResolveInfoBytecodeOffset>(m_globalResolveInfos.begin(), m_globalResolveInfos.size(), bytecodeOffset));
+}
 #endif
 
 void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index 573d422..fa3e280 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -553,6 +553,8 @@
         }
         GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; }
         bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset);
+        GlobalResolveInfo& globalResolveInfoForBytecodeOffset(unsigned bytecodeOffset);
+        unsigned numberOfGlobalResolveInfos() { return m_globalResolveInfos.size(); }
 
         void setNumberOfCallLinkInfos(size_t size) { m_callLinkInfos.grow(size); }
         size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); }
diff --git a/Source/JavaScriptCore/bytecode/GlobalResolveInfo.h b/Source/JavaScriptCore/bytecode/GlobalResolveInfo.h
index 5576cfa..0528638 100644
--- a/Source/JavaScriptCore/bytecode/GlobalResolveInfo.h
+++ b/Source/JavaScriptCore/bytecode/GlobalResolveInfo.h
@@ -42,6 +42,11 @@
     unsigned bytecodeOffset;
 };
 
+inline unsigned getGlobalResolveInfoBytecodeOffset(GlobalResolveInfo* globalResolveInfo)
+{
+    return globalResolveInfo->bytecodeOffset;
+}
+
 } // namespace JSC
 
 #endif // GlobalResolveInfo_h
diff --git a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp
new file mode 100644
index 0000000..ff13870
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "ResolveGlobalStatus.h"
+
+#include "CodeBlock.h"
+#include "JSValue.h"
+#include "Structure.h"
+
+namespace JSC {
+
+static ResolveGlobalStatus computeForStructure(CodeBlock* codeBlock, Structure* structure, Identifier& identifier)
+{
+    unsigned attributesIgnored;
+    JSCell* specificValue;
+    size_t offset = structure->get(
+        *codeBlock->globalData(), identifier, attributesIgnored, specificValue);
+    if (offset == notFound)
+        return ResolveGlobalStatus();
+    
+    return ResolveGlobalStatus(ResolveGlobalStatus::Simple, structure, offset, specificValue);
+}
+
+static ResolveGlobalStatus computeForLLInt(CodeBlock* codeBlock, unsigned bytecodeIndex, Identifier& identifier)
+{
+#if ENABLE(LLINT)
+    Instruction* instruction = codeBlock->instructions().begin() + bytecodeIndex;
+    
+    ASSERT(instruction[0].u.opcode == llint_op_resolve_global);
+    
+    Structure* structure = instruction[3].u.structure.get();
+    if (!structure)
+        return ResolveGlobalStatus();
+    
+    return computeForStructure(codeBlock, structure, identifier);
+#else
+    UNUSED_PARAM(codeBlock);
+    UNUSED_PARAM(bytecodeIndex);
+    UNUSED_PARAM(identifier);
+    return ResolveGlobalStatus();
+#endif
+}
+
+ResolveGlobalStatus ResolveGlobalStatus::computeFor(CodeBlock* codeBlock, unsigned bytecodeIndex, Identifier& identifier)
+{
+#if ENABLE(JIT) && ENABLE(VALUE_PROFILER)
+    if (!codeBlock->numberOfGlobalResolveInfos())
+        return computeForLLInt(codeBlock, bytecodeIndex, identifier);
+    
+    if (codeBlock->likelyToTakeSlowCase(bytecodeIndex))
+        return ResolveGlobalStatus(TakesSlowPath);
+    
+    GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfoForBytecodeOffset(bytecodeIndex);
+    
+    if (!globalResolveInfo.structure)
+        return computeForLLInt(codeBlock, bytecodeIndex, identifier);
+    
+    return computeForStructure(codeBlock, globalResolveInfo.structure.get(), identifier);
+#else
+    return computeForLLInt(codeBlock, bytecodeIndex, identifier);
+#endif
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h
new file mode 100644
index 0000000..4698332
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef ResolveGlobalStatus_h
+#define ResolveGlobalStatus_h
+
+#include "JSValue.h"
+#include <wtf/NotFound.h>
+
+namespace JSC {
+
+class CodeBlock;
+class Identifier;
+class Structure;
+
+class ResolveGlobalStatus {
+public:
+    enum State {
+        NoInformation,
+        Simple,
+        TakesSlowPath
+    };
+    
+    ResolveGlobalStatus()
+        : m_state(NoInformation)
+        , m_structure(0)
+        , m_offset(notFound)
+    {
+    }
+    
+    ResolveGlobalStatus(
+        State state, Structure* structure = 0, size_t offset = notFound,
+        JSValue specificValue = JSValue())
+        : m_state(state)
+        , m_structure(structure)
+        , m_offset(offset)
+        , m_specificValue(specificValue)
+    {
+    }
+    
+    static ResolveGlobalStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
+    
+    State state() const { return m_state; }
+    
+    bool isSet() const { return m_state != NoInformation; }
+    bool operator!() const { return !isSet(); }
+    bool isSimple() const { return m_state == Simple; }
+    bool takesSlowPath() const { return m_state == TakesSlowPath; }
+    
+    Structure* structure() const { return m_structure; }
+    size_t offset() const { return m_offset; }
+    JSValue specificValue() const { return m_specificValue; }
+
+private:
+    State m_state;
+    Structure* m_structure;
+    size_t m_offset;
+    JSValue m_specificValue;
+}; // class ResolveGlobalStatus
+
+} // namespace JSC
+
+#endif // ResolveGlobalStatus_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 317a085..c52c805 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -35,6 +35,7 @@
 #include "GetByIdStatus.h"
 #include "MethodCallLinkStatus.h"
 #include "PutByIdStatus.h"
+#include "ResolveGlobalStatus.h"
 #include <wtf/HashMap.h>
 #include <wtf/MathExtras.h>
 
@@ -94,6 +95,9 @@
     void setIntrinsicResult(bool usesResult, int resultOperand, NodeIndex);
     // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
     bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction);
+    void handleGetByOffset(
+        int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
+        bool useInlineStorage, size_t offset);
     void handleGetById(
         int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
         const GetByIdStatus&);
@@ -1567,6 +1571,31 @@
     }
 }
 
+void ByteCodeParser::handleGetByOffset(
+    int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
+    bool useInlineStorage, size_t offset)
+{
+    NodeIndex propertyStorage;
+    size_t offsetOffset;
+    if (useInlineStorage) {
+        propertyStorage = base;
+        ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
+        offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
+    } else {
+        propertyStorage = addToGraph(GetPropertyStorage, base);
+        offsetOffset = 0;
+    }
+    set(destinationOperand,
+        addToGraph(
+            GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
+            propertyStorage));
+        
+    StorageAccessData storageAccessData;
+    storageAccessData.offset = offset + offsetOffset;
+    storageAccessData.identifierNumber = identifierNumber;
+    m_graph.m_storageAccessData.append(storageAccessData);
+}
+
 void ByteCodeParser::handleGetById(
     int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
     const GetByIdStatus& getByIdStatus)
@@ -1620,25 +1649,9 @@
         return;
     }
     
-    NodeIndex propertyStorage;
-    size_t offsetOffset;
-    if (useInlineStorage) {
-        propertyStorage = base;
-        ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
-        offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
-    } else {
-        propertyStorage = addToGraph(GetPropertyStorage, base);
-        offsetOffset = 0;
-    }
-    set(destinationOperand,
-        addToGraph(
-            GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
-            propertyStorage));
-        
-    StorageAccessData storageAccessData;
-    storageAccessData.offset = getByIdStatus.offset() + offsetOffset;
-    storageAccessData.identifierNumber = identifierNumber;
-    m_graph.m_storageAccessData.append(storageAccessData);
+    handleGetByOffset(
+        destinationOperand, prediction, base, identifierNumber, useInlineStorage,
+        getByIdStatus.offset());
 }
 
 void ByteCodeParser::prepareToParseBlock()
@@ -2648,10 +2661,39 @@
         case op_resolve_global: {
             SpeculatedType prediction = getPrediction();
             
+            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[
+                currentInstruction[2].u.operand];
+            
+            ResolveGlobalStatus status = ResolveGlobalStatus::computeFor(
+                m_inlineStackTop->m_profiledBlock, m_currentIndex,
+                m_codeBlock->identifier(identifierNumber));
+            if (status.isSimple()) {
+                ASSERT(status.structure());
+                
+                NodeIndex globalObject = addStructureTransitionCheck(
+                    m_inlineStackTop->m_codeBlock->globalObject(), status.structure());
+                
+                if (status.specificValue()) {
+                    ASSERT(status.specificValue().isCell());
+                    
+                    set(currentInstruction[1].u.operand,
+                        cellConstant(status.specificValue().asCell()));
+                } else {
+                    handleGetByOffset(
+                        currentInstruction[1].u.operand, prediction, globalObject,
+                        identifierNumber, status.structure()->isUsingInlineStorage(),
+                        status.offset());
+                }
+                
+                m_globalResolveNumber++; // Skip over the unused global resolve info.
+                
+                NEXT_OPCODE(op_resolve_global);
+            }
+            
             NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction));
             m_graph.m_resolveGlobalData.append(ResolveGlobalData());
             ResolveGlobalData& data = m_graph.m_resolveGlobalData.last();
-            data.identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
+            data.identifierNumber = identifierNumber;
             data.resolveInfoIndex = m_globalResolveNumber++;
             set(currentInstruction[1].u.operand, resolve);
 
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index aa71b8a..66cc898 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -43,6 +43,16 @@
 
 namespace JSC {
 
+JSCell* getCallableObjectSlow(JSCell* cell)
+{
+    Structure* structure = cell->structure();
+    if (structure->typeInfo().type() == JSFunctionType)
+        return cell;
+    if (structure->classInfo()->isSubClassOf(&InternalFunction::s_info))
+        return cell;
+    return 0;
+}
+
 ASSERT_CLASS_FITS_IN_CELL(JSObject);
 ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject);
 ASSERT_CLASS_FITS_IN_CELL(JSFinalObject);
@@ -133,7 +143,7 @@
         for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
             prototype = obj->prototype();
             if (prototype.isNull()) {
-                if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode())
+                if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
                     throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
                 return;
             }
@@ -180,7 +190,7 @@
             break;
     }
     
-    if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode())
+    if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
         throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
     return;
 }
@@ -196,7 +206,7 @@
 {
     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
     PutPropertySlot slot;
-    object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getJSFunction(value));
+    object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getCallableObject(value));
 }
 
 bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
@@ -226,7 +236,7 @@
     ASSERT(value.isGetterSetter() && (attributes & Accessor));
 
     PutPropertySlot slot;
-    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
+    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getCallableObject(value));
 
     // putDirect will change our Structure if we add a new property. For
     // getters and setters, though, we also need to change our Structure
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index ac8601d..fdb708d 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -46,6 +46,15 @@
         return 0;
     }
 
+    JS_EXPORT_PRIVATE JSCell* getCallableObjectSlow(JSCell*);
+
+    inline JSCell* getCallableObject(JSValue value)
+    {
+        if (!value.isCell())
+            return 0;
+        return getCallableObjectSlow(value.asCell());
+    }
+
     class GetterSetter;
     class HashEntry;
     class InternalFunction;
@@ -759,20 +768,20 @@
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
     ASSERT(!structure()->hasGetterSetterProperties());
 
-    return putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value));
+    return putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value));
 }
 
 inline void JSObject::putDirect(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes)
 {
     ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
     PutPropertySlot slot;
-    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value));
+    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getCallableObject(value));
 }
 
 inline void JSObject::putDirect(JSGlobalData& globalData, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
 {
     ASSERT(!value.isGetterSetter());
-    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getJSFunction(value));
+    putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, 0, slot, getCallableObject(value));
 }
 
 inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes)
@@ -781,7 +790,7 @@
     PropertyStorage newStorage = propertyStorage();
     if (structure()->shouldGrowPropertyStorage())
         newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
-    size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
+    size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getCallableObject(value));
     setPropertyStorage(globalData, newStorage, structure());
     putDirectOffset(globalData, offset, value);
 }