diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp')
-rw-r--r-- | Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp b/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp new file mode 100644 index 000000000..1b92412af --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp @@ -0,0 +1,368 @@ +/* + * Copyright (C) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ObjectPropertyConditionSet.h" + +#include "JSCInlines.h" +#include <wtf/ListDump.h> + +namespace JSC { + +ObjectPropertyCondition ObjectPropertyConditionSet::forObject(JSObject* object) const +{ + for (const ObjectPropertyCondition& condition : *this) { + if (condition.object() == object) + return condition; + } + return ObjectPropertyCondition(); +} + +ObjectPropertyCondition ObjectPropertyConditionSet::forConditionKind( + PropertyCondition::Kind kind) const +{ + for (const ObjectPropertyCondition& condition : *this) { + if (condition.kind() == kind) + return condition; + } + return ObjectPropertyCondition(); +} + +unsigned ObjectPropertyConditionSet::numberOfConditionsWithKind(PropertyCondition::Kind kind) const +{ + unsigned result = 0; + for (const ObjectPropertyCondition& condition : *this) { + if (condition.kind() == kind) + result++; + } + return result; +} + +bool ObjectPropertyConditionSet::hasOneSlotBaseCondition() const +{ + return numberOfConditionsWithKind(PropertyCondition::Presence) == 1; +} + +ObjectPropertyCondition ObjectPropertyConditionSet::slotBaseCondition() const +{ + ObjectPropertyCondition result; + unsigned numFound = 0; + for (const ObjectPropertyCondition& condition : *this) { + if (condition.kind() == PropertyCondition::Presence) { + result = condition; + numFound++; + } + } + RELEASE_ASSERT(numFound == 1); + return result; +} + +ObjectPropertyConditionSet ObjectPropertyConditionSet::mergedWith( + const ObjectPropertyConditionSet& other) const +{ + if (!isValid() || !other.isValid()) + return invalid(); + + Vector<ObjectPropertyCondition> result; + + if (!isEmpty()) + result.appendVector(m_data->vector); + + for (const ObjectPropertyCondition& newCondition : other) { + bool foundMatch = false; + for (const ObjectPropertyCondition& existingCondition : *this) { + if (newCondition == existingCondition) { + foundMatch = true; + continue; + } + if (!newCondition.isCompatibleWith(existingCondition)) + return invalid(); + } + if (!foundMatch) + result.append(newCondition); + } + + return create(result); +} + +bool ObjectPropertyConditionSet::structuresEnsureValidity() const +{ + if (!isValid()) + return false; + + for (const ObjectPropertyCondition& condition : *this) { + if (!condition.structureEnsuresValidity()) + return false; + } + return true; +} + +bool ObjectPropertyConditionSet::structuresEnsureValidityAssumingImpurePropertyWatchpoint() const +{ + if (!isValid()) + return false; + + for (const ObjectPropertyCondition& condition : *this) { + if (!condition.structureEnsuresValidityAssumingImpurePropertyWatchpoint()) + return false; + } + return true; +} + +bool ObjectPropertyConditionSet::needImpurePropertyWatchpoint() const +{ + for (const ObjectPropertyCondition& condition : *this) { + if (condition.validityRequiresImpurePropertyWatchpoint()) + return true; + } + return false; +} + +bool ObjectPropertyConditionSet::areStillLive() const +{ + for (const ObjectPropertyCondition& condition : *this) { + if (!condition.isStillLive()) + return false; + } + return true; +} + +void ObjectPropertyConditionSet::dumpInContext(PrintStream& out, DumpContext* context) const +{ + if (!isValid()) { + out.print("<invalid>"); + return; + } + + out.print("["); + if (m_data) + out.print(listDumpInContext(m_data->vector, context)); + out.print("]"); +} + +void ObjectPropertyConditionSet::dump(PrintStream& out) const +{ + dumpInContext(out, nullptr); +} + +namespace { + +bool verbose = false; + +ObjectPropertyCondition generateCondition( + VM& vm, JSCell* owner, JSObject* object, UniquedStringImpl* uid, PropertyCondition::Kind conditionKind) +{ + Structure* structure = object->structure(); + if (verbose) + dataLog("Creating condition ", conditionKind, " for ", pointerDump(structure), "\n"); + + ObjectPropertyCondition result; + switch (conditionKind) { + case PropertyCondition::Presence: { + unsigned attributes; + PropertyOffset offset = structure->getConcurrently(uid, attributes); + if (offset == invalidOffset) + return ObjectPropertyCondition(); + result = ObjectPropertyCondition::presence(vm, owner, object, uid, offset, attributes); + break; + } + case PropertyCondition::Absence: { + result = ObjectPropertyCondition::absence( + vm, owner, object, uid, object->structure()->storedPrototypeObject()); + break; + } + case PropertyCondition::AbsenceOfSetter: { + result = ObjectPropertyCondition::absenceOfSetter( + vm, owner, object, uid, object->structure()->storedPrototypeObject()); + break; + } + default: + RELEASE_ASSERT_NOT_REACHED(); + return ObjectPropertyCondition(); + } + + if (!result.structureEnsuresValidityAssumingImpurePropertyWatchpoint()) { + if (verbose) + dataLog("Failed to create condition: ", result, "\n"); + return ObjectPropertyCondition(); + } + + if (verbose) + dataLog("New condition: ", result, "\n"); + return result; +} + +enum Concurrency { + MainThread, + Concurrent +}; +template<typename Functor> +ObjectPropertyConditionSet generateConditions( + VM& vm, JSGlobalObject* globalObject, Structure* structure, JSObject* prototype, const Functor& functor, + Concurrency concurrency = MainThread) +{ + Vector<ObjectPropertyCondition> conditions; + + for (;;) { + if (verbose) + dataLog("Considering structure: ", pointerDump(structure), "\n"); + + if (structure->isProxy()) { + if (verbose) + dataLog("It's a proxy, so invalid.\n"); + return ObjectPropertyConditionSet::invalid(); + } + + JSValue value = structure->prototypeForLookup(globalObject); + + if (value.isNull()) { + if (!prototype) { + if (verbose) + dataLog("Reached end up prototype chain as expected, done.\n"); + break; + } + if (verbose) + dataLog("Unexpectedly reached end of prototype chain, so invalid.\n"); + return ObjectPropertyConditionSet::invalid(); + } + + JSObject* object = jsCast<JSObject*>(value); + structure = object->structure(vm); + + // Since we're accessing a prototype repeatedly, it's a good bet that it should not be + // treated as a dictionary. + if (structure->isDictionary()) { + if (concurrency == MainThread) + structure->flattenDictionaryStructure(vm, object); + else { + if (verbose) + dataLog("Cannot flatten dictionary when not on main thread, so invalid.\n"); + return ObjectPropertyConditionSet::invalid(); + } + } + + if (!functor(conditions, object)) { + if (verbose) + dataLog("Functor failed, invalid.\n"); + return ObjectPropertyConditionSet::invalid(); + } + + if (object == prototype) { + if (verbose) + dataLog("Reached desired prototype, done.\n"); + break; + } + } + + if (verbose) + dataLog("Returning conditions: ", listDump(conditions), "\n"); + return ObjectPropertyConditionSet::create(conditions); +} + +} // anonymous namespace + +ObjectPropertyConditionSet generateConditionsForPropertyMiss( + VM& vm, JSCell* owner, ExecState* exec, Structure* headStructure, UniquedStringImpl* uid) +{ + return generateConditions( + vm, exec->lexicalGlobalObject(), headStructure, nullptr, + [&] (Vector<ObjectPropertyCondition>& conditions, JSObject* object) -> bool { + ObjectPropertyCondition result = + generateCondition(vm, owner, object, uid, PropertyCondition::Absence); + if (!result) + return false; + conditions.append(result); + return true; + }); +} + +ObjectPropertyConditionSet generateConditionsForPropertySetterMiss( + VM& vm, JSCell* owner, ExecState* exec, Structure* headStructure, UniquedStringImpl* uid) +{ + return generateConditions( + vm, exec->lexicalGlobalObject(), headStructure, nullptr, + [&] (Vector<ObjectPropertyCondition>& conditions, JSObject* object) -> bool { + ObjectPropertyCondition result = + generateCondition(vm, owner, object, uid, PropertyCondition::AbsenceOfSetter); + if (!result) + return false; + conditions.append(result); + return true; + }); +} + +ObjectPropertyConditionSet generateConditionsForPrototypePropertyHit( + VM& vm, JSCell* owner, ExecState* exec, Structure* headStructure, JSObject* prototype, + UniquedStringImpl* uid) +{ + return generateConditions( + vm, exec->lexicalGlobalObject(), headStructure, prototype, + [&] (Vector<ObjectPropertyCondition>& conditions, JSObject* object) -> bool { + PropertyCondition::Kind kind = + object == prototype ? PropertyCondition::Presence : PropertyCondition::Absence; + ObjectPropertyCondition result = + generateCondition(vm, owner, object, uid, kind); + if (!result) + return false; + conditions.append(result); + return true; + }); +} + +ObjectPropertyConditionSet generateConditionsForPrototypePropertyHitCustom( + VM& vm, JSCell* owner, ExecState* exec, Structure* headStructure, JSObject* prototype, + UniquedStringImpl* uid) +{ + return generateConditions( + vm, exec->lexicalGlobalObject(), headStructure, prototype, + [&] (Vector<ObjectPropertyCondition>& conditions, JSObject* object) -> bool { + if (object == prototype) + return true; + ObjectPropertyCondition result = + generateCondition(vm, owner, object, uid, PropertyCondition::Absence); + if (!result) + return false; + conditions.append(result); + return true; + }); +} + +ObjectPropertyConditionSet generateConditionsForPropertySetterMissConcurrently( + VM& vm, JSGlobalObject* globalObject, Structure* headStructure, UniquedStringImpl* uid) +{ + return generateConditions( + vm, globalObject, headStructure, nullptr, + [&] (Vector<ObjectPropertyCondition>& conditions, JSObject* object) -> bool { + ObjectPropertyCondition result = + generateCondition(vm, nullptr, object, uid, PropertyCondition::AbsenceOfSetter); + if (!result) + return false; + conditions.append(result); + return true; + }, Concurrent); +} + +} // namespace JSC + |