diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSSymbolTableObject.h')
| -rw-r--r-- | Source/JavaScriptCore/runtime/JSSymbolTableObject.h | 162 |
1 files changed, 110 insertions, 52 deletions
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h index b5b20a845..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,37 +32,47 @@ #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; 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, 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; }; @@ -72,12 +82,18 @@ inline bool symbolTableGet( { SymbolTable& symbolTable = *object->symbolTable(); ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); + 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; } @@ -87,13 +103,18 @@ inline bool symbolTableGet( { SymbolTable& symbolTable = *object->symbolTable(); ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); + 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; } @@ -104,42 +125,64 @@ inline bool symbolTableGet( { SymbolTable& symbolTable = *object->symbolTable(); ConcurrentJITLocker locker(symbolTable.m_lock); - SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName()); + 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> +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)); - + + VM& vm = exec->vm(); + 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 + 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()) { - if (shouldThrow) + if (fastEntry.isReadOnly() && !ignoreReadOnlyErrors) { + if (shouldThrowReadOnlyError) throwTypeError(exec, StrictModeReadonlyPropertyWriteError); 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(); + if (symbolTablePutMode == SymbolTablePutMode::WithAttributes) + iter->value.setAttributes(attributes); + 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 @@ -149,28 +192,43 @@ inline bool symbolTablePut( } 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) { - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); + 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; +} - 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) +{ + 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) +{ + 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 |
