Changeset 168443 in webkit


Ignore:
Timestamp:
May 7, 2014 3:00:10 PM (10 years ago)
Author:
mark.lam@apple.com
Message:

REGRESSION(r166678): Dromaeo/cssquery-dojo.html crashes regularly.
<https://webkit.org/b/131356>

Reviewed by Geoffrey Garen.

The issue is that GC needs to be made aware of writes to m_inferredValue
in the VariableWatchpointSet, but was not. As a result, if a JSCell*
is written to a VariableWatchpointSet m_inferredValue, and that JSCell
does not survive an eden GC shortly after, we will end up with a stale
JSCell pointer left in the m_inferredValue.

This issue can be detected more easily by running Dromaeo/cssquery-dojo.html
using DumpRenderTree with the VM heap in zombie mode.

The fix is to change VariableWatchpointSet m_inferredValue to type
WriteBarrier<Unknown> and ensure that VariableWatchpointSet::notifyWrite()
is executed by all the execution engines so that the WriteBarrier semantics
are honored.

We still check if the value to be written is the same as the one in the
inferredValue. We'll by-pass calling the slow path notifyWrite() if the
values are the same.

(JSC::CodeBlock::CodeBlock):

  • need to pass the symbolTable to prepareToWatch() because it will be needed for instantiating the VariableWatchpointSet in prepareToWatch().
  • bytecode/VariableWatchpointSet.h:

(JSC::VariableWatchpointSet::VariableWatchpointSet):

  • VariableWatchpointSet now tracks its owner symbol table for its m_inferredValue write barrier, and yes, m_inferredValue is now of type WriteBarrier<Unknown>.

(JSC::VariableWatchpointSet::inferredValue):
(JSC::VariableWatchpointSet::invalidate):
(JSC::VariableWatchpointSet::finalizeUnconditionally):
(JSC::VariableWatchpointSet::addressOfInferredValue):
(JSC::VariableWatchpointSet::notifyWrite): Deleted.

  • bytecode/VariableWatchpointSetInlines.h: Added.

(JSC::VariableWatchpointSet::notifyWrite):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::cellConstant):

  • Added an assert in case we try to make constants of zombified JSCells again.
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • We now let the slow path handle the cases when the VariableWatchpointSet is in state ClearWatchpoint and IsWatched, and the slow path will ensure that we handle the needed write barrier semantics correctly. We will by-pass the slow path if the value being written is the same as the inferred value.
  • ftl/FTLIntrinsicRepository.h:
  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::compileNotifyWrite):

  • Let the slow path handle the cases when the VariableWatchpointSet is in state ClearWatchpoint and IsWatched. We will by-pass the slow path if the value being written is the same as the inferred value.
  • heap/Heap.cpp:

(JSC::Zombify::operator()):

  • Use a different value for the zombified bits (to distinguish it from 0xbbadbeef which is used everywhere else).
  • heap/Heap.h:

(JSC::Heap::isZombified):

  • Provide a convenience test function to check if JSCells are zombified. This is currently only used in an assertion in the DFG bytecode parser, but the intent it that we'll apply this test in other strategic places later to help with early detection of usage of GC'ed objects when we run in zombie mode.
  • jit/JITOpcodes.cpp:

(JSC::JIT::emitSlow_op_captured_mov):

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

(JSC::JIT::emitNotifyWrite):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emitNotifyWrite):
(JSC::JIT::emitSlow_op_put_to_scope):

  • Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet is in state ClearWatchpoint and IsWatched. We will by-pass the slow path if the value being written is the same as the inferred value.


  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet is in state ClearWatchpoint and IsWatched. We will by-pass the slow path if the value being written is the same as the inferred value.


  • runtime/CommonSlowPaths.cpp:
  • runtime/JSCJSValue.h: Fixed some typos in the comments.
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::addGlobalVar):
(JSC::JSGlobalObject::addFunction):

  • runtime/JSSymbolTableObject.h:

(JSC::symbolTablePut):
(JSC::symbolTablePutWithAttributes):

  • runtime/SymbolTable.cpp:

(JSC::SymbolTableEntry::prepareToWatch):
(JSC::SymbolTableEntry::notifyWriteSlow):

  • runtime/SymbolTable.h:

(JSC::SymbolTableEntry::notifyWrite):

Location:
trunk/Source/JavaScriptCore
Files:
1 added
26 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r168406 r168443  
     12014-05-07  Mark Lam  <mark.lam@apple.com>
     2
     3        REGRESSION(r166678): Dromaeo/cssquery-dojo.html crashes regularly.
     4        <https://webkit.org/b/131356>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        The issue is that GC needs to be made aware of writes to m_inferredValue
     9        in the VariableWatchpointSet, but was not.  As a result, if a JSCell*
     10        is written to a VariableWatchpointSet m_inferredValue, and that JSCell
     11        does not survive an eden GC shortly after, we will end up with a stale
     12        JSCell pointer left in the m_inferredValue.
     13
     14        This issue can be detected more easily by running Dromaeo/cssquery-dojo.html
     15        using DumpRenderTree with the VM heap in zombie mode.
     16
     17        The fix is to change VariableWatchpointSet m_inferredValue to type
     18        WriteBarrier<Unknown> and ensure that VariableWatchpointSet::notifyWrite()
     19        is executed by all the execution engines so that the WriteBarrier semantics
     20        are honored.
     21
     22        We still check if the value to be written is the same as the one in the
     23        inferredValue.  We'll by-pass calling the slow path notifyWrite() if the
     24        values are the same.       
     25
     26        * JavaScriptCore.xcodeproj/project.pbxproj:
     27        * bytecode/CodeBlock.cpp:
     28        (JSC::CodeBlock::CodeBlock):
     29        - need to pass the symbolTable to prepareToWatch() because it will be needed
     30          for instantiating the VariableWatchpointSet in prepareToWatch().
     31
     32        * bytecode/VariableWatchpointSet.h:
     33        (JSC::VariableWatchpointSet::VariableWatchpointSet):
     34        - VariableWatchpointSet now tracks its owner symbol table for its m_inferredValue
     35          write barrier, and yes, m_inferredValue is now of type WriteBarrier<Unknown>.
     36        (JSC::VariableWatchpointSet::inferredValue):
     37        (JSC::VariableWatchpointSet::invalidate):
     38        (JSC::VariableWatchpointSet::finalizeUnconditionally):
     39        (JSC::VariableWatchpointSet::addressOfInferredValue):
     40        (JSC::VariableWatchpointSet::notifyWrite): Deleted.
     41        * bytecode/VariableWatchpointSetInlines.h: Added.
     42        (JSC::VariableWatchpointSet::notifyWrite):
     43
     44        * dfg/DFGByteCodeParser.cpp:
     45        (JSC::DFG::ByteCodeParser::cellConstant):
     46        - Added an assert in case we try to make constants of zombified JSCells again.
     47
     48        * dfg/DFGOperations.cpp:
     49        * dfg/DFGOperations.h:
     50        * dfg/DFGSpeculativeJIT.h:
     51        (JSC::DFG::SpeculativeJIT::callOperation):
     52        * dfg/DFGSpeculativeJIT32_64.cpp:
     53        (JSC::DFG::SpeculativeJIT::compile):
     54        * dfg/DFGSpeculativeJIT64.cpp:
     55        (JSC::DFG::SpeculativeJIT::compile):
     56        - We now let the slow path handle the cases when the VariableWatchpointSet is
     57          in state ClearWatchpoint and IsWatched, and the slow path will ensure that
     58          we handle the needed write barrier semantics correctly.
     59          We will by-pass the slow path if the value being written is the same as the
     60          inferred value.
     61
     62        * ftl/FTLIntrinsicRepository.h:
     63        * ftl/FTLLowerDFGToLLVM.cpp:
     64        (JSC::FTL::LowerDFGToLLVM::compileNotifyWrite):
     65        - Let the slow path handle the cases when the VariableWatchpointSet is
     66          in state ClearWatchpoint and IsWatched.
     67          We will by-pass the slow path if the value being written is the same as the
     68          inferred value.
     69
     70        * heap/Heap.cpp:
     71        (JSC::Zombify::operator()):
     72        - Use a different value for the zombified bits (to distinguish it from 0xbbadbeef
     73          which is used everywhere else).
     74        * heap/Heap.h:
     75        (JSC::Heap::isZombified):
     76        - Provide a convenience test function to check if JSCells are zombified.  This is
     77          currently only used in an assertion in the DFG bytecode parser, but the intent
     78          it that we'll apply this test in other strategic places later to help with early
     79          detection of usage of GC'ed objects when we run in zombie mode.
     80
     81        * jit/JITOpcodes.cpp:
     82        (JSC::JIT::emitSlow_op_captured_mov):
     83        * jit/JITOperations.h:
     84        * jit/JITPropertyAccess.cpp:
     85        (JSC::JIT::emitNotifyWrite):
     86        * jit/JITPropertyAccess32_64.cpp:
     87        (JSC::JIT::emitNotifyWrite):
     88        (JSC::JIT::emitSlow_op_put_to_scope):
     89        - Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet
     90          is in state ClearWatchpoint and IsWatched.
     91          We will by-pass the slow path if the value being written is the same as the
     92          inferred value.
     93       
     94        * llint/LowLevelInterpreter32_64.asm:
     95        * llint/LowLevelInterpreter64.asm:
     96        - Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet
     97          is in state ClearWatchpoint and IsWatched.
     98          We will by-pass the slow path if the value being written is the same as the
     99          inferred value.
     100       
     101        * runtime/CommonSlowPaths.cpp:
     102
     103        * runtime/JSCJSValue.h: Fixed some typos in the comments.
     104        * runtime/JSGlobalObject.cpp:
     105        (JSC::JSGlobalObject::addGlobalVar):
     106        (JSC::JSGlobalObject::addFunction):
     107        * runtime/JSSymbolTableObject.h:
     108        (JSC::symbolTablePut):
     109        (JSC::symbolTablePutWithAttributes):
     110        * runtime/SymbolTable.cpp:
     111        (JSC::SymbolTableEntry::prepareToWatch):
     112        (JSC::SymbolTableEntry::notifyWriteSlow):
     113        * runtime/SymbolTable.h:
     114        (JSC::SymbolTableEntry::notifyWrite):
     115
    11162014-05-06  Michael Saboff  <msaboff@apple.com>
    2117
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r168178 r168443  
    17091709                FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */; };
    17101710                FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4A331E15BD2E07006F54F3 /* VMInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1711                FE5248F9191442D900B7FDE4 /* VariableWatchpointSetInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5248F8191442D900B7FDE4 /* VariableWatchpointSetInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
    17111712                FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */; };
    17121713                FE5932A8183C5A2600A1ECCC /* VMEntryScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    33343335                FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMInspector.cpp; sourceTree = "<group>"; };
    33353336                FE4A331E15BD2E07006F54F3 /* VMInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMInspector.h; sourceTree = "<group>"; };
     3337                FE5248F8191442D900B7FDE4 /* VariableWatchpointSetInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableWatchpointSetInlines.h; sourceTree = "<group>"; };
    33363338                FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMEntryScope.cpp; sourceTree = "<group>"; };
    33373339                FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMEntryScope.h; sourceTree = "<group>"; };
     
    50305032                                0F426A451460CBAB00131F8F /* ValueRecovery.h */,
    50315033                                0F9181C618415CA50057B669 /* VariableWatchpointSet.h */,
     5034                                FE5248F8191442D900B7FDE4 /* VariableWatchpointSetInlines.h */,
    50325035                                0F426A461460CBAB00131F8F /* VirtualRegister.h */,
    50335036                                0F919D2215853CDE004A4E7D /* Watchpoint.cpp */,
     
    54925495                                A584032018BFFBE1005A0811 /* InspectorAgent.h in Headers */,
    54935496                                2AABCDE718EF294200002096 /* GCLogging.h in Headers */,
     5497                                FE5248F9191442D900B7FDE4 /* VariableWatchpointSetInlines.h in Headers */,
    54945498                                C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */,
    54955499                                2AACE63D18CA5A0300ED0191 /* GCActivityCallback.h in Headers */,
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r168189 r168443  
    17941794            SymbolTable::Map::iterator iter = m_symbolTable->find(locker, uid);
    17951795            ASSERT(iter != m_symbolTable->end(locker));
    1796             iter->value.prepareToWatch();
     1796            iter->value.prepareToWatch(symbolTable());
    17971797            instructions[i + 3].u.watchpointSet = iter->value.watchpointSet();
    17981798            break;
  • trunk/Source/JavaScriptCore/bytecode/VariableWatchpointSet.h

    r160109 r168443  
    11/*
    2  * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012-2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3232namespace JSC {
    3333
     34class SymbolTable;
     35
    3436class VariableWatchpointSet : public WatchpointSet {
    3537    friend class LLIntOffsetsExtractor;
    3638public:
    37     VariableWatchpointSet()
     39    VariableWatchpointSet(SymbolTable& symbolTable)
    3840        : WatchpointSet(ClearWatchpoint)
     41        , m_symbolTable(symbolTable)
    3942    {
    4043    }
     
    5356    //        either notice that it's invalidated and not install the watchpoint, or
    5457    //        you will have been notified that the watchpoint was fired.
    55     JSValue inferredValue() const { return m_inferredValue; }
     58    JSValue inferredValue() const { return m_inferredValue.get(); }
    5659   
    57     void notifyWrite(JSValue value)
    58     {
    59         ASSERT(!!value);
    60         switch (state()) {
    61         case ClearWatchpoint:
    62             m_inferredValue = value;
    63             startWatching();
    64             return;
    65 
    66         case IsWatched:
    67             ASSERT(!!m_inferredValue);
    68             if (value == m_inferredValue)
    69                 return;
    70             invalidate();
    71             return;
    72            
    73         case IsInvalidated:
    74             ASSERT(!m_inferredValue);
    75             return;
    76         }
    77        
    78         ASSERT_NOT_REACHED();
    79     }
     60    inline void notifyWrite(VM&, JSValue);
    8061   
    8162    void invalidate()
    8263    {
    83         m_inferredValue = JSValue();
     64        m_inferredValue.clear();
    8465        WatchpointSet::invalidate();
    8566    }
     
    9071        if (!m_inferredValue)
    9172            return;
    92         if (!m_inferredValue.isCell())
     73        JSValue inferredValue = m_inferredValue.get();
     74        if (!inferredValue.isCell())
    9375            return;
    94         JSCell* cell = m_inferredValue.asCell();
     76        JSCell* cell = inferredValue.asCell();
    9577        if (Heap::isMarked(cell))
    9678            return;
    9779        invalidate();
    9880    }
     81
     82    WriteBarrier<Unknown>* addressOfInferredValue() { return &m_inferredValue; }
    9983   
    100     JSValue* addressOfInferredValue() { return &m_inferredValue; }
    101 
    10284private:
    103     JSValue m_inferredValue;
     85    SymbolTable& m_symbolTable;
     86    WriteBarrier<Unknown> m_inferredValue;
    10487};
    10588
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r168172 r168443  
    3737#include "DFGJITCode.h"
    3838#include "GetByIdStatus.h"
     39#include "Heap.h"
    3940#include "JSActivation.h"
    4041#include "JSCInlines.h"
     
    721722    {
    722723        HashMap<JSCell*, Node*>::AddResult result = m_cellConstantNodes.add(cell, nullptr);
    723         if (result.isNewEntry)
     724        if (result.isNewEntry) {
     725            ASSERT(!Heap::isZombified(cell));
    724726            result.iterator->value = addToGraph(WeakJSConstant, OpInfo(cell));
     727        }
    725728       
    726729        return result.iterator->value;
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r168335 r168443  
    10191019}
    10201020
    1021 void JIT_OPERATION operationInvalidate(ExecState* exec, VariableWatchpointSet* set)
    1022 {
    1023     VM& vm = exec->vm();
    1024     NativeCallFrameTracer tracer(&vm, exec);
    1025 
    1026     set->invalidate();
     1021void JIT_OPERATION operationNotifyWrite(ExecState* exec, VariableWatchpointSet* set, EncodedJSValue encodedValue)
     1022{
     1023    VM& vm = exec->vm();
     1024    NativeCallFrameTracer tracer(&vm, exec);
     1025    JSValue value = JSValue::decode(encodedValue);
     1026
     1027    set->notifyWrite(vm, value);
    10271028}
    10281029
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r163765 r168443  
    125125char* JIT_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex);
    126126char* JIT_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*);
    127 void JIT_OPERATION operationInvalidate(ExecState*, VariableWatchpointSet*);
     127void JIT_OPERATION operationNotifyWrite(ExecState*, VariableWatchpointSet*, EncodedJSValue);
    128128
    129129#if ENABLE(FTL_JIT)
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r167591 r168443  
    11451145    }
    11461146
    1147     JITCompiler::Call callOperation(V_JITOperation_EVws operation, VariableWatchpointSet* watchpointSet)
    1148     {
    1149         m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet));
    1150         return appendCall(operation);
    1151     }
    1152 
    11531147    JITCompiler::Call callOperationWithCallFrameRollbackOnException(V_JITOperation_ECb operation, void* pointer)
    11541148    {
     
    14381432        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
    14391433        return appendCallWithExceptionCheck(operation);
     1434    }
     1435
     1436    JITCompiler::Call callOperation(V_JITOperation_EVwsJ operation, VariableWatchpointSet* watchpointSet, GPRReg arg)
     1437    {
     1438        m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet), arg);
     1439        return appendCall(operation);
    14401440    }
    14411441
     
    17031703        m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG SH4_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
    17041704        return appendCallWithExceptionCheck(operation);
     1705    }
     1706
     1707    JITCompiler::Call callOperation(V_JITOperation_EVwsJ operation, VariableWatchpointSet* watchpointSet, GPRReg argTag, GPRReg argPayload)
     1708    {
     1709        m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet), argPayload, argTag);
     1710        return appendCall(operation);
    17051711    }
    17061712
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r168051 r168443  
    38993899        m_jit.load8(set->addressOfState(), tempGPR);
    39003900   
    3901         JITCompiler::JumpList ready;
    3902    
    3903         ready.append(m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)));
    3904    
    3905         if (set->state() == ClearWatchpoint) {
    3906             JITCompiler::Jump isWatched =
    3907                 m_jit.branch32(JITCompiler::NotEqual, tempGPR, TrustedImm32(ClearWatchpoint));
    3908        
    3909             m_jit.store32(valueTagGPR, &set->addressOfInferredValue()->u.asBits.tag);
    3910             m_jit.store32(valuePayloadGPR, &set->addressOfInferredValue()->u.asBits.payload);
    3911             m_jit.store8(TrustedImm32(IsWatched), set->addressOfState());
    3912             ready.append(m_jit.jump());
    3913        
    3914             isWatched.link(&m_jit);
    3915         }
    3916 
    3917         JITCompiler::Jump definitelyNotEqual = m_jit.branch32(
     3901        JITCompiler::Jump isDone = m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated));
     3902        JITCompiler::JumpList notifySlow;
     3903        notifySlow.append(m_jit.branch32(
    39183904            JITCompiler::NotEqual,
    3919             JITCompiler::AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.payload),
    3920             valuePayloadGPR);
    3921         ready.append(m_jit.branch32(
    3922             JITCompiler::Equal,
    3923             JITCompiler::AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.tag),
     3905            JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->payloadPointer()),
     3906            valuePayloadGPR));
     3907        notifySlow.append(m_jit.branch32(
     3908            JITCompiler::NotEqual,
     3909            JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->tagPointer()),
    39243910            valueTagGPR));
    3925         definitelyNotEqual.link(&m_jit);
    3926    
    3927         JITCompiler::Jump slowCase = m_jit.branchTest8(
    3928             JITCompiler::NonZero, JITCompiler::AbsoluteAddress(set->addressOfSetIsNotEmpty()));
    3929         m_jit.store8(TrustedImm32(IsInvalidated), set->addressOfState());
    3930         m_jit.store32(
    3931             TrustedImm32(JSValue::EmptyValueTag),
    3932             &set->addressOfInferredValue()->u.asBits.tag);
    3933         m_jit.store32(
    3934             TrustedImm32(0), &set->addressOfInferredValue()->u.asBits.payload);
    3935 
    3936         ready.link(&m_jit);
    3937    
    39383911        addSlowPathGenerator(
    3939             slowPathCall(slowCase, this, operationInvalidate, NoResult, set));
     3912            slowPathCall(notifySlow, this, operationNotifyWrite, NoResult, set, valueTagGPR, valuePayloadGPR));
     3913        isDone.link(&m_jit);
    39403914   
    39413915        noResult(node);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r168051 r168443  
    39633963        m_jit.load8(set->addressOfState(), tempGPR);
    39643964   
    3965         JITCompiler::JumpList ready;
    3966    
    3967         ready.append(m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)));
    3968    
    3969         if (set->state() == ClearWatchpoint) {
    3970             JITCompiler::Jump isWatched =
    3971                 m_jit.branch32(JITCompiler::NotEqual, tempGPR, TrustedImm32(ClearWatchpoint));
    3972        
    3973             m_jit.store64(valueGPR, set->addressOfInferredValue());
    3974             m_jit.store8(TrustedImm32(IsWatched), set->addressOfState());
    3975             ready.append(m_jit.jump());
    3976        
    3977             isWatched.link(&m_jit);
    3978         }
    3979    
    3980         ready.append(m_jit.branch64(
    3981             JITCompiler::Equal,
    3982             JITCompiler::AbsoluteAddress(set->addressOfInferredValue()), valueGPR));
    3983    
    3984         JITCompiler::Jump slowCase = m_jit.branchTest8(
    3985             JITCompiler::NonZero, JITCompiler::AbsoluteAddress(set->addressOfSetIsNotEmpty()));
    3986         m_jit.store8(TrustedImm32(IsInvalidated), set->addressOfState());
    3987         m_jit.move(TrustedImm64(JSValue::encode(JSValue())), tempGPR);
    3988         m_jit.store64(tempGPR, set->addressOfInferredValue());
    3989 
    3990         ready.link(&m_jit);
     3965        JITCompiler::Jump isDone =
     3966            m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated));
     3967        JITCompiler::Jump slowCase = m_jit.branch64(JITCompiler::NotEqual,
     3968            JITCompiler::AbsoluteAddress(set->addressOfInferredValue()), valueGPR);
     3969        isDone.link(&m_jit);
    39913970   
    39923971        addSlowPathGenerator(
    3993             slowPathCall(slowCase, this, operationInvalidate, NoResult, set));
    3994    
     3972            slowPathCall(slowCase, this, operationNotifyWrite, NoResult, set, valueGPR));
     3973
    39953974        noResult(node);
    39963975        break;
  • trunk/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h

    r167392 r168443  
    8888    macro(V_JITOperation_EC, functionType(voidType, intPtr, intPtr)) \
    8989    macro(V_JITOperation_ECb, functionType(voidType, intPtr, intPtr)) \
    90     macro(V_JITOperation_EVws, functionType(voidType, intPtr, intPtr)) \
     90    macro(V_JITOperation_EVwsJ, functionType(voidType, intPtr, intPtr, int64)) \
    9191    macro(Z_JITOperation_D, functionType(int32, doubleType))
    9292
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r167612 r168443  
    32873287       
    32883288        LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyWrite not invalidated case"));
    3289         LBasicBlock isClear = FTL_NEW_BLOCK(m_out, ("NotifyWrite clear case"));
    3290         LBasicBlock isWatched = FTL_NEW_BLOCK(m_out, ("NotifyWrite watched case"));
    3291         LBasicBlock invalidate = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate case"));
    3292         LBasicBlock invalidateFast = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate fast case"));
    3293         LBasicBlock invalidateSlow = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate slow case"));
     3289        LBasicBlock notifySlow = FTL_NEW_BLOCK(m_out, ("NotifyWrite notify slow case"));
    32943290        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyWrite continuation"));
    32953291       
     
    33003296            usually(continuation), rarely(isNotInvalidated));
    33013297       
    3302         LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, isClear);
    3303 
    3304         LValue isClearValue;
    3305         if (set->state() == ClearWatchpoint)
    3306             isClearValue = m_out.equal(state, m_out.constInt8(ClearWatchpoint));
    3307         else
    3308             isClearValue = m_out.booleanFalse;
    3309         m_out.branch(isClearValue, unsure(isClear), unsure(isWatched));
    3310        
    3311         m_out.appendTo(isClear, isWatched);
    3312        
    3313         m_out.store64(value, m_out.absolute(set->addressOfInferredValue()));
    3314         m_out.store8(m_out.constInt8(IsWatched), m_out.absolute(set->addressOfState()));
    3315         m_out.jump(continuation);
    3316        
    3317         m_out.appendTo(isWatched, invalidate);
    3318        
     3298        LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, notifySlow);
     3299
    33193300        m_out.branch(
    33203301            m_out.equal(value, m_out.load64(m_out.absolute(set->addressOfInferredValue()))),
    3321             unsure(continuation), unsure(invalidate));
    3322        
    3323         m_out.appendTo(invalidate, invalidateFast);
    3324        
    3325         m_out.branch(
    3326             m_out.notZero8(m_out.load8(m_out.absolute(set->addressOfSetIsNotEmpty()))),
    3327             rarely(invalidateSlow), usually(invalidateFast));
    3328        
    3329         m_out.appendTo(invalidateFast, invalidateSlow);
    3330        
    3331         m_out.store64(
    3332             m_out.constInt64(JSValue::encode(JSValue())),
    3333             m_out.absolute(set->addressOfInferredValue()));
    3334         m_out.store8(m_out.constInt8(IsInvalidated), m_out.absolute(set->addressOfState()));
    3335         m_out.jump(continuation);
    3336        
    3337         m_out.appendTo(invalidateSlow, continuation);
    3338        
    3339         vmCall(m_out.operation(operationInvalidate), m_callFrame, m_out.constIntPtr(set));
     3302            unsure(continuation), unsure(notifySlow));
     3303
     3304        m_out.appendTo(notifySlow, continuation);
     3305
     3306        vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set), value);
    33403307        m_out.jump(continuation);
    33413308       
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r167948 r168443  
    13341334        void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + MarkedBlock::blockFor(cell)->cellSize());
    13351335        for (; current < limit; current++)
    1336             *current = reinterpret_cast<void*>(0xbbadbeef);
     1336            *current = zombifiedBits;
    13371337    }
    13381338};
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r167897 r168443  
    22 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    33 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
    4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
     4 *  Copyright (C) 2003-2009, 2013-2014 Apple Inc. All rights reserved.
    55 *
    66 *  This library is free software; you can redistribute it and/or
     
    7474}
    7575
     76static void* const zombifiedBits = reinterpret_cast<void*>(0xdeadbeef);
     77
    7678typedef std::pair<JSValue, WTF::String> ValueStringPair;
    7779typedef HashCountedSet<JSCell*> ProtectCountSet;
     
    219221
    220222    void removeCodeBlock(CodeBlock* cb) { m_codeBlocks.remove(cb); }
     223
     224    static bool isZombified(JSCell* cell) { return *(void**)cell == zombifiedBits; }
    221225
    222226private:
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r167646 r168443  
    12031203    if (!set || set->state() == IsInvalidated)
    12041204        return;
     1205#if USE(JSVALUE32_64)
     1206    linkSlowCase(iter);
     1207#endif
    12051208    linkSlowCase(iter);
    12061209    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_captured_mov);
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r166135 r168443  
    11/*
    2  * Copyright (C) 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    165165typedef void JIT_OPERATION (*V_JITOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue);
    166166typedef void JIT_OPERATION (*V_JITOperation_ESsiJJI)(ExecState*, StructureStubInfo*, EncodedJSValue, EncodedJSValue, StringImpl*);
    167 typedef void JIT_OPERATION (*V_JITOperation_EVws)(ExecState*, VariableWatchpointSet*);
     167typedef void JIT_OPERATION (*V_JITOperation_EVwsJ)(ExecState*, VariableWatchpointSet*, EncodedJSValue);
    168168typedef void JIT_OPERATION (*V_JITOperation_EZ)(ExecState*, int32_t);
    169169typedef void JIT_OPERATION (*V_JITOperation_EVm)(ExecState*, VM*);
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r167394 r168443  
    780780   
    781781    load8(set->addressOfState(), scratch);
    782    
    783     JumpList ready;
    784    
    785     ready.append(branch32(Equal, scratch, TrustedImm32(IsInvalidated)));
    786    
    787     if (set->state() == ClearWatchpoint) {
    788         Jump isWatched = branch32(NotEqual, scratch, TrustedImm32(ClearWatchpoint));
    789        
    790         store64(value, set->addressOfInferredValue());
    791         store8(TrustedImm32(IsWatched), set->addressOfState());
    792         ready.append(jump());
    793        
    794         isWatched.link(this);
    795     }
    796    
    797     ready.append(branch64(Equal, AbsoluteAddress(set->addressOfInferredValue()), value));
    798     addSlowCase(branchTest8(NonZero, AbsoluteAddress(set->addressOfSetIsNotEmpty())));
    799     store8(TrustedImm32(IsInvalidated), set->addressOfState());
    800     move(TrustedImm64(JSValue::encode(JSValue())), scratch);
    801     store64(scratch, set->addressOfInferredValue());
    802    
    803     ready.link(this);
     782    Jump isDone = branch32(Equal, scratch, TrustedImm32(IsInvalidated));
     783    addSlowCase(branch64(NotEqual, AbsoluteAddress(set->addressOfInferredValue()), value));
     784    isDone.link(this);
    804785}
    805786
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r167288 r168443  
    813813   
    814814    load8(set->addressOfState(), scratch);
    815    
    816     JumpList ready;
    817    
    818     ready.append(branch32(Equal, scratch, TrustedImm32(IsInvalidated)));
    819    
    820     if (set->state() == ClearWatchpoint) {
    821         Jump isWatched = branch32(NotEqual, scratch, TrustedImm32(ClearWatchpoint));
    822        
    823         store32(tag, &set->addressOfInferredValue()->u.asBits.tag);
    824         store32(payload, &set->addressOfInferredValue()->u.asBits.payload);
    825         store8(TrustedImm32(IsWatched), set->addressOfState());
    826         ready.append(jump());
    827        
    828         isWatched.link(this);
    829     }
    830 
    831     Jump definitelyNotEqual = branch32(
    832         NotEqual, AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.payload), payload);
    833     ready.append(branch32(
    834         Equal, AbsoluteAddress(&set->addressOfInferredValue()->u.asBits.tag), tag));
    835     definitelyNotEqual.link(this);
    836     addSlowCase(branchTest8(NonZero, AbsoluteAddress(set->addressOfSetIsNotEmpty())));
    837     store8(TrustedImm32(IsInvalidated), set->addressOfState());
    838     store32(
    839         TrustedImm32(JSValue::EmptyValueTag), &set->addressOfInferredValue()->u.asBits.tag);
    840     store32(TrustedImm32(0), &set->addressOfInferredValue()->u.asBits.payload);
    841    
    842     ready.link(this);
     815    Jump isDone = branch32(Equal, scratch, TrustedImm32(IsInvalidated));
     816
     817    JumpList notifySlow = branch32(
     818        NotEqual, AbsoluteAddress(set->addressOfInferredValue()->payloadPointer()), payload);
     819    notifySlow.append(branch32(
     820        NotEqual, AbsoluteAddress(set->addressOfInferredValue()->tagPointer()), tag));
     821    addSlowCase(notifySlow);
     822
     823    isDone.link(this);
    843824}
    844825
     
    901882    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks)
    902883        && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
    903         linkCount++;
     884        linkCount += 2;
    904885    if (!linkCount)
    905886        return;
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r167127 r168443  
    797797    loadb VariableWatchpointSet::m_state[set], scratch
    798798    bieq scratch, IsInvalidated, .done
    799     bineq scratch, ClearWatchpoint, .overwrite
    800     storei valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set]
    801     storei valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set]
    802     storeb IsWatched, VariableWatchpointSet::m_state[set]
    803     jmp .done
    804 
    805 .overwrite:
    806     bineq valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set], .definitelyDifferent
    807     bieq valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set], .done
    808 .definitelyDifferent:
    809     btbnz VariableWatchpointSet::m_setIsNotEmpty[set], slow
    810     storei EmptyValueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set]
    811     storei 0, VariableWatchpointSet::m_inferredValue + PayloadOffset[set]
    812     storeb IsInvalidated, VariableWatchpointSet::m_state[set]
    813 
     799    bineq valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set], slow
     800    bineq valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set], slow
    814801.done:
    815802end
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r167031 r168443  
    657657    loadb VariableWatchpointSet::m_state[set], scratch
    658658    bieq scratch, IsInvalidated, .done
    659     bineq scratch, ClearWatchpoint, .overwrite
    660     storeq value, VariableWatchpointSet::m_inferredValue[set]
    661     storeb IsWatched, VariableWatchpointSet::m_state[set]
    662     jmp .done
    663 
    664 .overwrite:
    665     bqeq value, VariableWatchpointSet::m_inferredValue[set], .done
    666     btbnz VariableWatchpointSet::m_setIsNotEmpty[set], slow
    667     storeq 0, VariableWatchpointSet::m_inferredValue[set]
    668     storeb IsInvalidated, VariableWatchpointSet::m_state[set]
    669 
    670 .done:   
     659    bqneq value, VariableWatchpointSet::m_inferredValue[set], slow
     660.done:
    671661end
    672662
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r164764 r168443  
    5454#include "JSCInlines.h"
    5555#include "StructureRareDataInlines.h"
     56#include "VariableWatchpointSetInlines.h"
    5657#include <wtf/StringPrintStream.h>
    5758
     
    263264    JSValue value = OP_C(2).jsValue();
    264265    if (VariableWatchpointSet* set = pc[3].u.watchpointSet)
    265         set->notifyWrite(value);
     266        set->notifyWrite(vm, value);
    266267    RETURN(value);
    267268}
     
    274275    JSValue value = JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope());
    275276    if (VariableWatchpointSet* set = pc[3].u.watchpointSet)
    276         set->notifyWrite(value);
     277        set->notifyWrite(vm, value);
    277278    RETURN(value);
    278279}
  • trunk/Source/JavaScriptCore/runtime/JSCJSValue.h

    r167394 r168443  
    334334     * This range of NaN space is represented by 64-bit numbers begining with the 16-bit
    335335     * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
    336      * numbers will begin fall in these ranges.
     336     * numbers will fall in these ranges.
    337337     *
    338338     * The top 16-bits denote the type of the encoded JSValue:
     
    348348     * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF.
    349349     * Values must be decoded by reversing this operation before subsequent floating point
    350      * operations my be peformed.
     350     * operations may be peformed.
    351351     *
    352352     * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r167313 r168443  
    11/*
    2  * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008, 2009, 2014 Apple Inc. All rights reserved.
    33 * Copyright (C) 2008 Cameron Zwarich (cwzwarich@uwaterloo.ca)
    44 *
     
    116116#include "StringConstructor.h"
    117117#include "StringPrototype.h"
     118#include "VariableWatchpointSetInlines.h"
    118119#include "WeakMapConstructor.h"
    119120#include "WeakMapPrototype.h"
     
    243244    SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0);
    244245    if (constantMode == IsVariable)
    245         newEntry.prepareToWatch();
     246        newEntry.prepareToWatch(symbolTable());
    246247    SymbolTable::Map::AddResult result = symbolTable()->add(locker, ident.impl(), newEntry);
    247248    if (result.isNewEntry)
     
    257258void JSGlobalObject::addFunction(ExecState* exec, const Identifier& propertyName, JSValue value)
    258259{
    259     removeDirect(exec->vm(), propertyName); // Newly declared functions overwrite existing properties.
     260    VM& vm = exec->vm();
     261    removeDirect(vm, propertyName); // Newly declared functions overwrite existing properties.
    260262    NewGlobalVar var = addGlobalVar(propertyName, IsVariable);
    261263    registerAt(var.registerNumber).set(exec->vm(), this, value);
    262264    if (var.set)
    263         var.set->notifyWrite(value);
     265        var.set->notifyWrite(vm, value);
    264266}
    265267
  • trunk/Source/JavaScriptCore/runtime/JSSymbolTableObject.h

    r165676 r168443  
    11/*
    2  * Copyright (C) 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3333#include "PropertyDescriptor.h"
    3434#include "SymbolTable.h"
     35#include "VariableWatchpointSetInlines.h"
    3536
    3637namespace JSC {
     
    139140        }
    140141        if (VariableWatchpointSet* set = iter->value.watchpointSet())
    141             set->notifyWrite(value);
     142            set->notifyWrite(vm, value);
    142143        reg = &object->registerAt(fastEntry.getIndex());
    143144    }
     
    166167        ASSERT(!entry.isNull());
    167168        if (VariableWatchpointSet* set = entry.watchpointSet())
    168             set->notifyWrite(value);
     169            set->notifyWrite(vm, value);
    169170        entry.setAttributes(attributes);
    170171        reg = &object->registerAt(entry.getIndex());
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.cpp

    r165676 r168443  
    11/*
    2  * Copyright (C) 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3333#include "JSCInlines.h"
    3434#include "SlotVisitorInlines.h"
     35#include "VariableWatchpointSetInlines.h"
    3536
    3637namespace JSC {
     
    6667}
    6768
    68 void SymbolTableEntry::prepareToWatch()
     69void SymbolTableEntry::prepareToWatch(SymbolTable* symbolTable)
    6970{
    7071    FatEntry* entry = inflate();
    7172    if (entry->m_watchpoints)
    7273        return;
    73     entry->m_watchpoints = adoptRef(new VariableWatchpointSet());
     74    entry->m_watchpoints = adoptRef(new VariableWatchpointSet(*symbolTable));
    7475}
    7576
     
    7980}
    8081
    81 void SymbolTableEntry::notifyWriteSlow(JSValue value)
     82void SymbolTableEntry::notifyWriteSlow(VM& vm, JSValue value)
    8283{
    8384    VariableWatchpointSet* watchpoints = fatEntry()->m_watchpoints.get();
     
    8586        return;
    8687   
    87     watchpoints->notifyWrite(value);
     88    watchpoints->notifyWrite(vm, value);
    8889}
    8990
  • trunk/Source/JavaScriptCore/runtime/SymbolTable.h

    r167641 r168443  
    11/*
    2  * Copyright (C) 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008, 2012-2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    219219    JSValue inferredValue();
    220220   
    221     void prepareToWatch();
     221    void prepareToWatch(SymbolTable*);
    222222   
    223223    void addWatchpoint(Watchpoint*);
     
    230230    }
    231231   
    232     ALWAYS_INLINE void notifyWrite(JSValue value)
     232    ALWAYS_INLINE void notifyWrite(VM& vm, JSValue value)
    233233    {
    234234        if (LIKELY(!isFat()))
    235235            return;
    236         notifyWriteSlow(value);
     236        notifyWriteSlow(vm, value);
    237237    }
    238238   
     
    258258   
    259259    SymbolTableEntry& copySlow(const SymbolTableEntry&);
    260     JS_EXPORT_PRIVATE void notifyWriteSlow(JSValue);
     260    JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue);
    261261   
    262262    bool isFat() const
Note: See TracChangeset for help on using the changeset viewer.