diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSSymbolTableObject.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSSymbolTableObject.h | 172 |
1 files changed, 111 insertions, 61 deletions
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h index b5b20a845..366b5a012 100644 --- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,43 +26,53 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSSymbolTableObject_h -#define JSSymbolTableObject_h +#pragma once #include "JSScope.h" #include "PropertyDescriptor.h" #include "SymbolTable.h" +#include "ThrowScope.h" +#include "VariableWriteFireDetail.h" namespace JSC { class JSSymbolTableObject : public JSScope { public: typedef JSScope Base; + static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames; SymbolTable* symbolTable() const { return m_symbolTable.get(); } JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static ptrdiff_t offsetOfSymbolTable() { return OBJECT_OFFSETOF(JSSymbolTableObject, m_symbolTable); } + + DECLARE_EXPORT_INFO; + protected: - static const unsigned StructureFlags = IsEnvironmentRecord | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; + JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope) + : Base(vm, structure, scope) + { + } - JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SymbolTable* symbolTable = 0) + JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SymbolTable* symbolTable) : Base(vm, structure, scope) { - if (symbolTable) - m_symbolTable.set(vm, this, symbolTable); + ASSERT(symbolTable); + setSymbolTable(vm, symbolTable); } - - void finishCreation(VM& vm) + + void setSymbolTable(VM& vm, SymbolTable* symbolTable) { - Base::finishCreation(vm); - if (!m_symbolTable) - m_symbolTable.set(vm, this, SymbolTable::create(vm)); + ASSERT(!m_symbolTable); + symbolTable->singletonScope()->notifyWrite(vm, this, "Allocated a scope"); + m_symbolTable.set(vm, this, symbolTable); } - + static void visitChildren(JSCell*, SlotVisitor&); - + +private: WriteBarrier<SymbolTable> m_symbolTable; }; @@ -71,13 +81,19 @@ inline bool symbolTableGet( SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot) { SymbolTable& symbolTable = *object->symbolTable(); - ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); + ConcurrentJSLocker locker(symbolTable.m_lock); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); if (iter == symbolTable.end(locker)) return false; SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); - slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get()); + + ScopeOffset offset = entry.scopeOffset(); + // Defend against the inspector asking for a var after it has been optimized out. + if (!object->isValidScopeOffset(offset)) + return false; + + slot.setValue(object, entry.getAttributes() | DontDelete, object->variableAt(offset).get()); return true; } @@ -86,14 +102,19 @@ inline bool symbolTableGet( SymbolTableObjectType* object, PropertyName propertyName, PropertyDescriptor& descriptor) { SymbolTable& symbolTable = *object->symbolTable(); - ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); + ConcurrentJSLocker locker(symbolTable.m_lock); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); if (iter == symbolTable.end(locker)) return false; SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); - descriptor.setDescriptor( - object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); + + ScopeOffset offset = entry.scopeOffset(); + // Defend against the inspector asking for a var after it has been optimized out. + if (!object->isValidScopeOffset(offset)) + return false; + + descriptor.setDescriptor(object->variableAt(offset).get(), entry.getAttributes() | DontDelete); return true; } @@ -103,77 +124,106 @@ inline bool symbolTableGet( bool& slotIsWriteable) { SymbolTable& symbolTable = *object->symbolTable(); - ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); + ConcurrentJSLocker locker(symbolTable.m_lock); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); if (iter == symbolTable.end(locker)) return false; SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); - slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get()); + + ScopeOffset offset = entry.scopeOffset(); + // Defend against the inspector asking for a var after it has been optimized out. + if (!object->isValidScopeOffset(offset)) + return false; + + slot.setValue(object, entry.getAttributes() | DontDelete, object->variableAt(offset).get()); slotIsWriteable = !entry.isReadOnly(); return true; } template<typename SymbolTableObjectType> -inline bool symbolTablePut( - SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, - bool shouldThrow) +ALWAYS_INLINE void symbolTablePutTouchWatchpointSet(VM& vm, SymbolTableObjectType* object, PropertyName propertyName, JSValue value, WriteBarrierBase<Unknown>* reg, WatchpointSet* set) +{ + reg->set(vm, object, value); + if (set) + VariableWriteFireDetail::touch(vm, set, object, propertyName); +} + +template<typename SymbolTableObjectType> +ALWAYS_INLINE void symbolTablePutInvalidateWatchpointSet(VM& vm, SymbolTableObjectType* object, PropertyName propertyName, JSValue value, WriteBarrierBase<Unknown>* reg, WatchpointSet* set) +{ + reg->set(vm, object, value); + if (set) + set->invalidate(vm, VariableWriteFireDetail(object, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it. +} + +enum class SymbolTablePutMode { + Touch, + Invalidate +}; + +template<SymbolTablePutMode symbolTablePutMode, typename SymbolTableObjectType> +inline bool symbolTablePut(SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, bool& putResult) { VM& vm = exec->vm(); - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); - + auto scope = DECLARE_THROW_SCOPE(vm); + + WatchpointSet* set = nullptr; WriteBarrierBase<Unknown>* reg; { SymbolTable& symbolTable = *object->symbolTable(); - GCSafeConcurrentJITLocker locker(symbolTable.m_lock, exec->vm().heap); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); + // FIXME: This is very suspicious. We shouldn't need a GC-safe lock here. + // https://bugs.webkit.org/show_bug.cgi?id=134601 + GCSafeConcurrentJSLocker locker(symbolTable.m_lock, vm.heap); + SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid()); if (iter == symbolTable.end(locker)) return false; bool wasFat; SymbolTableEntry::Fast fastEntry = iter->value.getFast(wasFat); ASSERT(!fastEntry.isNull()); - if (fastEntry.isReadOnly()) { - if (shouldThrow) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + if (fastEntry.isReadOnly() && !ignoreReadOnlyErrors) { + if (shouldThrowReadOnlyError) + throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError)); + putResult = false; return true; } - if (VariableWatchpointSet* set = iter->value.watchpointSet()) - set->notifyWrite(value); - reg = &object->registerAt(fastEntry.getIndex()); + + ScopeOffset offset = fastEntry.scopeOffset(); + + // Defend against the inspector asking for a var after it has been optimized out. + if (!object->isValidScopeOffset(offset)) + return false; + + set = iter->value.watchpointSet(); + reg = &object->variableAt(offset); } // I'd prefer we not hold lock while executing barriers, since I prefer to reserve // the right for barriers to be able to trigger GC. And I don't want to hold VM // locks while GC'ing. - reg->set(vm, object, value); + if (symbolTablePutMode == SymbolTablePutMode::Invalidate) + symbolTablePutInvalidateWatchpointSet(vm, object, propertyName, value, reg, set); + else + symbolTablePutTouchWatchpointSet(vm, object, propertyName, value, reg, set); + putResult = true; return true; } template<typename SymbolTableObjectType> -inline bool symbolTablePutWithAttributes( - SymbolTableObjectType* object, VM& vm, PropertyName propertyName, - JSValue value, unsigned attributes) +inline bool symbolTablePutTouchWatchpointSet( + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, + bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, bool& putResult) { ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); + return symbolTablePut<SymbolTablePutMode::Touch>(object, exec, propertyName, value, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult); +} - WriteBarrierBase<Unknown>* reg; - { - SymbolTable& symbolTable = *object->symbolTable(); - ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); - if (iter == symbolTable.end(locker)) - return false; - SymbolTableEntry& entry = iter->value; - ASSERT(!entry.isNull()); - if (VariableWatchpointSet* set = entry.watchpointSet()) - set->notifyWrite(value); - entry.setAttributes(attributes); - reg = &object->registerAt(entry.getIndex()); - } - reg->set(vm, object, value); - return true; +template<typename SymbolTableObjectType> +inline bool symbolTablePutInvalidateWatchpointSet( + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, + bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, bool& putResult) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); + return symbolTablePut<SymbolTablePutMode::Invalidate>(object, exec, propertyName, value, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult); } } // namespace JSC - -#endif // JSSymbolTableObject_h - |