Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (118554 => 118555)
--- trunk/Source/_javascript_Core/ChangeLog 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-05-25 20:19:55 UTC (rev 118555)
@@ -1,3 +1,61 @@
+2012-05-21 Filip Pizlo <[email protected]>
+
+ DFG ConvertThis should just be a CheckStructure if the structure is known
+ https://bugs.webkit.org/show_bug.cgi?id=87057
+
+ Reviewed by Gavin Barraclough.
+
+ Merged r118021 from dfgopt.
+
+ This gives ValueProfile the ability to track singleton values - i.e. profiling
+ sites that always see the same value.
+
+ That is then used to profile the structure in op_convert_this.
+
+ This is then used to optimize op_convert_this into a CheckStructure if the
+ structure is always the same.
+
+ That then results in better CSE in inlined code that uses 'this', since
+ previously we couldn't CSE accesses on 'this' from different inline call frames.
+
+ Also fixed a bug where we were unnecessarily flushing 'this'.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dump):
+ (JSC::CodeBlock::stronglyVisitStrongReferences):
+ * bytecode/LazyOperandValueProfile.cpp:
+ (JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):
+ * bytecode/LazyOperandValueProfile.h:
+ (CompressedLazyOperandValueProfileHolder):
+ * bytecode/Opcode.h:
+ (JSC):
+ (JSC::padOpcodeName):
+ * bytecode/ValueProfile.h:
+ (JSC::ValueProfileBase::ValueProfileBase):
+ (JSC::ValueProfileBase::dump):
+ (JSC::ValueProfileBase::computeUpdatedPrediction):
+ (ValueProfileBase):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::setArgument):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_convert_this):
+ (JSC::JIT::emitSlow_op_convert_this):
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::emit_op_convert_this):
+ (JSC::JIT::emitSlow_op_convert_this):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/JSValue.h:
+ (JSValue):
+ * runtime/Structure.h:
+ (JSC::JSValue::structureOrUndefined):
+ (JSC):
+
2012-05-24 Tim Horton <[email protected]>
Add feature defines for web-facing parts of CSS Regions and Exclusions
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (118554 => 118555)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2012-05-25 20:19:55 UTC (rev 118555)
@@ -670,6 +670,7 @@
case op_convert_this: {
int r0 = (++it)->u.operand;
dataLog("[%4d] convert_this\t %s\n", location, registerName(exec, r0).data());
+ ++it; // Skip value profile.
break;
}
case op_new_object: {
@@ -2085,14 +2086,14 @@
}
}
- m_lazyOperandValueProfiles.computeUpdatedPredictions();
+ m_lazyOperandValueProfiles.computeUpdatedPredictions(Collection);
#endif
#if ENABLE(VALUE_PROFILER)
for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex)
- valueProfileForArgument(profileIndex)->computeUpdatedPrediction();
+ valueProfileForArgument(profileIndex)->computeUpdatedPrediction(Collection);
for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex)
- valueProfile(profileIndex)->computeUpdatedPrediction();
+ valueProfile(profileIndex)->computeUpdatedPrediction(Collection);
#endif
}
Modified: trunk/Source/_javascript_Core/bytecode/LazyOperandValueProfile.cpp (118554 => 118555)
--- trunk/Source/_javascript_Core/bytecode/LazyOperandValueProfile.cpp 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/bytecode/LazyOperandValueProfile.cpp 2012-05-25 20:19:55 UTC (rev 118555)
@@ -33,13 +33,13 @@
CompressedLazyOperandValueProfileHolder::CompressedLazyOperandValueProfileHolder() { }
CompressedLazyOperandValueProfileHolder::~CompressedLazyOperandValueProfileHolder() { }
-void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions()
+void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions(OperationInProgress operation)
{
if (!m_data)
return;
for (unsigned i = 0; i < m_data->size(); ++i)
- m_data->at(i).computeUpdatedPrediction();
+ m_data->at(i).computeUpdatedPrediction(operation);
}
LazyOperandValueProfile* CompressedLazyOperandValueProfileHolder::add(
Modified: trunk/Source/_javascript_Core/bytecode/LazyOperandValueProfile.h (118554 => 118555)
--- trunk/Source/_javascript_Core/bytecode/LazyOperandValueProfile.h 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/bytecode/LazyOperandValueProfile.h 2012-05-25 20:19:55 UTC (rev 118555)
@@ -155,7 +155,7 @@
CompressedLazyOperandValueProfileHolder();
~CompressedLazyOperandValueProfileHolder();
- void computeUpdatedPredictions();
+ void computeUpdatedPredictions(OperationInProgress);
LazyOperandValueProfile* add(const LazyOperandValueProfileKey& key);
Modified: trunk/Source/_javascript_Core/bytecode/Opcode.h (118554 => 118555)
--- trunk/Source/_javascript_Core/bytecode/Opcode.h 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/bytecode/Opcode.h 2012-05-25 20:19:55 UTC (rev 118555)
@@ -43,7 +43,7 @@
macro(op_init_lazy_reg, 2) \
macro(op_create_arguments, 2) \
macro(op_create_this, 2) \
- macro(op_convert_this, 2) \
+ macro(op_convert_this, 3) \
\
macro(op_new_object, 2) \
macro(op_new_array, 4) \
Modified: trunk/Source/_javascript_Core/bytecode/ValueProfile.h (118554 => 118555)
--- trunk/Source/_javascript_Core/bytecode/ValueProfile.h 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/bytecode/ValueProfile.h 2012-05-25 20:19:55 UTC (rev 118555)
@@ -33,6 +33,7 @@
#if ENABLE(VALUE_PROFILER)
+#include "Heap.h"
#include "JSArray.h"
#include "PredictedType.h"
#include "Structure.h"
@@ -51,6 +52,7 @@
: m_bytecodeOffset(-1)
, m_prediction(PredictNone)
, m_numberOfSamplesInPrediction(0)
+ , m_singletonValueIsTop(false)
{
for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
m_buckets[i] = JSValue::encode(JSValue());
@@ -60,6 +62,7 @@
: m_bytecodeOffset(bytecodeOffset)
, m_prediction(PredictNone)
, m_numberOfSamplesInPrediction(0)
+ , m_singletonValueIsTop(false)
{
for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
m_buckets[i] = JSValue::encode(JSValue());
@@ -112,6 +115,11 @@
"samples = %u, prediction = %s",
totalNumberOfSamples(),
predictionToString(m_prediction));
+ fprintf(out, ", value = ");
+ if (m_singletonValueIsTop)
+ fprintf(out, "TOP");
+ else
+ fprintf(out, "%s", m_singletonValue.description());
bool first = true;
for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
JSValue value = JSValue::decode(m_buckets[i]);
@@ -127,7 +135,7 @@
}
// Updates the prediction and returns the new one.
- PredictedType computeUpdatedPrediction()
+ PredictedType computeUpdatedPrediction(OperationInProgress operation = NoOperation)
{
for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
JSValue value = JSValue::decode(m_buckets[i]);
@@ -137,9 +145,23 @@
m_numberOfSamplesInPrediction++;
mergePrediction(m_prediction, predictionFromValue(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;
}
@@ -148,6 +170,9 @@
PredictedType m_prediction;
unsigned m_numberOfSamplesInPrediction;
+ bool m_singletonValueIsTop;
+ JSValue m_singletonValue;
+
EncodedJSValue m_buckets[totalNumberOfBuckets];
};
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (118554 => 118555)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2012-05-25 20:19:55 UTC (rev 118555)
@@ -445,8 +445,9 @@
emitOpcode(op_create_this);
instructions().append(m_thisRegister.index());
} else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
- emitOpcode(op_convert_this);
+ ValueProfile* profile = ""
instructions().append(m_thisRegister.index());
+ instructions().append(profile);
}
}
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (118554 => 118555)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-05-25 20:19:55 UTC (rev 118555)
@@ -350,8 +350,9 @@
stack->m_argumentPositions[argument]->addVariable(variableAccessData);
NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
m_currentBlock->variablesAtTail.argument(argument) = nodeIndex;
- // Always flush arguments.
- addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
+ // Always flush arguments, except for 'this'.
+ if (argument)
+ addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
}
VariableAccessData* flushArgument(int operand)
@@ -1582,10 +1583,27 @@
case op_convert_this: {
NodeIndex op1 = getThis();
- if (m_graph[op1].op() == ConvertThis)
- setThis(op1);
- else
- setThis(addToGraph(ConvertThis, op1));
+ if (m_graph[op1].op() != ConvertThis) {
+ ValueProfile* profile =
+ m_inlineStackTop->m_profiledBlock->valueProfileForBytecodeOffset(m_currentProfilingIndex);
+ profile->computeUpdatedPrediction();
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ dataLog("[@%lu bc#%u]: profile %p: ", m_graph.size(), m_currentProfilingIndex, profile);
+ profile->dump(WTF::dataFile());
+ dataLog("\n");
+#endif
+ if (profile->m_singletonValueIsTop
+ || !profile->m_singletonValue
+ || !profile->m_singletonValue.isCell()
+ || profile->m_singletonValue.asCell()->classInfo() != &Structure::s_info)
+ setThis(addToGraph(ConvertThis, op1));
+ else {
+ addToGraph(
+ CheckStructure,
+ OpInfo(m_graph.addStructureSet(jsCast<Structure*>(profile->m_singletonValue.asCell()))),
+ op1);
+ }
+ }
NEXT_OPCODE(op_convert_this);
}
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (118554 => 118555)
--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2012-05-25 20:19:55 UTC (rev 118555)
@@ -1257,10 +1257,14 @@
void JIT::emit_op_convert_this(Instruction* currentInstruction)
{
- emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
+ emitGetVirtualRegister(currentInstruction[1].u.operand, regT1);
- emitJumpSlowCaseIfNotJSCell(regT0);
- addSlowCase(branchPtr(Equal, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
+ emitJumpSlowCaseIfNotJSCell(regT1);
+ if (shouldEmitProfiling()) {
+ loadPtr(Address(regT1, JSCell::structureOffset()), regT0);
+ emitValueProfilingSite();
+ }
+ addSlowCase(branchPtr(Equal, Address(regT1, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
}
void JIT::emit_op_create_this(Instruction* currentInstruction)
@@ -1315,15 +1319,21 @@
void* globalThis = m_codeBlock->globalObject()->globalScopeChain()->globalThis.get();
linkSlowCase(iter);
- Jump isNotUndefined = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsUndefined())));
+ if (shouldEmitProfiling())
+ move(TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(jsUndefined()))), regT0);
+ Jump isNotUndefined = branchPtr(NotEqual, regT1, TrustedImmPtr(JSValue::encode(jsUndefined())));
+ emitValueProfilingSite();
move(TrustedImmPtr(globalThis), regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand, regT0);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_convert_this));
+ linkSlowCase(iter);
+ if (shouldEmitProfiling())
+ move(TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(m_globalData->stringStructure.get()))), regT0);
isNotUndefined.link(this);
- linkSlowCase(iter);
+ emitValueProfilingSite();
JITStubCall stubCall(this, cti_op_convert_this);
- stubCall.addArgument(regT0);
+ stubCall.addArgument(regT1);
stubCall.call(currentInstruction[1].u.operand);
}
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp (118554 => 118555)
--- trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp 2012-05-25 20:19:55 UTC (rev 118555)
@@ -1548,12 +1548,15 @@
{
unsigned thisRegister = currentInstruction[1].u.operand;
- emitLoad(thisRegister, regT1, regT0);
+ emitLoad(thisRegister, regT3, regT2);
- addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
- addSlowCase(branchPtr(Equal, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
-
- map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0);
+ addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag)));
+ if (shouldEmitProfiling()) {
+ loadPtr(Address(regT2, JSCell::structureOffset()), regT0);
+ move(regT3, regT1);
+ emitValueProfilingSite();
+ }
+ addSlowCase(branchPtr(Equal, Address(regT2, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
}
void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -1562,16 +1565,26 @@
unsigned thisRegister = currentInstruction[1].u.operand;
linkSlowCase(iter);
- Jump isNotUndefined = branch32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag));
+ if (shouldEmitProfiling()) {
+ move(TrustedImm32(JSValue::UndefinedTag), regT1);
+ move(TrustedImm32(0), regT0);
+ }
+ Jump isNotUndefined = branch32(NotEqual, regT3, TrustedImm32(JSValue::UndefinedTag));
+ emitValueProfilingSite();
move(TrustedImmPtr(globalThis), regT0);
move(TrustedImm32(JSValue::CellTag), regT1);
emitStore(thisRegister, regT1, regT0);
emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_convert_this));
+ linkSlowCase(iter);
+ if (shouldEmitProfiling()) {
+ move(TrustedImm32(JSValue::CellTag), regT1);
+ move(TrustedImmPtr(m_globalData->stringStructure.get()), regT0);
+ }
isNotUndefined.link(this);
- linkSlowCase(iter);
+ emitValueProfilingSite();
JITStubCall stubCall(this, cti_op_convert_this);
- stubCall.addArgument(regT1, regT0);
+ stubCall.addArgument(regT3, regT2);
stubCall.call(thisRegister);
}
Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (118554 => 118555)
--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2012-05-25 20:19:55 UTC (rev 118555)
@@ -467,6 +467,8 @@
LLINT_BEGIN();
JSValue v1 = LLINT_OP(1).jsValue();
ASSERT(v1.isPrimitive());
+ pc[OPCODE_LENGTH(op_convert_this) - 1].u.profile->m_buckets[0] =
+ JSValue::encode(v1.structureOrUndefined());
LLINT_RETURN(v1.toThisObject(exec));
}
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (118554 => 118555)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2012-05-25 20:19:55 UTC (rev 118555)
@@ -364,11 +364,13 @@
loadi PayloadOffset[cfr, t0, 8], t0
loadp JSCell::m_structure[t0], t0
bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
- dispatch(2)
+ loadi 8[PC], t1
+ valueProfile(CellTag, t0, t1)
+ dispatch(3)
.opConvertThisSlow:
callSlowPath(_llint_slow_path_convert_this)
- dispatch(2)
+ dispatch(3)
_llint_op_new_object:
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (118554 => 118555)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2012-05-25 20:19:55 UTC (rev 118555)
@@ -241,11 +241,13 @@
btpnz t0, tagMask, .opConvertThisSlow
loadp JSCell::m_structure[t0], t0
bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
- dispatch(2)
+ loadp 16[PB, PC, 8], t1
+ valueProfile(t0, t1)
+ dispatch(3)
.opConvertThisSlow:
callSlowPath(_llint_slow_path_convert_this)
- dispatch(2)
+ dispatch(3)
_llint_op_new_object:
Modified: trunk/Source/_javascript_Core/runtime/JSValue.h (118554 => 118555)
--- trunk/Source/_javascript_Core/runtime/JSValue.h 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/runtime/JSValue.h 2012-05-25 20:19:55 UTC (rev 118555)
@@ -239,6 +239,8 @@
bool isCell() const;
JSCell* asCell() const;
JS_EXPORT_PRIVATE bool isValidCallee();
+
+ JSValue structureOrUndefined() const;
char* description() const;
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (118554 => 118555)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2012-05-25 20:11:42 UTC (rev 118554)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2012-05-25 20:19:55 UTC (rev 118555)
@@ -332,6 +332,13 @@
return entry ? entry->offset : notFound;
}
+ inline JSValue JSValue::structureOrUndefined() const
+ {
+ if (isCell())
+ return JSValue(asCell()->structure());
+ return jsUndefined();
+ }
+
inline bool JSCell::isObject() const
{
return m_structure->isObject();