Changeset 95865 in webkit


Ignore:
Timestamp:
Sep 23, 2011 3:05:24 PM (13 years ago)
Author:
oliver@apple.com
Message:

Make write barriers actually do something when enabled
https://bugs.webkit.org/show_bug.cgi?id=68717

Reviewed by Geoffrey Garen.

../../../../Volumes/Data/git/WebKit/OpenSource/Source/JavaScriptCore:

Add a basic card marking style write barrier to JSC (currently
turned off). This requires two scratch registers in the JIT
so there was some register re-arranging to satisfy that requirement.
Happily this produced a minor perf bump in sunspider (~0.5%).

Turning the barriers on causes an overall regression of around 1.5%

(JSC::MacroAssemblerX86Common::store8):

  • assembler/X86Assembler.h:

(JSC::X86Assembler::movb_i8m):

  • dfg/DFGJITCodeGenerator.cpp:

(JSC::DFG::JITCodeGenerator::isKnownNotCell):
(JSC::DFG::JITCodeGenerator::writeBarrier):
(JSC::DFG::JITCodeGenerator::markCellCard):
(JSC::DFG::JITCodeGenerator::cachedPutById):

  • dfg/DFGJITCodeGenerator.h:
  • dfg/DFGRepatch.cpp:

(JSC::DFG::tryCachePutByID):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • heap/CardSet.h: Added.

(JSC::CardSet::CardSet):
(JSC::::cardForAtom):
(JSC::::cardMarkedForAtom):
(JSC::::markCardForAtom):

  • heap/Heap.cpp:
  • heap/Heap.h:

(JSC::Heap::addressOfCardFor):
(JSC::Heap::writeBarrierFastCase):

  • heap/MarkedBlock.h:

(JSC::MarkedBlock::setDirtyObject):
(JSC::MarkedBlock::addressOfCardFor):
(JSC::MarkedBlock::offsetOfCards):

  • jit/JIT.h:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::emit_op_put_scoped_var):
(JSC::JIT::emit_op_put_global_var):
(JSC::JIT::emitWriteBarrier):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::emitSlow_op_put_by_id):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::emit_op_put_scoped_var):
(JSC::JIT::emit_op_put_global_var):

../../../../Volumes/Data/git/WebKit/OpenSource/Source/WebCore:

Add a forwarding header, and fix an evaluation ordering
issue that shows up if you try to use write barriers.

  • ForwardingHeaders/heap/CardSet.h: Added.
  • bindings/js/JSEventListener.h:

(WebCore::JSEventListener::jsFunction):

Location:
trunk/Source
Files:
2 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r95864 r95865  
     12011-09-23  Oliver Hunt  <oliver@apple.com>
     2
     3        Make write barriers actually do something when enabled
     4        https://bugs.webkit.org/show_bug.cgi?id=68717
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Add a basic card marking style write barrier to JSC (currently
     9        turned off).  This requires two scratch registers in the JIT
     10        so there was some register re-arranging to satisfy that requirement.
     11        Happily this produced a minor perf bump in sunspider (~0.5%).
     12
     13        Turning the barriers on causes an overall regression of around 1.5%
     14
     15        * JavaScriptCore.exp:
     16        * JavaScriptCore.xcodeproj/project.pbxproj:
     17        * assembler/MacroAssemblerX86Common.h:
     18        (JSC::MacroAssemblerX86Common::store8):
     19        * assembler/X86Assembler.h:
     20        (JSC::X86Assembler::movb_i8m):
     21        * dfg/DFGJITCodeGenerator.cpp:
     22        (JSC::DFG::JITCodeGenerator::isKnownNotCell):
     23        (JSC::DFG::JITCodeGenerator::writeBarrier):
     24        (JSC::DFG::JITCodeGenerator::markCellCard):
     25        (JSC::DFG::JITCodeGenerator::cachedPutById):
     26        * dfg/DFGJITCodeGenerator.h:
     27        * dfg/DFGRepatch.cpp:
     28        (JSC::DFG::tryCachePutByID):
     29        * dfg/DFGSpeculativeJIT.cpp:
     30        (JSC::DFG::SpeculativeJIT::compile):
     31        * heap/CardSet.h: Added.
     32        (JSC::CardSet::CardSet):
     33        (JSC::::cardForAtom):
     34        (JSC::::cardMarkedForAtom):
     35        (JSC::::markCardForAtom):
     36        * heap/Heap.cpp:
     37        * heap/Heap.h:
     38        (JSC::Heap::addressOfCardFor):
     39        (JSC::Heap::writeBarrierFastCase):
     40        * heap/MarkedBlock.h:
     41        (JSC::MarkedBlock::setDirtyObject):
     42        (JSC::MarkedBlock::addressOfCardFor):
     43        (JSC::MarkedBlock::offsetOfCards):
     44        * jit/JIT.h:
     45        * jit/JITPropertyAccess.cpp:
     46        (JSC::JIT::emit_op_put_by_val):
     47        (JSC::JIT::emit_op_put_by_id):
     48        (JSC::JIT::privateCompilePutByIdTransition):
     49        (JSC::JIT::emit_op_put_scoped_var):
     50        (JSC::JIT::emit_op_put_global_var):
     51        (JSC::JIT::emitWriteBarrier):
     52        * jit/JITPropertyAccess32_64.cpp:
     53        (JSC::JIT::emit_op_put_by_val):
     54        (JSC::JIT::emit_op_put_by_id):
     55        (JSC::JIT::emitSlow_op_put_by_id):
     56        (JSC::JIT::privateCompilePutByIdTransition):
     57        (JSC::JIT::emit_op_put_scoped_var):
     58        (JSC::JIT::emit_op_put_global_var):
     59
    1602011-09-23  Thouraya ANDOLSI  <thouraya.andolsi@st.com>
    261
  • trunk/Source/JavaScriptCore/JavaScriptCore.exp

    r95849 r95865  
    241241__ZN3JSC4Heap19setActivityCallbackEN3WTF10PassOwnPtrINS_18GCActivityCallbackEEE
    242242__ZN3JSC4Heap20protectedObjectCountEv
    243 __ZN3JSC4Heap20writeBarrierSlowCaseEPKNS_6JSCellEPS1_
    244243__ZN3JSC4Heap25protectedObjectTypeCountsEv
    245244__ZN3JSC4Heap26protectedGlobalObjectCountEv
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r95751 r95865  
    430430                A7482E93116A7CAD003B0712 /* JSWeakObjectMapRefInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */; settings = {ATTRIBUTES = (Private, ); }; };
    431431                A74DE1D0120B875600D40D5B /* ARMv7Assembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A74DE1CB120B86D600D40D5B /* ARMv7Assembler.cpp */; };
     432                A7521E131429169A003C8D0C /* CardSet.h in Headers */ = {isa = PBXBuildFile; fileRef = A7521E121429169A003C8D0C /* CardSet.h */; settings = {ATTRIBUTES = (); }; };
    432433                A75706DE118A2BCF0057F88F /* JITArithmetic32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A75706DD118A2BCF0057F88F /* JITArithmetic32_64.cpp */; };
    433434                A766B44F0EE8DCD1009518CA /* ExecutableAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    12141215                A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakObjectMapRefInternal.h; sourceTree = "<group>"; };
    12151216                A74DE1CB120B86D600D40D5B /* ARMv7Assembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ARMv7Assembler.cpp; sourceTree = "<group>"; };
     1217                A7521E121429169A003C8D0C /* CardSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CardSet.h; sourceTree = "<group>"; };
    12161218                A75706DD118A2BCF0057F88F /* JITArithmetic32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic32_64.cpp; sourceTree = "<group>"; };
    12171219                A76C51741182748D00715B05 /* JSInterfaceJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInterfaceJIT.h; sourceTree = "<group>"; };
     
    16341636                                0FD82F281426CA5A00179C94 /* JettisonedCodeBlocks.cpp */,
    16351637                                0FD82F291426CA5A00179C94 /* JettisonedCodeBlocks.h */,
     1638                                A70456AE1427FB030037DA68 /* AllocationSpace.cpp */,
    16361639                                A70456AF1427FB150037DA68 /* AllocationSpace.h */,
    1637                                 A70456AE1427FB030037DA68 /* AllocationSpace.cpp */,
    1638                                 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */,
    1639                                 0FC815141405118D00CFA603 /* VTableSpectrum.h */,
    1640                                 0FC815121405118600CFA603 /* VTableSpectrum.cpp */,
    1641                                 0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */,
    1642                                 0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */,
     1640                                A7521E121429169A003C8D0C /* CardSet.h */,
    16431641                                146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */,
    16441642                                149DAAF212EB559D0083B12B /* ConservativeRoots.h */,
     
    16661664                                142E3132134FF0A600AFADB5 /* Strong.h */,
    16671665                                141448CC13A1783700F5BA1A /* TinyBloomFilter.h */,
     1666                                0FC815121405118600CFA603 /* VTableSpectrum.cpp */,
     1667                                0FC815141405118D00CFA603 /* VTableSpectrum.h */,
    16681668                                142E3133134FF0A600AFADB5 /* Weak.h */,
     1669                                0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */,
     1670                                0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */,
     1671                                0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */,
    16691672                        );
    16701673                        path = heap;
     
    28192822                                A70456B01427FB910037DA68 /* AllocationSpace.h in Headers */,
    28202823                                86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */,
     2824                                A7521E131429169A003C8D0C /* CardSet.h in Headers */,
    28212825                        );
    28222826                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r94981 r95865  
    510510    {
    511511        m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
     512    }
     513   
     514    void store8(TrustedImm32 imm, Address address)
     515    {
     516        ASSERT(-128 <= imm.m_value && imm.m_value < 128);
     517        m_assembler.movb_i8m(imm.m_value, address.offset, address.base);
     518    }
     519
     520    void store8(TrustedImm32 imm, BaseIndex address)
     521    {
     522        ASSERT(-128 <= imm.m_value && imm.m_value < 128);
     523        m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
    512524    }
    513525
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r95692 r95865  
    146146        OP_GROUP2_EvIb                  = 0xC1,
    147147        OP_RET                          = 0xC3,
     148        OP_GROUP11_EvIb                 = 0xC6,
    148149        OP_GROUP11_EvIz                 = 0xC7,
    149150        OP_INT3                         = 0xCC,
     
    10561057        m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, offset);
    10571058        m_formatter.immediate32(imm);
     1059    }
     1060   
     1061    void movb_i8m(int imm, int offset, RegisterID base)
     1062    {
     1063        ASSERT(-128 <= imm && imm < 128);
     1064        m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, offset);
     1065        m_formatter.immediate8(imm);
     1066    }
     1067
     1068    void movb_i8m(int imm, int offset, RegisterID base, RegisterID index, int scale)
     1069    {
     1070        ASSERT(-128 <= imm && imm < 128);
     1071        m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, index, scale, offset);
     1072        m_formatter.immediate8(imm);
    10581073    }
    10591074
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp

    r95563 r95865  
    430430}
    431431
     432bool JITCodeGenerator::isKnownNotCell(NodeIndex nodeIndex)
     433{
     434    Node& node = m_jit.graph()[nodeIndex];
     435    VirtualRegister virtualRegister = node.virtualRegister();
     436    GenerationInfo& info = m_generationInfo[virtualRegister];
     437    if (node.hasConstant() && !valueOfJSConstant(nodeIndex).isCell())
     438        return true;
     439    return !(info.isJSCell() || info.isUnknownJS());
     440}
     441
    432442bool JITCodeGenerator::isKnownNotInteger(NodeIndex nodeIndex)
    433443{
     
    11671177}
    11681178
    1169 void JITCodeGenerator::writeBarrier(MacroAssembler& jit, GPRReg owner, GPRReg scratch, WriteBarrierUseKind useKind)
     1179void JITCodeGenerator::writeBarrier(MacroAssembler& jit, GPRReg owner, GPRReg scratch1, GPRReg scratch2, WriteBarrierUseKind useKind)
    11701180{
    11711181    UNUSED_PARAM(jit);
    11721182    UNUSED_PARAM(owner);
    1173     UNUSED_PARAM(scratch);
     1183    UNUSED_PARAM(scratch1);
     1184    UNUSED_PARAM(scratch2);
    11741185    UNUSED_PARAM(useKind);
    1175     ASSERT(owner != scratch);
     1186    ASSERT(owner != scratch1);
     1187    ASSERT(owner != scratch2);
     1188    ASSERT(scratch1 != scratch2);
    11761189
    11771190#if ENABLE(WRITE_BARRIER_PROFILING)
    11781191    JITCompiler::emitCount(jit, WriteBarrierCounters::jitCounterFor(useKind));
    11791192#endif
    1180 }
    1181 
    1182 void JITCodeGenerator::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
    1183 {
     1193    markCellCard(jit, owner, scratch1, scratch2);
     1194}
     1195
     1196void JITCodeGenerator::markCellCard(MacroAssembler& jit, GPRReg owner, GPRReg scratch1, GPRReg scratch2)
     1197{
     1198    UNUSED_PARAM(jit);
     1199    UNUSED_PARAM(owner);
     1200    UNUSED_PARAM(scratch1);
     1201    UNUSED_PARAM(scratch2);
     1202   
     1203#if ENABLE(GGC)
     1204    jit.move(owner, scratch1);
     1205    jit.andPtr(TrustedImm32(static_cast<int32_t>(MarkedBlock::blockMask)), scratch1);
     1206    jit.move(owner, scratch2);
     1207    jit.andPtr(TrustedImm32(static_cast<int32_t>(~MarkedBlock::blockMask)), scratch2);
     1208    jit.rshift32(TrustedImm32(MarkedBlock::log2CardSize), scratch2);
     1209    jit.store8(TrustedImm32(1), MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::TimesOne, MarkedBlock::offsetOfCards()));
     1210#endif
     1211}
     1212
     1213void JITCodeGenerator::writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, NodeIndex valueIndex, WriteBarrierUseKind useKind, GPRReg scratch1, GPRReg scratch2)
     1214{
     1215    UNUSED_PARAM(ownerGPR);
     1216    UNUSED_PARAM(valueGPR);
     1217    UNUSED_PARAM(scratch1);
     1218    UNUSED_PARAM(scratch2);
     1219    UNUSED_PARAM(useKind);
     1220
     1221    if (isKnownNotCell(valueIndex))
     1222        return;
     1223
     1224#if ENABLE(WRITE_BARRIER_PROFILING)
     1225    JITCompiler::emitCount(jit, WriteBarrierCounters::jitCounterFor(useKind));
     1226#endif
     1227
     1228#if ENABLE(GGC)
     1229    JITCompiler::Jump rhsNotCell;
     1230    bool hadCellCheck = false;
     1231    if (!isKnownCell(valueIndex) && !isCellPrediction(m_jit.graph().getPrediction(m_jit.graph()[valueIndex]))) {
     1232        hadCellCheck = true;
     1233        rhsNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
     1234    }
     1235
     1236    GPRTemporary temp1;
     1237    GPRTemporary temp2;
     1238    if (scratch1 == InvalidGPRReg) {
     1239        GPRTemporary scratchGPR(this);
     1240        temp1.adopt(scratchGPR);
     1241        scratch1 = temp1.gpr();
     1242    }
     1243    if (scratch2 == InvalidGPRReg) {
     1244        GPRTemporary scratchGPR(this);
     1245        temp2.adopt(scratchGPR);
     1246        scratch2 = temp2.gpr();
     1247    }
     1248
     1249    markCellCard(m_jit, ownerGPR, scratch1, scratch2);
     1250    if (hadCellCheck)
     1251        rhsNotCell.link(&m_jit);
     1252#endif
     1253}
     1254
     1255void JITCodeGenerator::writeBarrier(JSCell* owner, GPRReg valueGPR, NodeIndex valueIndex, WriteBarrierUseKind useKind, GPRReg scratch)
     1256{
     1257    UNUSED_PARAM(owner);
     1258    UNUSED_PARAM(valueGPR);
     1259    UNUSED_PARAM(scratch);
     1260    UNUSED_PARAM(useKind);
     1261
     1262    if (isKnownNotCell(valueIndex))
     1263        return;
     1264
     1265#if ENABLE(WRITE_BARRIER_PROFILING)
     1266    JITCompiler::emitCount(jit, WriteBarrierCounters::jitCounterFor(useKind));
     1267#endif
     1268
     1269#if ENABLE(GGC)
     1270    JITCompiler::Jump rhsNotCell;
     1271    bool hadCellCheck = false;
     1272    if (!isKnownCell(valueIndex) && !isCellPrediction(m_jit.graph().getPrediction(m_jit.graph()[valueIndex]))) {
     1273        hadCellCheck = true;
     1274        rhsNotCell = m_jit.branchTestPtr(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
     1275    }
     1276   
     1277    GPRTemporary temp;
     1278    if (scratch == InvalidGPRReg) {
     1279        GPRTemporary scratchGPR(this);
     1280        temp.adopt(scratchGPR);
     1281        scratch = temp.gpr();
     1282    }
     1283
     1284    uint8_t* cardAddress = Heap::addressOfCardFor(owner);
     1285    m_jit.move(JITCompiler::TrustedImmPtr(cardAddress), scratch);
     1286    m_jit.store8(JITCompiler::TrustedImm32(1), JITCompiler::Address(scratch));
     1287
     1288    if (hadCellCheck)
     1289        rhsNotCell.link(&m_jit);
     1290#endif
     1291}
     1292
     1293void JITCodeGenerator::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
     1294{
     1295   
    11841296    JITCompiler::DataLabelPtr structureToCompare;
    11851297    JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
    1186    
    1187     writeBarrier(m_jit, baseGPR, scratchGPR, WriteBarrierForPropertyAccess);
     1298
     1299    writeBarrier(baseGPR, valueGPR, valueIndex, WriteBarrierForPropertyAccess, scratchGPR);
    11881300
    11891301    m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
     
    19782090#endif
    19792091
     2092GPRTemporary::GPRTemporary()
     2093    : m_jit(0)
     2094    , m_gpr(InvalidGPRReg)
     2095{
     2096}
     2097
    19802098GPRTemporary::GPRTemporary(JITCodeGenerator* jit)
    19812099    : m_jit(jit)
     
    20862204}
    20872205
     2206void GPRTemporary::adopt(GPRTemporary& other)
     2207{
     2208    ASSERT(!m_jit);
     2209    ASSERT(m_gpr == InvalidGPRReg);
     2210    ASSERT(other.m_jit);
     2211    ASSERT(other.m_gpr != InvalidGPRReg);
     2212    m_jit = other.m_jit;
     2213    m_gpr = other.m_gpr;
     2214    other.m_jit = 0;
     2215    other.m_gpr = InvalidGPRReg;
     2216}
     2217
    20882218FPRTemporary::FPRTemporary(JITCodeGenerator* jit)
    20892219    : m_jit(jit)
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h

    r95758 r95865  
    182182    }
    183183
    184     static void writeBarrier(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR, WriteBarrierUseKind);
     184    static void markCellCard(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR1, GPRReg scratchGPR2);
     185    static void writeBarrier(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, WriteBarrierUseKind);
     186
     187    void writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, NodeIndex valueIndex, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg, GPRReg scratchGPR2 = InvalidGPRReg);
     188    void writeBarrier(JSCell* owner, GPRReg valueGPR, NodeIndex valueIndex, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg);
    185189
    186190    static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg)
     
    434438
    435439    bool isKnownBoolean(NodeIndex);
     440
     441    bool isKnownNotCell(NodeIndex);
    436442   
    437443    // Checks/accessors for constant values.
     
    619625
    620626    JITCompiler::Call cachedGetById(GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), NodeType = GetById);
    621     void cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
     627    void cachedPutById(GPRReg base, GPRReg value, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
    622628    void cachedGetMethod(GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
    623629   
     
    12481254class GPRTemporary {
    12491255public:
     1256    GPRTemporary();
    12501257    GPRTemporary(JITCodeGenerator*);
    12511258    GPRTemporary(JITCodeGenerator*, GPRReg specific);
     
    12601267    GPRTemporary(JITCodeGenerator*, StorageOperand&);
    12611268
     1269    void adopt(GPRTemporary&);
     1270
    12621271    ~GPRTemporary()
    12631272    {
    1264         m_jit->unlock(gpr());
     1273        if (m_jit)
     1274            m_jit->unlock(gpr());
    12651275    }
    12661276
  • trunk/Source/JavaScriptCore/dfg/DFGRepatch.cpp

    r95447 r95865  
    518518                    testPrototype(stubJit, scratchGPR, (*it)->storedPrototype(), failureCases);
    519519            }
    520            
    521             JITCodeGenerator::writeBarrier(stubJit, baseGPR, scratchGPR, WriteBarrierForPropertyAccess);
    522            
     520
     521#if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
     522            // Must always emit this write barrier as the structure transition itself requires it
     523            GPRReg scratch2 = JITCodeGenerator::selectScratchGPR(baseGPR, valueGPR, scratchGPR);
     524            stubJit.push(scratch2);
     525            JITCodeGenerator::writeBarrier(stubJit, baseGPR, scratchGPR, scratch2, WriteBarrierForPropertyAccess);
     526            stubJit.pop(scratch2);
     527#endif
     528
    523529            stubJit.storePtr(MacroAssembler::TrustedImmPtr(structure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
    524530            if (structure->isUsingInlineStorage())
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r95840 r95865  
    2525
    2626#include "config.h"
     27
    2728#include "DFGSpeculativeJIT.h"
    2829
     
    14051406        if (!m_compileOkay)
    14061407            return;
    1407        
    1408         writeBarrier(m_jit, baseReg, scratchReg, WriteBarrierForPropertyAccess);
     1408
     1409        writeBarrier(baseReg, value.gpr(), node.child3(), WriteBarrierForPropertyAccess, scratchReg);
    14091410
    14101411        // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
     
    14651466        GPRReg scratchReg = scratch.gpr();
    14661467
    1467         writeBarrier(m_jit, baseReg, scratchReg, WriteBarrierForPropertyAccess);
     1468        writeBarrier(base.gpr(), value.gpr(), node.child3(), WriteBarrierForPropertyAccess, scratchReg);
    14681469
    14691470        // Get the array storage.
     
    17961797        JSValueOperand value(this, node.child2());
    17971798        m_jit.storePtr(value.gpr(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register)));
    1798         writeBarrier(m_jit, scopeChain.gpr(), scratchGPR, WriteBarrierForVariableAccess);
     1799        writeBarrier(scopeChain.gpr(), value.gpr(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);
    17991800        break;
    18001801    }
     
    19021903        value.use();
    19031904
    1904         cachedPutById(baseGPR, valueGPR, scratchGPR, node.identifierNumber(), NotDirect);
     1905        cachedPutById(baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect);
    19051906       
    19061907        noResult(m_compileIndex, UseChildrenCalledExplicitly);
     
    19201921        value.use();
    19211922
    1922         cachedPutById(baseGPR, valueGPR, scratchGPR, node.identifierNumber(), Direct);
     1923        cachedPutById(baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct);
    19231924
    19241925        noResult(m_compileIndex, UseChildrenCalledExplicitly);
     
    19471948        m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()), globalObjectReg);
    19481949
    1949         writeBarrier(m_jit, globalObjectReg, scratchReg, WriteBarrierForVariableAccess);
     1950        writeBarrier(m_jit.codeBlock()->globalObject(), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg);
    19501951
    19511952        m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg);
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r95681 r95865  
    683683}
    684684
    685 #if ENABLE(GGC)
    686 void Heap::writeBarrierSlowCase(const JSCell* owner, JSCell* cell)
    687 {
    688 }
    689 
    690 #else
    691 
    692 void Heap::writeBarrierSlowCase(const JSCell*, JSCell*)
    693 {
    694 }
    695 #endif
    696 
    697685} // namespace JSC
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r95681 r95865  
    7575        static void writeBarrier(const JSCell*, JSValue);
    7676        static void writeBarrier(const JSCell*, JSCell*);
     77        static uint8_t* addressOfCardFor(JSCell*);
    7778
    7879        Heap(JSGlobalData*, HeapSize);
     
    132133        static const size_t minExtraCost = 256;
    133134        static const size_t maxExtraCost = 1024 * 1024;
    134        
    135 #if ENABLE(GGC)
    136         static void writeBarrierFastCase(const JSCell* owner, JSCell*);
    137 #endif
    138135
    139136        bool isValidAllocation(size_t);
     
    158155        RegisterFile& registerFile();
    159156
    160         static void writeBarrierSlowCase(const JSCell*, JSCell*);
    161 
    162157        void waitForRelativeTimeWhileHoldingLock(double relative);
    163158        void waitForRelativeTime(double relative);
     
    240235
    241236#if ENABLE(GGC)
    242     inline void Heap::writeBarrierFastCase(const JSCell* owner, JSCell* cell)
    243     {
    244         if (MarkedBlock::blockFor(owner)->inNewSpace())
    245             return;
    246         writeBarrierSlowCase(owner, cell);
    247     }
    248 
    249     inline void Heap::writeBarrier(const JSCell* owner, JSCell* cell)
     237    inline uint8_t* Heap::addressOfCardFor(JSCell* cell)
     238    {
     239        return MarkedBlock::blockFor(cell)->addressOfCardFor(cell);
     240    }
     241
     242    inline void Heap::writeBarrier(const JSCell* owner, JSCell*)
    250243    {
    251244        WriteBarrierCounters::countWriteBarrier();
    252         writeBarrierFastCase(owner, cell);
     245        MarkedBlock::blockFor(owner)->setDirtyObject(owner);
    253246    }
    254247
    255248    inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
    256249    {
    257         WriteBarrierCounters::countWriteBarrier();
    258250        if (!value)
    259251            return;
    260252        if (!value.isCell())
    261253            return;
    262         writeBarrierFastCase(owner, value.asCell());
     254        writeBarrier(owner, value.asCell());
    263255    }
    264256#else
  • trunk/Source/JavaScriptCore/heap/MarkedBlock.h

    r95596 r95865  
    2323#define MarkedBlock_h
    2424
     25#include "CardSet.h"
     26
    2527#include <wtf/Bitmap.h>
    2628#include <wtf/DoublyLinkedList.h>
     
    6668        static const size_t atomSize = 4 * sizeof(void*);
    6769        static const size_t blockSize = 16 * KB;
    68         static const size_t atomsPerBlock = blockSize / atomSize; // ~0.4% overhead for mark bits.
     70        static const size_t blockMask = ~(blockSize - 1); // blockSize must be a power of two.
     71
     72        static const size_t atomsPerBlock = blockSize / atomSize; // ~0.4% overhead
     73        static const size_t bytesPerCard = 512; // 1.6% overhead
     74        static const int log2CardSize = 9;
    6975
    7076        struct FreeCell {
     
    133139        bool testAndClearMarked(const void*);
    134140        void setMarked(const void*);
     141       
     142#if ENABLE(GGC)
     143        void setDirtyObject(const void* atom)
     144        {
     145            m_cards.markCardForAtom(atom);
     146        }
     147
     148        uint8_t* addressOfCardFor(const void* atom)
     149        {
     150            return &m_cards.cardForAtom(atom);
     151        }
     152
     153        static inline size_t offsetOfCards()
     154        {
     155            return OBJECT_OFFSETOF(MarkedBlock, m_cards);
     156        }
     157#endif
    135158
    136159        template <typename Functor> void forEachCell(Functor&);
    137160
    138161    private:
    139         static const size_t blockMask = ~(blockSize - 1); // blockSize must be a power of two.
    140162        static const size_t atomMask = ~(atomSize - 1); // atomSize must be a power of two.
    141163       
     
    170192            return static_cast<DestructorState>(m_destructorState);
    171193        }
    172        
     194
     195#if ENABLE(GGC)
     196        CardSet<bytesPerCard, blockSize> m_cards;
     197#endif
     198
    173199        size_t m_endAtom; // This is a fuzzy end. Always test for < m_endAtom.
    174200        size_t m_atomsPerCell;
     
    301327        }
    302328    }
    303    
     329
    304330} // namespace JSC
    305331
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r95676 r95865  
    317317        void testPrototype(JSValue, JumpList& failureCases);
    318318
    319         void emitWriteBarrier(RegisterID owner, RegisterID scratch, WriteBarrierUseKind);
     319        enum WriteBarrierMode { UnconditionalWriteBarrier, ShouldFilterImmediates };
     320        // value register in write barrier is used before any scratch registers
     321        // so may safely be the same as either of the scratch registers.
     322        void emitWriteBarrier(RegisterID owner, RegisterID valueTag, RegisterID scratch, RegisterID scratch2, WriteBarrierMode, WriteBarrierUseKind);
     323        void emitWriteBarrier(JSCell* owner, RegisterID value, RegisterID scratch, WriteBarrierMode, WriteBarrierUseKind);
    320324
    321325        template<typename ClassType, typename StructureType> void emitAllocateBasicJSObject(StructureType, void* vtable, RegisterID result, RegisterID storagePtr);
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r95786 r95865  
    208208
    209209    Label storeResult(this);
    210     emitGetVirtualRegister(value, regT0);
    211     storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
     210    emitGetVirtualRegister(value, regT3);
     211    storePtr(regT3, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
    212212    Jump end = jump();
    213213   
     
    216216    branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
    217217
    218     move(regT1, regT0);
    219     add32(TrustedImm32(1), regT0);
    220     store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)));
     218    add32(TrustedImm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)));
    221219    jump().linkTo(storeResult, this);
    222220
    223221    end.link(this);
     222
     223    emitWriteBarrier(regT0, regT3, regT1, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
    224224}
    225225
     
    440440    emitJumpSlowCaseIfNotJSCell(regT0, baseVReg);
    441441
    442     emitWriteBarrier(regT0, regT2, WriteBarrierForPropertyAccess);
    443 
    444442    BEGIN_UNINTERRUPTED_SEQUENCE(sequencePutById);
    445443
     
    454452    ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetPutByIdStructure);
    455453
    456     loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT0);
    457     DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT0, patchPutByIdDefaultOffset));
     454    loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT2);
     455    DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT2, patchPutByIdDefaultOffset));
    458456
    459457    END_UNINTERRUPTED_SEQUENCE(sequencePutById);
     458
     459    emitWriteBarrier(regT0, regT1, regT2, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
    460460
    461461    ASSERT_JIT_OFFSET_UNUSED(displacementLabel, differenceBetween(hotPathBegin, displacementLabel), patchOffsetPutByIdPropertyMapOffset);
     
    538538        restoreReturnAddressBeforeReturn(regT3);
    539539    }
    540    
    541     emitWriteBarrier(regT0, regT2, WriteBarrierForPropertyAccess);
     540
     541    // Planting the new structure triggers the write barrier so we need
     542    // an unconditional barrier here.
     543    emitWriteBarrier(regT0, regT1, regT2, regT3, UnconditionalWriteBarrier, WriteBarrierForPropertyAccess);
    542544
    543545    storePtr(TrustedImmPtr(newStructure), Address(regT0, JSCell::structureOffset()));
     
    990992    loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, object)), regT1);
    991993
    992     emitWriteBarrier(regT1, regT2, WriteBarrierForVariableAccess);
     994    emitWriteBarrier(regT1, regT0, regT2, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess);
    993995
    994996    loadPtr(Address(regT1, JSVariableObject::offsetOfRegisters()), regT1);
     
    10101012
    10111013    emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
     1014
    10121015    move(TrustedImmPtr(globalObject), regT1);
    1013    
    1014     emitWriteBarrier(regT1, regT2, WriteBarrierForVariableAccess);
    1015 
    10161016    loadPtr(Address(regT1, JSVariableObject::offsetOfRegisters()), regT1);
    10171017    storePtr(regT0, Address(regT1, currentInstruction[1].u.operand * sizeof(Register)));
    1018 }
    1019 
    1020 void JIT::emitWriteBarrier(RegisterID owner, RegisterID scratch, WriteBarrierUseKind useKind)
     1018    emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
     1019}
     1020
     1021#endif // USE(JSVALUE64)
     1022
     1023void JIT::emitWriteBarrier(RegisterID owner, RegisterID value, RegisterID scratch, RegisterID scratch2, WriteBarrierMode mode, WriteBarrierUseKind useKind)
     1024{
     1025    UNUSED_PARAM(owner);
     1026    UNUSED_PARAM(scratch);
     1027    UNUSED_PARAM(scratch2);
     1028    UNUSED_PARAM(useKind);
     1029    UNUSED_PARAM(value);
     1030    UNUSED_PARAM(mode);
     1031    ASSERT(owner != scratch);
     1032    ASSERT(owner != scratch2);
     1033   
     1034#if ENABLE(WRITE_BARRIER_PROFILING)
     1035    emitCount(WriteBarrierCounters::jitCounterFor(useKind));
     1036#endif
     1037   
     1038#if ENABLE(GGC)
     1039    Jump filterCells;
     1040    if (mode == ShouldFilterImmediates)
     1041        filterCells = emitJumpIfNotJSCell(value);
     1042    move(owner, scratch);
     1043    andPtr(TrustedImm32(static_cast<int32_t>(MarkedBlock::blockMask)), scratch);
     1044    move(owner, scratch2);
     1045    andPtr(TrustedImm32(static_cast<int32_t>(~MarkedBlock::blockMask)), scratch2);
     1046    rshift32(TrustedImm32(MarkedBlock::log2CardSize), scratch2);
     1047    store8(TrustedImm32(1), BaseIndex(scratch, scratch2, TimesOne, MarkedBlock::offsetOfCards()));
     1048    if (mode == ShouldFilterImmediates)
     1049        filterCells.link(this);
     1050#endif
     1051}
     1052
     1053void JIT::emitWriteBarrier(JSCell* owner, RegisterID value, RegisterID scratch, WriteBarrierMode mode, WriteBarrierUseKind useKind)
    10211054{
    10221055    UNUSED_PARAM(owner);
    10231056    UNUSED_PARAM(scratch);
    10241057    UNUSED_PARAM(useKind);
    1025     ASSERT(owner != scratch);
     1058    UNUSED_PARAM(value);
     1059    UNUSED_PARAM(mode);
    10261060   
    10271061#if ENABLE(WRITE_BARRIER_PROFILING)
    10281062    emitCount(WriteBarrierCounters::jitCounterFor(useKind));
    10291063#endif
    1030 }
    1031 
    1032 #endif // USE(JSVALUE64)
     1064   
     1065#if ENABLE(GGC)
     1066    Jump filterCells;
     1067    if (mode == ShouldFilterImmediates)
     1068        filterCells = emitJumpIfNotJSCell(value);
     1069    uint8_t* cardAddress = Heap::addressOfCardFor(owner);
     1070    move(TrustedImmPtr(cardAddress), scratch);
     1071    store8(TrustedImm32(1), Address(scratch));
     1072    if (mode == ShouldFilterImmediates)
     1073        filterCells.link(this);
     1074#endif
     1075}
    10331076
    10341077void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r95455 r95865  
    259259   
    260260    addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
    261     emitJumpSlowCaseIfNotJSCell(base, regT1);
    262     emitWriteBarrier(regT0, regT1, WriteBarrierForPropertyAccess);
    263261    addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsArrayVPtr)));
    264262    addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset())));
    265263   
     264    emitJumpSlowCaseIfNotJSCell(base, regT1);
     265    emitWriteBarrier(regT0, regT1, regT1, regT3, UnconditionalWriteBarrier, WriteBarrierForPropertyAccess);
     266
    266267    loadPtr(Address(regT0, JSArray::storageOffset()), regT3);
    267268   
     
    397398    emitJumpSlowCaseIfNotJSCell(base, regT1);
    398399   
    399     emitWriteBarrier(regT0, regT1, WriteBarrierForPropertyAccess);
    400    
    401400    BEGIN_UNINTERRUPTED_SEQUENCE(sequencePutById);
    402401   
     
    411410    ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetPutByIdStructure);
    412411   
    413     loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT0);
    414     DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT0, patchPutByIdDefaultOffset)); // payload
    415     DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT0, patchPutByIdDefaultOffset)); // tag
     412    loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT1);
     413    DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT1, patchPutByIdDefaultOffset)); // payload
     414    DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT1, patchPutByIdDefaultOffset)); // tag
    416415   
    417416    END_UNINTERRUPTED_SEQUENCE(sequencePutById);
     417
     418    emitWriteBarrier(regT0, regT2, regT1, regT2, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
    418419   
    419420    ASSERT_JIT_OFFSET_UNUSED(displacementLabel1, differenceBetween(hotPathBegin, displacementLabel1), patchOffsetPutByIdPropertyMapOffset1);
     
    431432   
    432433    JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct : cti_op_put_by_id);
    433     stubCall.addArgument(regT1, regT0);
     434    stubCall.addArgument(base);
    434435    stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident))));
    435436    stubCall.addArgument(regT3, regT2);
     
    517518    }
    518519
    519     emitWriteBarrier(regT0, regT1, WriteBarrierForPropertyAccess);
     520    emitWriteBarrier(regT0, regT1, regT1, regT3, UnconditionalWriteBarrier, WriteBarrierForPropertyAccess);
    520521
    521522    storePtr(TrustedImmPtr(newStructure), Address(regT0, JSCell::structureOffset()));
     
    10441045    loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2);
    10451046
    1046     emitWriteBarrier(regT2, regT3, WriteBarrierForVariableAccess);
    1047 
    1048     loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2);
    1049     emitStore(index, regT1, regT0, regT2);
    1050     map(m_bytecodeOffset + OPCODE_LENGTH(op_put_scoped_var), value, regT1, regT0);
     1047    loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT3);
     1048    emitStore(index, regT1, regT0, regT3);
     1049    emitWriteBarrier(regT2, regT1, regT0, regT1, ShouldFilterImmediates, WriteBarrierForVariableAccess);
    10511050}
    10521051
     
    10751074    move(TrustedImmPtr(globalObject), regT2);
    10761075
    1077     emitWriteBarrier(regT2, regT3, WriteBarrierForVariableAccess);
     1076    emitWriteBarrier(globalObject, regT1, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess);
    10781077
    10791078    loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2);
     
    10821081}
    10831082
    1084 void JIT::emitWriteBarrier(RegisterID owner, RegisterID scratch, WriteBarrierUseKind useKind)
    1085 {
    1086     UNUSED_PARAM(owner);
    1087     UNUSED_PARAM(scratch);
    1088     UNUSED_PARAM(useKind);
    1089     ASSERT(owner != scratch);
    1090    
    1091 #if ENABLE(WRITE_BARRIER_PROFILING)
    1092     emitCount(WriteBarrierCounters::jitCounterFor(useKind));
    1093 #endif
    1094 }
    1095 
    10961083} // namespace JSC
    10971084
  • trunk/Source/WebCore/ChangeLog

    r95863 r95865  
     12011-09-23  Oliver Hunt  <oliver@apple.com>
     2
     3        Make write barriers actually do something when enabled
     4        https://bugs.webkit.org/show_bug.cgi?id=68717
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Add a forwarding header, and fix an evaluation ordering
     9        issue that shows up if you try to use write barriers.
     10
     11        * ForwardingHeaders/heap/CardSet.h: Added.
     12        * bindings/js/JSEventListener.h:
     13        (WebCore::JSEventListener::jsFunction):
     14
    1152011-09-23  James Robinson  <jamesr@chromium.org>
    216
  • trunk/Source/WebCore/bindings/js/JSEventListener.h

    r86499 r95865  
    7575    inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext* scriptExecutionContext) const
    7676    {
    77         if (!m_jsFunction)
    78             m_jsFunction.setMayBeNull(*scriptExecutionContext->globalData(), m_wrapper.get(), initializeJSFunction(scriptExecutionContext));
     77        if (!m_jsFunction) {
     78            JSC::JSObject* function = initializeJSFunction(scriptExecutionContext);
     79            m_jsFunction.setMayBeNull(*scriptExecutionContext->globalData(), m_wrapper.get(), function);
     80        }
    7981
    8082        // Verify that we have a valid wrapper protecting our function from
Note: See TracChangeset for help on using the changeset viewer.