diff options
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGAbstractState.cpp | 4 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGCSEPhase.cpp | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp | 4 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp | 4 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/SlotVisitorInlines.h | 1 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/NodeConstructors.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/ResultType.h | 15 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSArray.cpp | 60 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSObject.cpp | 30 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSObject.h | 13 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/NumericStrings.h | 6 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/Structure.cpp | 6 |
12 files changed, 103 insertions, 54 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index ab2a5af98..19bad5c09 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -1255,7 +1255,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node) case GetScope: // FIXME: We could get rid of these if we know that the JSFunction is a constant. https://bugs.webkit.org/show_bug.cgi?id=106202 case GetMyScope: case SkipTopScope: - forNode(node).set(SpecCellOther); + forNode(node).set(SpecObjectOther); break; case SkipScope: { @@ -1264,7 +1264,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node) m_foundConstants = true; break; } - forNode(node).set(SpecCellOther); + forNode(node).set(SpecObjectOther); break; } diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index 47af696a0..0eb29fcaf 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -254,9 +254,11 @@ private: break; } case PutScopedVar: { - if (node->child2() == registers && node->varNumber() == varNumber) + if (node->varNumber() != varNumber) + break; + if (node->child2() == registers) return node->child3().node(); - break; + return 0; } case SetLocal: { VariableAccessData* variableAccessData = node->variableAccessData(); @@ -327,9 +329,11 @@ private: Node* node = m_currentBlock->at(i); switch (node->op()) { case PutScopedVar: { - if (node->child1() == scope && node->child2() == registers && node->varNumber() == varNumber) + if (node->varNumber() != varNumber) + break; + if (node->child1() == scope && node->child2() == registers) return node; - break; + return 0; } case GetScopedVar: { diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 01a9e4e42..ddcc313d6 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -396,7 +396,7 @@ private: case GetMyScope: case SkipTopScope: case SkipScope: { - changed |= setPrediction(SpecCellOther); + changed |= setPrediction(SpecObjectOther); break; } @@ -497,7 +497,7 @@ private: break; case GetScope: - changed |= setPrediction(SpecCellOther); + changed |= setPrediction(SpecObjectOther); break; case Identity: diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 0957f0eab..6502aa574 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -1104,6 +1104,10 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) switch (info.registerFormat()) { case DataFormatNone: { + if (info.spillFormat() == DataFormatInteger || info.spillFormat() == DataFormatDouble) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + return allocate(); + } if (edge->hasConstant()) { JSValue jsValue = valueOfJSConstant(edge.node()); diff --git a/Source/JavaScriptCore/heap/SlotVisitorInlines.h b/Source/JavaScriptCore/heap/SlotVisitorInlines.h index 4273a28d6..da338ce11 100644 --- a/Source/JavaScriptCore/heap/SlotVisitorInlines.h +++ b/Source/JavaScriptCore/heap/SlotVisitorInlines.h @@ -174,6 +174,7 @@ inline void SlotVisitor::donateAndDrain() inline void SlotVisitor::copyLater(JSCell* owner, void* ptr, size_t bytes) { + ASSERT(bytes); CopiedBlock* block = CopiedSpace::blockFor(ptr); if (block->isOversize()) { m_shared.m_copiedSpace->pin(block); diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h index b31c01432..4bc670f81 100644 --- a/Source/JavaScriptCore/parser/NodeConstructors.h +++ b/Source/JavaScriptCore/parser/NodeConstructors.h @@ -517,7 +517,7 @@ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifie } inline LogicalOpNode::LogicalOpNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper) - : ExpressionNode(location, ResultType::booleanType()) + : ExpressionNode(location, ResultType::forLogicalOp(expr1->resultDescriptor(), expr2->resultDescriptor())) , m_expr1(expr1) , m_expr2(expr2) , m_operator(oper) diff --git a/Source/JavaScriptCore/parser/ResultType.h b/Source/JavaScriptCore/parser/ResultType.h index de4bde66b..ad86c98c7 100644 --- a/Source/JavaScriptCore/parser/ResultType.h +++ b/Source/JavaScriptCore/parser/ResultType.h @@ -120,7 +120,20 @@ namespace JSC { return stringType(); return stringOrNumberType(); } - + + // Unlike in C, a logical op produces the value of the + // last expression evaluated (and not true or false). + static ResultType forLogicalOp(ResultType op1, ResultType op2) + { + if (op1.definitelyIsBoolean() && op2.definitelyIsBoolean()) + return booleanType(); + if (op1.definitelyIsNumber() && op2.definitelyIsNumber()) + return numberType(); + if (op1.definitelyIsString() && op2.definitelyIsString()) + return stringType(); + return unknownType(); + } + static ResultType forBitOp() { return numberTypeIsInt32(); diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index f97ccedcd..bc6f73672 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -755,21 +755,21 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // so only if it's not horribly slow. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); - + + // Storing to a hole is fine since we're still having a good time. But reading from a hole + // is totally not fine, since we might have to read from the proto chain. + // We have to check for holes before we start moving things around so that we don't get halfway + // through shifting and then realize we should have been in ArrayStorage mode. unsigned end = oldLength - count; for (unsigned i = startIndex; i < end; ++i) { - // Storing to a hole is fine since we're still having a good time. But reading - // from a hole is totally not fine, since we might have to read from the proto - // chain. JSValue v = m_butterfly->contiguous()[i + count].get(); - if (UNLIKELY(!v)) { - // The purpose of this path is to ensure that we don't make the same - // mistake in the future: shiftCountWithArrayStorage() can't do anything - // about holes (at least for now), but it can detect them quickly. So - // we convert to array storage and then allow the array storage path to - // figure it out. + if (UNLIKELY(!v)) return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); - } + } + + for (unsigned i = startIndex; i < end; ++i) { + JSValue v = m_butterfly->contiguous()[i + count].get(); + ASSERT(v); // No need for a barrier since we're just moving data around in the same vector. // This is in line with our standing assumption that we won't have a deletion // barrier. @@ -790,21 +790,21 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex // so only if it's not horribly slow. if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); - + + // Storing to a hole is fine since we're still having a good time. But reading from a hole + // is totally not fine, since we might have to read from the proto chain. + // We have to check for holes before we start moving things around so that we don't get halfway + // through shifting and then realize we should have been in ArrayStorage mode. unsigned end = oldLength - count; for (unsigned i = startIndex; i < end; ++i) { - // Storing to a hole is fine since we're still having a good time. But reading - // from a hole is totally not fine, since we might have to read from the proto - // chain. double v = m_butterfly->contiguousDouble()[i + count]; - if (UNLIKELY(v != v)) { - // The purpose of this path is to ensure that we don't make the same - // mistake in the future: shiftCountWithArrayStorage() can't do anything - // about holes (at least for now), but it can detect them quickly. So - // we convert to array storage and then allow the array storage path to - // figure it out. + if (UNLIKELY(v != v)) return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm())); - } + } + + for (unsigned i = startIndex; i < end; ++i) { + double v = m_butterfly->contiguousDouble()[i + count]; + ASSERT(v == v); // No need for a barrier since we're just moving data around in the same vector. // This is in line with our standing assumption that we won't have a deletion // barrier. @@ -889,11 +889,18 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); ensureLength(exec->vm(), oldLength + count); - + + // We have to check for holes before we start moving things around so that we don't get halfway + // through shifting and then realize we should have been in ArrayStorage mode. for (unsigned i = oldLength; i-- > startIndex;) { JSValue v = m_butterfly->contiguous()[i].get(); if (UNLIKELY(!v)) return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); + } + + for (unsigned i = oldLength; i-- > startIndex;) { + JSValue v = m_butterfly->contiguous()[i].get(); + ASSERT(v); m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v); } @@ -915,10 +922,17 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd ensureLength(exec->vm(), oldLength + count); + // We have to check for holes before we start moving things around so that we don't get halfway + // through shifting and then realize we should have been in ArrayStorage mode. for (unsigned i = oldLength; i-- > startIndex;) { double v = m_butterfly->contiguousDouble()[i]; if (UNLIKELY(v != v)) return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm())); + } + + for (unsigned i = oldLength; i-- > startIndex;) { + double v = m_butterfly->contiguousDouble()[i]; + ASSERT(v == v); m_butterfly->contiguousDouble()[i + count] = v; } diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 01dc96333..5637e2090 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -595,7 +595,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(VM& vm) if (mayInterceptIndexedAccesses()) return; - setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors), m_butterfly); if (!vm.prototypeMap.isPrototype(this)) return; @@ -681,7 +681,7 @@ ArrayStorage* JSObject::createInitialArrayStorage(VM& vm) ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm) { ASSERT(hasUndecided(structure()->indexingType())); - setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32), m_butterfly); return m_butterfly->contiguousInt32(); } @@ -692,14 +692,14 @@ ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm) for (unsigned i = m_butterfly->vectorLength(); i--;) m_butterfly->contiguousDouble()[i] = QNaN; - setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly); return m_butterfly->contiguousDouble(); } ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm) { ASSERT(hasUndecided(structure()->indexingType())); - setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly); return m_butterfly->contiguous(); } @@ -765,7 +765,7 @@ ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm) *currentAsDouble = v.asInt32(); } - setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly); return m_butterfly->contiguousDouble(); } @@ -773,7 +773,7 @@ ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm) { ASSERT(hasInt32(structure()->indexingType())); - setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly); return m_butterfly->contiguous(); } @@ -831,7 +831,7 @@ ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm) currentAsValue->setWithoutWriteBarrier(v); } - setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous)); + setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly); return m_butterfly->contiguous(); } @@ -1129,7 +1129,7 @@ void JSObject::switchToSlowPutArrayStorage(VM& vm) case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage); - setStructure(vm, newStructure); + setStructure(vm, newStructure, m_butterfly); break; } @@ -1153,7 +1153,7 @@ void JSObject::setPrototype(VM& vm, JSValue prototype) vm.prototypeMap.addPrototype(asObject(prototype)); Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype); - setStructure(vm, newStructure); + setStructure(vm, newStructure, m_butterfly); if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses()) return; @@ -1213,7 +1213,7 @@ void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSV // getters and setters, though, we also need to change our Structure // if we override an existing non-getter or non-setter. if (slot.type() != PutPropertySlot::NewProperty) - setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes)); + setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes), m_butterfly); if (attributes & ReadOnly) structure()->setContainsReadOnlyProperties(); @@ -1570,7 +1570,7 @@ void JSObject::seal(VM& vm) if (isSealed(vm)) return; preventExtensions(vm); - setStructure(vm, Structure::sealTransition(vm, structure())); + setStructure(vm, Structure::sealTransition(vm, structure()), m_butterfly); } void JSObject::freeze(VM& vm) @@ -1578,14 +1578,14 @@ void JSObject::freeze(VM& vm) if (isFrozen(vm)) return; preventExtensions(vm); - setStructure(vm, Structure::freezeTransition(vm, structure())); + setStructure(vm, Structure::freezeTransition(vm, structure()), m_butterfly); } void JSObject::preventExtensions(VM& vm) { enterDictionaryIndexingMode(vm); if (isExtensible()) - setStructure(vm, Structure::preventExtensionsTransition(vm, structure())); + setStructure(vm, Structure::preventExtensionsTransition(vm, structure()), m_butterfly); } // This presently will flatten to an uncachable dictionary; this is suitable @@ -1603,7 +1603,7 @@ void JSObject::reifyStaticFunctionsForDelete(ExecState* exec) } if (!structure()->isUncacheableDictionary()) - setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure())); + setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()), m_butterfly); for (const ClassInfo* info = classInfo(); info; info = info->parentClass) { const HashTable* hashTable = info->propHashTable(globalObject()->globalExec()); @@ -1633,7 +1633,7 @@ bool JSObject::removeDirect(VM& vm, PropertyName propertyName) return true; } - setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset)); + setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset), m_butterfly); if (offset == invalidOffset) return false; putDirectUndefined(offset); diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index c62dc2aec..7a78a46a6 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -595,6 +595,7 @@ public: void setButterfly(VM&, Butterfly*, Structure*); void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this. + void setStructure(VM&, Structure*, Butterfly* = 0); void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*); void setStructureAndReallocateStorageIfNecessary(VM&, Structure*); @@ -1109,7 +1110,7 @@ inline void JSObject::setButterfly(VM& vm, Butterfly* butterfly, Structure* stru { ASSERT(structure); ASSERT(!butterfly == (!structure->outOfLineCapacity() && !hasIndexingHeader(structure->indexingType()))); - setStructure(vm, structure); + setStructure(vm, structure, butterfly); m_butterfly = butterfly; } @@ -1316,7 +1317,7 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal return true; } // case (2) Despecify, fall through to (3). - setStructure(vm, Structure::despecifyFunctionTransition(vm, structure(), propertyName)); + setStructure(vm, Structure::despecifyFunctionTransition(vm, structure(), propertyName), m_butterfly); } // case (3) set the slot, do the put, return. @@ -1344,12 +1345,18 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal return true; } +inline void JSObject::setStructure(VM& vm, Structure* structure, Butterfly* butterfly) +{ + JSCell::setStructure(vm, structure); + ASSERT_UNUSED(butterfly, !butterfly == !(structure->outOfLineCapacity() || hasIndexingHeader(structure->indexingType()))); +} + inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsigned oldCapacity, Structure* newStructure) { ASSERT(oldCapacity <= newStructure->outOfLineCapacity()); if (oldCapacity == newStructure->outOfLineCapacity()) { - setStructure(vm, newStructure); + setStructure(vm, newStructure, m_butterfly); return; } diff --git a/Source/JavaScriptCore/runtime/NumericStrings.h b/Source/JavaScriptCore/runtime/NumericStrings.h index 4cd92fc1f..68bfbd06a 100644 --- a/Source/JavaScriptCore/runtime/NumericStrings.h +++ b/Source/JavaScriptCore/runtime/NumericStrings.h @@ -37,7 +37,7 @@ namespace JSC { ALWAYS_INLINE String add(double d) { CacheEntry<double>& entry = lookup(d); - if (d == entry.key && !entry.value.isNull()) + if (!entry.value.isNull() && d == entry.key) return entry.value; entry.key = d; entry.value = String::numberToStringECMAScript(d); @@ -49,7 +49,7 @@ namespace JSC { if (static_cast<unsigned>(i) < cacheSize) return lookupSmallString(static_cast<unsigned>(i)); CacheEntry<int>& entry = lookup(i); - if (i == entry.key && !entry.value.isNull()) + if (!entry.value.isNull() && i == entry.key) return entry.value; entry.key = i; entry.value = String::number(i); @@ -61,7 +61,7 @@ namespace JSC { if (i < cacheSize) return lookupSmallString(static_cast<unsigned>(i)); CacheEntry<unsigned>& entry = lookup(i); - if (i == entry.key && !entry.value.isNull()) + if (!entry.value.isNull() && i == entry.key) return entry.value; entry.key = i; entry.value = String::number(i); diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index f551eaecc..950728cca 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -649,6 +649,12 @@ Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object) } m_dictionaryKind = NoneDictionaryKind; + + // If the object had a Butterfly but after flattening/compacting we no longer have need of it, + // we need to zero it out because the collector depends on the Structure to know the size for copying. + if (object->butterfly() && !this->outOfLineCapacity() && !hasIndexingHeader(this->indexingType())) + object->setButterfly(vm, 0, this); + return this; } |