Commit c5684714 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

op_to_this shouldn't use value profiling

https://bugs.webkit.org/show_bug.cgi?id=121920

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Currently it's the only opcode that uses m_singletonValue, which is unnecessary. Our current plan is
to remove m_singletonValue so that GenGC can have a simpler story for handling CodeBlocks/FunctionExecutables
during nursery collections.

This patch adds an inline cache for the Structure of to_this so it no longer depends on the ValueProfile's
m_singletonValue. Since nobody uses m_singletonValue now, this patch also removes m_singletonValue from
ValueProfile.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
(JSC::CodeBlock::updateAllValueProfilePredictions):
(JSC::CodeBlock::updateAllPredictions):
(JSC::CodeBlock::shouldOptimizeNow):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::updateAllValueProfilePredictions):
(JSC::CodeBlock::updateAllPredictions):
* bytecode/LazyOperandValueProfile.cpp:
(JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):
* bytecode/LazyOperandValueProfile.h:
* bytecode/ValueProfile.h:
(JSC::ValueProfileBase::ValueProfileBase):
(JSC::ValueProfileBase::briefDescription):
(JSC::ValueProfileBase::dump):
(JSC::ValueProfileBase::computeUpdatedPrediction):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_to_this):
(JSC::JIT::emitSlow_op_to_this):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_to_this):
(JSC::JIT::emitSlow_op_to_this):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):

LayoutTests:

Updated a couple tests that waited for two DFG compiles, but with this patch we
don't do two compiles any more, so we don't want to wait forever.

* js/script-tests/dfg-convert-this-polymorphic-object-then-exit-on-other.js:
* js/script-tests/dfg-convert-this-polymorphic-object-then-exit-on-string.js:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156468 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0169d5fc
2013-09-26 Mark Hahnenberg <mhahnenberg@apple.com>
op_to_this shouldn't use value profiling
https://bugs.webkit.org/show_bug.cgi?id=121920
Reviewed by Geoffrey Garen.
Updated a couple tests that waited for two DFG compiles, but with this patch we
don't do two compiles any more, so we don't want to wait forever.
* js/script-tests/dfg-convert-this-polymorphic-object-then-exit-on-other.js:
* js/script-tests/dfg-convert-this-polymorphic-object-then-exit-on-string.js:
2013-09-26 Andreas Kling <akling@apple.com>
Rebaseline some tests after IndexedDB was enabled.
......@@ -11,7 +11,7 @@ x = 42;
silentTestPass = true;
noInline(foo);
for (var i = 0; i < 1000; i = dfgIncrement({f:foo, i:dfgIncrement({f:foo, i:i + 1, n:100}), n:500, compiles:2})) {
for (var i = 0; i < 1000; i = dfgIncrement({f:foo, i:i + 1, n:500})) {
var me;
if (i < 150)
me = this;
......
......@@ -13,7 +13,7 @@ String.prototype.x = 42;
silentTestPass = true;
noInline(foo);
for (var i = 0; i < 1000; i = dfgIncrement({f:foo, i:dfgIncrement({f:foo, i:i + 1, n:100}), n:500, compiles:2})) {
for (var i = 0; i < 1000; i = dfgIncrement({f:foo, i:i + 1, n:500})) {
var me;
if (i < 150)
me = this;
......
2013-09-26 Mark Hahnenberg <mhahnenberg@apple.com>
op_to_this shouldn't use value profiling
https://bugs.webkit.org/show_bug.cgi?id=121920
Reviewed by Geoffrey Garen.
Currently it's the only opcode that uses m_singletonValue, which is unnecessary. Our current plan is
to remove m_singletonValue so that GenGC can have a simpler story for handling CodeBlocks/FunctionExecutables
during nursery collections.
This patch adds an inline cache for the Structure of to_this so it no longer depends on the ValueProfile's
m_singletonValue. Since nobody uses m_singletonValue now, this patch also removes m_singletonValue from
ValueProfile.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
(JSC::CodeBlock::updateAllValueProfilePredictions):
(JSC::CodeBlock::updateAllPredictions):
(JSC::CodeBlock::shouldOptimizeNow):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::updateAllValueProfilePredictions):
(JSC::CodeBlock::updateAllPredictions):
* bytecode/LazyOperandValueProfile.cpp:
(JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):
* bytecode/LazyOperandValueProfile.h:
* bytecode/ValueProfile.h:
(JSC::ValueProfileBase::ValueProfileBase):
(JSC::ValueProfileBase::briefDescription):
(JSC::ValueProfileBase::dump):
(JSC::ValueProfileBase::computeUpdatedPrediction):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_to_this):
(JSC::JIT::emitSlow_op_to_this):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_to_this):
(JSC::JIT::emitSlow_op_to_this):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
2013-09-25 Oliver Hunt <oliver@apple.com>
Implement prefixed-destructuring assignment
......@@ -1734,7 +1734,6 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
instructions[i + opLength - 2] = &m_arrayProfiles[arrayProfileIndex];
// fallthrough
}
case op_to_this:
case op_get_by_id:
case op_call_varargs: {
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
......@@ -2238,6 +2237,13 @@ void CodeBlock::finalizeUnconditionally()
break;
case op_get_array_length:
break;
case op_to_this:
if (!curInstruction[2].u.structure || Heap::isMarked(curInstruction[2].u.structure.get()))
break;
if (Options::verboseOSR())
dataLogF("Clearing LLInt to_this with structure %p.\n", curInstruction[2].u.structure.get());
curInstruction[2].u.structure.clear();
break;
case op_get_callee:
if (!curInstruction[2].u.jsCell || Heap::isMarked(curInstruction[2].u.jsCell.get()))
break;
......@@ -2418,7 +2424,7 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor)
for (unsigned i = 0; i < m_objectAllocationProfiles.size(); ++i)
m_objectAllocationProfiles[i].visitAggregate(visitor);
updateAllPredictions(Collection);
updateAllPredictions();
}
void CodeBlock::stronglyVisitWeakReferences(SlotVisitor& visitor)
......@@ -3093,8 +3099,7 @@ ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset)
return addArrayProfile(bytecodeOffset);
}
void CodeBlock::updateAllPredictionsAndCountLiveness(
HeapOperation operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
void CodeBlock::updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
{
ConcurrentJITLocker locker(m_lock);
......@@ -3107,23 +3112,23 @@ void CodeBlock::updateAllPredictionsAndCountLiveness(
numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight.
numberOfSamplesInProfiles += numSamples;
if (profile->m_bytecodeOffset < 0) {
profile->computeUpdatedPrediction(locker, operation);
profile->computeUpdatedPrediction(locker);
continue;
}
if (profile->numberOfSamples() || profile->m_prediction != SpecNone)
numberOfLiveNonArgumentValueProfiles++;
profile->computeUpdatedPrediction(locker, operation);
profile->computeUpdatedPrediction(locker);
}
#if ENABLE(DFG_JIT)
m_lazyOperandValueProfiles.computeUpdatedPredictions(locker, operation);
m_lazyOperandValueProfiles.computeUpdatedPredictions(locker);
#endif
}
void CodeBlock::updateAllValueProfilePredictions(HeapOperation operation)
void CodeBlock::updateAllValueProfilePredictions()
{
unsigned ignoredValue1, ignoredValue2;
updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
updateAllPredictionsAndCountLiveness(ignoredValue1, ignoredValue2);
}
void CodeBlock::updateAllArrayPredictions()
......@@ -3138,9 +3143,9 @@ void CodeBlock::updateAllArrayPredictions()
m_arrayAllocationProfiles[i].updateIndexingType();
}
void CodeBlock::updateAllPredictions(HeapOperation operation)
void CodeBlock::updateAllPredictions()
{
updateAllValueProfilePredictions(operation);
updateAllValueProfilePredictions();
updateAllArrayPredictions();
}
......@@ -3160,7 +3165,7 @@ bool CodeBlock::shouldOptimizeNow()
unsigned numberOfLiveNonArgumentValueProfiles;
unsigned numberOfSamplesInProfiles;
updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
updateAllPredictionsAndCountLiveness(numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
if (Options::verboseOSR()) {
dataLogF(
......
......@@ -870,14 +870,14 @@ public:
#if ENABLE(VALUE_PROFILER)
bool shouldOptimizeNow();
void updateAllValueProfilePredictions(HeapOperation = NoOperation);
void updateAllValueProfilePredictions();
void updateAllArrayPredictions();
void updateAllPredictions(HeapOperation = NoOperation);
void updateAllPredictions();
#else
bool updateAllPredictionsAndCheckIfShouldOptimizeNow() { return false; }
void updateAllValueProfilePredictions(HeapOperation = NoOperation) { }
void updateAllValueProfilePredictions() { }
void updateAllArrayPredictions() { }
void updateAllPredictions(HeapOperation = NoOperation) { }
void updateAllPredictions() { }
#endif
#if ENABLE(JIT)
......@@ -941,7 +941,7 @@ private:
#endif
#if ENABLE(VALUE_PROFILER)
void updateAllPredictionsAndCountLiveness(HeapOperation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
#endif
void setConstantRegisters(const Vector<WriteBarrier<Unknown> >& constants)
......
......@@ -35,13 +35,13 @@ namespace JSC {
CompressedLazyOperandValueProfileHolder::CompressedLazyOperandValueProfileHolder() { }
CompressedLazyOperandValueProfileHolder::~CompressedLazyOperandValueProfileHolder() { }
void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions(const ConcurrentJITLocker& locker, HeapOperation operation)
void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions(const ConcurrentJITLocker& locker)
{
if (!m_data)
return;
for (unsigned i = 0; i < m_data->size(); ++i)
m_data->at(i).computeUpdatedPrediction(locker, operation);
m_data->at(i).computeUpdatedPrediction(locker);
}
LazyOperandValueProfile* CompressedLazyOperandValueProfileHolder::add(
......
......@@ -157,7 +157,7 @@ public:
CompressedLazyOperandValueProfileHolder();
~CompressedLazyOperandValueProfileHolder();
void computeUpdatedPredictions(const ConcurrentJITLocker&, HeapOperation);
void computeUpdatedPredictions(const ConcurrentJITLocker&);
LazyOperandValueProfile* add(
const ConcurrentJITLocker&, const LazyOperandValueProfileKey& key);
......
......@@ -55,7 +55,6 @@ struct ValueProfileBase {
: m_bytecodeOffset(-1)
, m_prediction(SpecNone)
, m_numberOfSamplesInPrediction(0)
, m_singletonValueIsTop(false)
{
for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
m_buckets[i] = JSValue::encode(JSValue());
......@@ -65,7 +64,6 @@ struct ValueProfileBase {
: m_bytecodeOffset(bytecodeOffset)
, m_prediction(SpecNone)
, m_numberOfSamplesInPrediction(0)
, m_singletonValueIsTop(false)
{
for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
m_buckets[i] = JSValue::encode(JSValue());
......@@ -117,23 +115,13 @@ struct ValueProfileBase {
computeUpdatedPrediction(locker);
StringPrintStream out;
if (m_singletonValueIsTop)
out.print("predicting ", SpeculationDump(m_prediction));
else if (m_singletonValue)
out.print("predicting ", m_singletonValue);
out.print("predicting ", SpeculationDump(m_prediction));
return out.toCString();
}
void dump(PrintStream& out)
{
out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction));
out.printf(", value = ");
if (m_singletonValueIsTop)
out.printf("TOP");
else
out.print(m_singletonValue);
bool first = true;
for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
JSValue value = JSValue::decode(m_buckets[i]);
......@@ -150,7 +138,7 @@ struct ValueProfileBase {
// Updates the prediction and returns the new one. Never call this from any thread
// that isn't executing the code.
SpeculatedType computeUpdatedPrediction(const ConcurrentJITLocker&, HeapOperation operation = NoOperation)
SpeculatedType computeUpdatedPrediction(const ConcurrentJITLocker&)
{
for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
JSValue value = JSValue::decode(m_buckets[i]);
......@@ -160,23 +148,9 @@ struct ValueProfileBase {
m_numberOfSamplesInPrediction++;
mergeSpeculation(m_prediction, speculationFromValue(value));
if (!m_singletonValueIsTop && !!value) {
if (!m_singletonValue)
m_singletonValue = value;
else if (m_singletonValue != value)
m_singletonValueIsTop = true;
}
m_buckets[i] = JSValue::encode(JSValue());
}
if (operation == Collection
&& !m_singletonValueIsTop
&& !!m_singletonValue
&& m_singletonValue.isCell()
&& !Heap::isMarked(m_singletonValue.asCell()))
m_singletonValueIsTop = true;
return m_prediction;
}
......@@ -185,9 +159,6 @@ struct ValueProfileBase {
SpeculatedType m_prediction;
unsigned m_numberOfSamplesInPrediction;
bool m_singletonValueIsTop;
JSValue m_singletonValue;
EncodedJSValue m_buckets[totalNumberOfBuckets];
};
......
......@@ -387,9 +387,9 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, Unl
if (isConstructor()) {
emitCreateThis(&m_thisRegister);
} else if (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks) {
UnlinkedValueProfile profile = emitProfiledOpcode(op_to_this);
emitOpcode(op_to_this);
instructions().append(kill(&m_thisRegister));
instructions().append(profile);
instructions().append(0);
}
for (size_t i = 0; i < deconstructedParameters.size(); i++) {
auto& entry = deconstructedParameters[i];
......
......@@ -1905,25 +1905,16 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_to_this: {
Node* op1 = getThis();
if (op1->op() != ToThis) {
ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
ValueProfile* profile =
m_inlineStackTop->m_profiledBlock->valueProfileForBytecodeOffset(m_currentIndex);
profile->computeUpdatedPrediction(locker);
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLogF("[bc#%u]: profile %p: ", m_currentIndex, profile);
profile->dump(WTF::dataFile());
dataLogF("\n");
#endif
if (profile->m_singletonValueIsTop
|| !profile->m_singletonValue
|| !profile->m_singletonValue.isCell()
|| profile->m_singletonValue.asCell()->classInfo() != Structure::info()
|| static_cast<Structure*>(profile->m_singletonValue.asCell())->classInfo()->methodTable.toThis != JSObject::info()->methodTable.toThis)
Structure* cachedStructure = currentInstruction[2].u.structure.get();
if (!cachedStructure
|| cachedStructure->classInfo()->methodTable.toThis != JSObject::info()->methodTable.toThis
|| m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
setThis(addToGraph(ToThis, op1));
else {
} else {
addToGraph(
CheckStructure,
OpInfo(m_graph.addStructureSet(jsCast<Structure*>(profile->m_singletonValue.asCell()))),
OpInfo(m_graph.addStructureSet(cachedStructure)),
op1);
}
}
......
......@@ -865,14 +865,15 @@ void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction)
void JIT::emit_op_to_this(Instruction* currentInstruction)
{
WriteBarrierBase<Structure>* cachedStructure = &currentInstruction[2].u.structure;
emitGetVirtualRegister(currentInstruction[1].u.operand, regT1);
emitJumpSlowCaseIfNotJSCell(regT1);
loadPtr(Address(regT1, JSCell::structureOffset()), regT0);
if (shouldEmitProfiling())
emitValueProfilingSite(regT4);
addSlowCase(branch8(NotEqual, Address(regT0, Structure::typeInfoTypeOffset()), TrustedImm32(FinalObjectType)));
loadPtr(cachedStructure, regT2);
addSlowCase(branchPtr(NotEqual, regT0, regT2));
}
void JIT::emit_op_get_callee(Instruction* currentInstruction)
......@@ -945,6 +946,7 @@ void JIT::emitSlow_op_to_this(Instruction* currentInstruction, Vector<SlowCaseEn
{
linkSlowCase(iter);
linkSlowCase(iter);
linkSlowCase(iter);
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_this);
slowPathCall.call();
......
......@@ -1180,17 +1180,16 @@ void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCa
void JIT::emit_op_to_this(Instruction* currentInstruction)
{
WriteBarrierBase<Structure>* cachedStructure = &currentInstruction[2].u.structure;
int thisRegister = currentInstruction[1].u.operand;
emitLoad(thisRegister, regT3, regT2);
addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag)));
loadPtr(Address(regT2, JSCell::structureOffset()), regT0);
if (shouldEmitProfiling()) {
move(regT3, regT1);
emitValueProfilingSite(regT4);
}
addSlowCase(branch8(NotEqual, Address(regT0, Structure::typeInfoTypeOffset()), TrustedImm32(FinalObjectType)));
loadPtr(cachedStructure, regT2);
addSlowCase(branchPtr(NotEqual, regT0, regT2));
}
void JIT::emitSlow_op_to_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
......@@ -1198,6 +1197,7 @@ void JIT::emitSlow_op_to_this(Instruction* currentInstruction, Vector<SlowCaseEn
int dst = currentInstruction[1].u.operand;
linkSlowCase(iter);
linkSlowCase(iter);
linkSlowCase(iter);
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_to_this);
slowPathCall.call();
emitLoad(dst, regT1, regT0);
......
......@@ -431,7 +431,8 @@ _llint_op_to_this:
loadi PayloadOffset[cfr, t0, 8], t0
loadp JSCell::m_structure[t0], t0
bbneq Structure::m_typeInfo + TypeInfo::m_type[t0], FinalObjectType, .opToThisSlow
valueProfile(CellTag, t0, 8, t1)
loadpFromInstruction(2, t2)
bpneq t0, t2, .opToThisSlow
dispatch(3)
.opToThisSlow:
......
......@@ -311,7 +311,8 @@ _llint_op_to_this:
btqnz t0, tagMask, .opToThisSlow
loadp JSCell::m_structure[t0], t0
bbneq Structure::m_typeInfo + TypeInfo::m_type[t0], FinalObjectType, .opToThisSlow
valueProfile(t0, 2, t1)
loadpFromInstruction(2, t2)
bpneq t0, t2, .opToThisSlow
dispatch(3)
.opToThisSlow:
......
......@@ -230,10 +230,10 @@ SLOW_PATH_DECL(slow_path_to_this)
{
BEGIN();
JSValue v1 = OP(1).jsValue();
#if ENABLE(VALUE_PROFILER)
pc[OPCODE_LENGTH(op_to_this) - 1].u.profile->m_buckets[0] =
JSValue::encode(v1.structureOrUndefined());
#endif
if (v1.isCell())
pc[2].u.structure.set(exec->vm(), exec->codeBlock()->ownerExecutable(), v1.asCell()->structure());
else
pc[2].u.structure.clear();
RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode));
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment