1/* 2 * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#ifndef JSSymbolTableObject_h 30#define JSSymbolTableObject_h 31 32#include "JSScope.h" 33#include "PropertyDescriptor.h" 34#include "SymbolTable.h" 35#include "VariableWatchpointSetInlines.h" 36 37namespace JSC { 38 39class JSSymbolTableObject : public JSScope { 40public: 41 typedef JSScope Base; 42 43 SymbolTable* symbolTable() const { return m_symbolTable.get(); } 44 45 JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); 46 JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 47 48protected: 49 static const unsigned StructureFlags = IsEnvironmentRecord | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; 50 51 JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SymbolTable* symbolTable = 0) 52 : Base(vm, structure, scope) 53 { 54 if (symbolTable) 55 m_symbolTable.set(vm, this, symbolTable); 56 } 57 58 void finishCreation(VM& vm) 59 { 60 Base::finishCreation(vm); 61 if (!m_symbolTable) 62 m_symbolTable.set(vm, this, SymbolTable::create(vm)); 63 } 64 65 static void visitChildren(JSCell*, SlotVisitor&); 66 67 WriteBarrier<SymbolTable> m_symbolTable; 68}; 69 70template<typename SymbolTableObjectType> 71inline bool symbolTableGet( 72 SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot) 73{ 74 SymbolTable& symbolTable = *object->symbolTable(); 75 ConcurrentJITLocker locker(symbolTable.m_lock); 76 SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); 77 if (iter == symbolTable.end(locker)) 78 return false; 79 SymbolTableEntry::Fast entry = iter->value; 80 ASSERT(!entry.isNull()); 81 slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get()); 82 return true; 83} 84 85template<typename SymbolTableObjectType> 86inline bool symbolTableGet( 87 SymbolTableObjectType* object, PropertyName propertyName, PropertyDescriptor& descriptor) 88{ 89 SymbolTable& symbolTable = *object->symbolTable(); 90 ConcurrentJITLocker locker(symbolTable.m_lock); 91 SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); 92 if (iter == symbolTable.end(locker)) 93 return false; 94 SymbolTableEntry::Fast entry = iter->value; 95 ASSERT(!entry.isNull()); 96 descriptor.setDescriptor( 97 object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); 98 return true; 99} 100 101template<typename SymbolTableObjectType> 102inline bool symbolTableGet( 103 SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot, 104 bool& slotIsWriteable) 105{ 106 SymbolTable& symbolTable = *object->symbolTable(); 107 ConcurrentJITLocker locker(symbolTable.m_lock); 108 SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); 109 if (iter == symbolTable.end(locker)) 110 return false; 111 SymbolTableEntry::Fast entry = iter->value; 112 ASSERT(!entry.isNull()); 113 slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get()); 114 slotIsWriteable = !entry.isReadOnly(); 115 return true; 116} 117 118template<typename SymbolTableObjectType> 119inline bool symbolTablePut( 120 SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, 121 bool shouldThrow) 122{ 123 VM& vm = exec->vm(); 124 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); 125 126 WriteBarrierBase<Unknown>* reg; 127 { 128 SymbolTable& symbolTable = *object->symbolTable(); 129 // FIXME: This is very suspicious. We shouldn't need a GC-safe lock here. 130 // https://bugs.webkit.org/show_bug.cgi?id=134601 131 GCSafeConcurrentJITLocker locker(symbolTable.m_lock, exec->vm().heap); 132 SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); 133 if (iter == symbolTable.end(locker)) 134 return false; 135 bool wasFat; 136 SymbolTableEntry::Fast fastEntry = iter->value.getFast(wasFat); 137 ASSERT(!fastEntry.isNull()); 138 if (fastEntry.isReadOnly()) { 139 if (shouldThrow) 140 throwTypeError(exec, StrictModeReadonlyPropertyWriteError); 141 return true; 142 } 143 if (VariableWatchpointSet* set = iter->value.watchpointSet()) { 144 // FIXME: It's strange that we're doing this while holding the symbol table's lock. 145 // https://bugs.webkit.org/show_bug.cgi?id=134601 146 set->notifyWrite(vm, value); 147 } 148 reg = &object->registerAt(fastEntry.getIndex()); 149 } 150 // I'd prefer we not hold lock while executing barriers, since I prefer to reserve 151 // the right for barriers to be able to trigger GC. And I don't want to hold VM 152 // locks while GC'ing. 153 reg->set(vm, object, value); 154 return true; 155} 156 157template<typename SymbolTableObjectType> 158inline bool symbolTablePutWithAttributes( 159 SymbolTableObjectType* object, VM& vm, PropertyName propertyName, 160 JSValue value, unsigned attributes) 161{ 162 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); 163 164 WriteBarrierBase<Unknown>* reg; 165 { 166 SymbolTable& symbolTable = *object->symbolTable(); 167 ConcurrentJITLocker locker(symbolTable.m_lock); 168 SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); 169 if (iter == symbolTable.end(locker)) 170 return false; 171 SymbolTableEntry& entry = iter->value; 172 ASSERT(!entry.isNull()); 173 if (VariableWatchpointSet* set = entry.watchpointSet()) 174 set->notifyWrite(vm, value); 175 entry.setAttributes(attributes); 176 reg = &object->registerAt(entry.getIndex()); 177 } 178 reg->set(vm, object, value); 179 return true; 180} 181 182} // namespace JSC 183 184#endif // JSSymbolTableObject_h 185 186