diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSSymbolTableObject.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSSymbolTableObject.h | 192 |
1 files changed, 133 insertions, 59 deletions
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h index 6db2b88ab..368cedcb8 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, 2015 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. * @@ -32,40 +32,48 @@ #include "JSScope.h" #include "PropertyDescriptor.h" #include "SymbolTable.h" +#include "VariableWriteFireDetail.h" namespace JSC { +class JSSymbolTableObject; + class JSSymbolTableObject : public JSScope { public: typedef JSScope Base; + static const unsigned StructureFlags = Base::StructureFlags | IsEnvironmentRecord | OverridesGetPropertyNames; - SharedSymbolTable* symbolTable() const { return m_symbolTable.get(); } - - static NO_RETURN_DUE_TO_CRASH void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + 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); } + 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, SharedSymbolTable* 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, SharedSymbolTable::create(vm)); + ASSERT(!m_symbolTable); + symbolTable->singletonScope()->notifyWrite(vm, this, "Allocated a scope"); + m_symbolTable.set(vm, this, symbolTable); } - + static void visitChildren(JSCell*, SlotVisitor&); - - WriteBarrier<SharedSymbolTable> m_symbolTable; + +private: + WriteBarrier<SymbolTable> m_symbolTable; }; template<typename SymbolTableObjectType> @@ -73,12 +81,19 @@ inline bool symbolTableGet( SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot) { SymbolTable& symbolTable = *object->symbolTable(); - SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); - if (iter == symbolTable.end()) + ConcurrentJITLocker 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->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; } @@ -87,13 +102,19 @@ inline bool symbolTableGet( SymbolTableObjectType* object, PropertyName propertyName, PropertyDescriptor& descriptor) { SymbolTable& symbolTable = *object->symbolTable(); - SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); - if (iter == symbolTable.end()) + ConcurrentJITLocker 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,58 +124,111 @@ inline bool symbolTableGet( bool& slotIsWriteable) { SymbolTable& symbolTable = *object->symbolTable(); - SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); - if (iter == symbolTable.end()) + ConcurrentJITLocker 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->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> +enum class SymbolTablePutMode { + WithAttributes, + WithoutAttributes +}; + +template<SymbolTablePutMode symbolTablePutMode, typename SymbolTableObjectType> inline bool symbolTablePut( - SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, - bool shouldThrow) + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes, + bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, WatchpointSet*& set) { - VM& vm = exec->vm(); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); - - SymbolTable& symbolTable = *object->symbolTable(); - SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); - if (iter == symbolTable.end()) - return false; - bool wasFat; - SymbolTableEntry::Fast fastEntry = iter->value.getFast(wasFat); - ASSERT(!fastEntry.isNull()); - if (fastEntry.isReadOnly()) { - if (shouldThrow) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return true; + + VM& vm = exec->vm(); + + WriteBarrierBase<Unknown>* reg; + { + SymbolTable& symbolTable = *object->symbolTable(); + // FIXME: This is very suspicious. We shouldn't need a GC-safe lock here. + // https://bugs.webkit.org/show_bug.cgi?id=134601 + GCSafeConcurrentJITLocker 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() && !ignoreReadOnlyErrors) { + if (shouldThrowReadOnlyError) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + return true; + } + + 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(); + if (symbolTablePutMode == SymbolTablePutMode::WithAttributes) + iter->value.setAttributes(attributes); + reg = &object->variableAt(offset); } - if (UNLIKELY(wasFat)) - iter->value.notifyWrite(); - object->registerAt(fastEntry.getIndex()).set(vm, object, value); + // 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); return true; } template<typename SymbolTableObjectType> -inline bool symbolTablePutWithAttributes( - SymbolTableObjectType* object, VM& vm, PropertyName propertyName, +inline bool symbolTablePutTouchWatchpointSet( + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, + bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors) +{ + WatchpointSet* set = nullptr; + unsigned attributes = 0; + bool result = symbolTablePut<SymbolTablePutMode::WithoutAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set); + if (set) + VariableWriteFireDetail::touch(set, object, propertyName); + return result; +} + +template<typename SymbolTableObjectType> +inline bool symbolTablePutInvalidateWatchpointSet( + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, + bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors) +{ + WatchpointSet* set = nullptr; + unsigned attributes = 0; + bool result = symbolTablePut<SymbolTablePutMode::WithoutAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set); + if (set) + set->invalidate(VariableWriteFireDetail(object, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it. + return result; +} + +template<typename SymbolTableObjectType> +inline bool symbolTablePutWithAttributesTouchWatchpointSet( + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) { - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); - - SymbolTable::iterator iter = object->symbolTable()->find(propertyName.publicName()); - if (iter == object->symbolTable()->end()) - return false; - SymbolTableEntry& entry = iter->value; - ASSERT(!entry.isNull()); - entry.notifyWrite(); - entry.setAttributes(attributes); - object->registerAt(entry.getIndex()).set(vm, object, value); - return true; + WatchpointSet* set = nullptr; + bool shouldThrowReadOnlyError = false; + bool ignoreReadOnlyErrors = true; + bool result = symbolTablePut<SymbolTablePutMode::WithAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set); + if (set) + VariableWriteFireDetail::touch(set, object, propertyName); + return result; } } // namespace JSC |