Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (88279 => 88280)
--- trunk/Source/_javascript_Core/ChangeLog 2011-06-07 23:02:20 UTC (rev 88279)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-06-07 23:03:32 UTC (rev 88280)
@@ -1,3 +1,29 @@
+2011-06-07 Gavin Barraclough <[email protected]>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=62240
+ DFG JIT - add support for for-loop array initialization.
+
+ Support put by val beyond vector length.
+ Add a operationPutByValBeyondArrayBounds operation, make
+ PutValVal call this if the vector length check fails.
+
+ * dfg/DFGJITCodeGenerator.h:
+ (JSC::DFG::JITCodeGenerator::silentSpillGPR):
+ (JSC::DFG::JITCodeGenerator::silentFillGPR):
+ (JSC::DFG::JITCodeGenerator::silentSpillAllRegisters):
+ (JSC::DFG::JITCodeGenerator::isDoubleConstantWithInt32Value):
+ (JSC::DFG::JITCodeGenerator::isJSConstantWithInt32Value):
+ (JSC::DFG::JITCodeGenerator::isIntegerConstant):
+ (JSC::DFG::JITCodeGenerator::valueOfIntegerConstant):
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::operationPutByValInternal):
+ * dfg/DFGOperations.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT.h:
+
2011-06-06 James Simonsen <[email protected]>
Reviewed by James Robinson.
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h (88279 => 88280)
--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-06-07 23:02:20 UTC (rev 88279)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-06-07 23:03:32 UTC (rev 88280)
@@ -158,7 +158,7 @@
// they spill all live values to the appropriate
// slots in the RegisterFile without changing any state
// in the GenerationInfo.
- void silentSpillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
+ void silentSpillGPR(VirtualRegister spillMe, GPRReg canTrample, GPRReg exclude = InvalidGPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() != DataFormatNone);
@@ -170,8 +170,8 @@
DataFormat registerFormat = info.registerFormat();
if (registerFormat == DataFormatInteger) {
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, info.gpr());
- m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
+ m_jit.orPtr(GPRInfo::tagTypeNumberRegister, info.gpr(), canTrample);
+ m_jit.storePtr(canTrample, JITCompiler::addressFor(spillMe));
} else {
ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
@@ -203,8 +203,8 @@
if (registerFormat == DataFormatInteger) {
if (node.isConstant()) {
- ASSERT(isInt32Constant(nodeIndex));
- m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), info.gpr());
+ ASSERT(isIntegerConstant(nodeIndex));
+ m_jit.move(Imm32(valueOfIntegerConstant(nodeIndex)), info.gpr());
} else
m_jit.load32(JITCompiler::addressFor(spillMe), info.gpr());
return;
@@ -235,15 +235,21 @@
}
}
- void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve = InvalidGPRReg)
+ void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg)
{
GPRReg canTrample = GPRInfo::regT0;
- if (preserve == GPRInfo::regT0)
+ if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0)
+ canTrample = GPRInfo::regT0;
+ else if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1)
canTrample = GPRInfo::regT1;
+ else if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2)
+ canTrample = GPRInfo::regT2;
+ else
+ canTrample = GPRInfo::regT3;
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
- silentSpillGPR(iter.name(), exclude);
+ silentSpillGPR(iter.name(), canTrample, exclude);
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
@@ -258,7 +264,7 @@
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
- silentSpillGPR(iter.name());
+ silentSpillGPR(iter.name(), canTrample);
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
@@ -382,6 +388,56 @@
double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); }
JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
+ bool isDoubleConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
+ {
+ if (!m_jit.isDoubleConstant(nodeIndex))
+ return false;
+ double value = m_jit.valueOfDoubleConstant(nodeIndex);
+
+ int32_t asInt32 = static_cast<int32_t>(value);
+ if (value != asInt32)
+ return false;
+ if (!asInt32 && signbit(value))
+ return false;
+
+ out = asInt32;
+ return true;
+ }
+
+ bool isJSConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
+ {
+ if (!m_jit.isJSConstant(nodeIndex))
+ return false;
+ JSValue value = m_jit.valueOfJSConstant(nodeIndex);
+
+ if (!value.isInt32())
+ return false;
+
+ out = value.asInt32();
+ return true;
+ }
+
+ bool isIntegerConstant(NodeIndex nodeIndex)
+ {
+ int32_t unused;
+ return isInt32Constant(nodeIndex)
+ || isDoubleConstantWithInt32Value(nodeIndex, unused)
+ || isJSConstantWithInt32Value(nodeIndex, unused);
+ }
+
+ int32_t valueOfIntegerConstant(NodeIndex nodeIndex)
+ {
+ if (isInt32Constant(nodeIndex))
+ return valueOfInt32Constant(nodeIndex);
+ int32_t result = 0;
+ bool okay = isDoubleConstantWithInt32Value(nodeIndex, result);
+ if (okay)
+ return result;
+ okay = isJSConstantWithInt32Value(nodeIndex, result);
+ ASSERT_UNUSED(okay, okay);
+ return result;
+ }
+
Identifier* identifier(unsigned index)
{
return &m_jit.codeBlock()->identifier(index);
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (88279 => 88280)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-06-07 23:02:20 UTC (rev 88279)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-06-07 23:03:32 UTC (rev 88280)
@@ -56,35 +56,35 @@
JSValue value = JSValue::decode(encodedValue);
if (LIKELY(property.isUInt32())) {
- uint32_t i = property.asUInt32();
+ uint32_t index = property.asUInt32();
if (isJSArray(globalData, baseValue)) {
- JSArray* jsArray = asArray(baseValue);
- if (jsArray->canSetIndex(i)) {
- jsArray->setIndex(*globalData, i, value);
+ JSArray* array = asArray(baseValue);
+ if (array->canSetIndex(index)) {
+ array->setIndex(*globalData, index, value);
return;
}
- jsArray->JSArray::put(exec, i, value);
+ array->JSArray::put(exec, index, value);
return;
}
- if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
- JSByteArray* jsByteArray = asByteArray(baseValue);
+ if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(index)) {
+ JSByteArray* byteArray = asByteArray(baseValue);
// FIXME: the JITstub used to relink this to an optimized form!
if (value.isInt32()) {
- jsByteArray->setIndex(i, value.asInt32());
+ byteArray->setIndex(index, value.asInt32());
return;
}
double dValue = 0;
if (value.getNumber(dValue)) {
- jsByteArray->setIndex(i, dValue);
+ byteArray->setIndex(index, dValue);
return;
}
}
- baseValue.put(exec, i, value);
+ baseValue.put(exec, index, value);
return;
}
@@ -134,21 +134,21 @@
if (property.isUInt32()) {
JSGlobalData* globalData = &exec->globalData();
- uint32_t i = property.asUInt32();
+ uint32_t index = property.asUInt32();
// FIXME: the JIT used to handle these in compiled code!
- if (isJSArray(globalData, base) && asArray(base)->canGetIndex(i))
- return JSValue::encode(asArray(base)->getIndex(i));
+ if (isJSArray(globalData, base) && asArray(base)->canGetIndex(index))
+ return JSValue::encode(asArray(base)->getIndex(index));
// FIXME: the JITstub used to relink this to an optimized form!
- if (isJSString(globalData, base) && asString(base)->canGetIndex(i))
- return JSValue::encode(asString(base)->getIndex(exec, i));
+ if (isJSString(globalData, base) && asString(base)->canGetIndex(index))
+ return JSValue::encode(asString(base)->getIndex(exec, index));
// FIXME: the JITstub used to relink this to an optimized form!
- if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(i))
- return JSValue::encode(asByteArray(base)->getIndex(exec, i));
+ if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(index))
+ return JSValue::encode(asByteArray(base)->getIndex(exec, index));
- return JSValue::encode(baseValue.get(exec, i));
+ return JSValue::encode(baseValue.get(exec, index));
}
if (property.isString()) {
@@ -197,6 +197,13 @@
operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
}
+void operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
+{
+ // We should only get here if index is outside the existing vector.
+ ASSERT(!array->canSetIndex(index));
+ array->JSArray::put(exec, index, JSValue::decode(encodedValue));
+}
+
void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(true);
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (88279 => 88280)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-06-07 23:02:20 UTC (rev 88279)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-06-07 23:03:32 UTC (rev 88280)
@@ -54,6 +54,7 @@
EncodedJSValue operationGetByIdOptimize(ExecState*, EncodedJSValue encodedBase, Identifier*);
void operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
+void operationPutByValBeyondArrayBounds(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
void operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
void operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
void operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (88279 => 88280)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-06-07 23:02:20 UTC (rev 88279)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-06-07 23:03:32 UTC (rev 88280)
@@ -687,8 +687,18 @@
Node& baseNode = m_jit.graph()[node.child1];
if (baseNode.op != GetLocal || m_jit.graph().getPrediction(baseNode.local()) != PredictArray)
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
- speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
+ MacroAssembler::Jump withinArrayBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
+ // Code to handle put beyond array bounds.
+ silentSpillAllRegisters(storageReg, baseReg, propertyReg, valueReg);
+ setupStubArguments(baseReg, propertyReg, valueReg);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ JITCompiler::Call functionCall = appendCallWithExceptionCheck(operationPutByValBeyondArrayBounds);
+ silentFillAllRegisters(storageReg);
+ JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
+
+ withinArrayBounds.link(&m_jit);
+
// Get the array storage.
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
@@ -708,6 +718,8 @@
// Store the value to the array.
m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
+ wasBeyondArrayBounds.link(&m_jit);
+
noResult(m_compileIndex);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (88279 => 88280)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2011-06-07 23:02:20 UTC (rev 88279)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2011-06-07 23:03:32 UTC (rev 88280)
@@ -138,35 +138,6 @@
void checkArgumentTypes();
void initializeVariableTypes();
- bool isDoubleConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
- {
- if (!m_jit.isDoubleConstant(nodeIndex))
- return false;
- double value = m_jit.valueOfDoubleConstant(nodeIndex);
-
- int32_t asInt32 = static_cast<int32_t>(value);
- if (value != asInt32)
- return false;
- if (!asInt32 && signbit(value))
- return false;
-
- out = asInt32;
- return true;
- }
-
- bool isJSConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
- {
- if (!m_jit.isJSConstant(nodeIndex))
- return false;
- JSValue value = m_jit.valueOfJSConstant(nodeIndex);
-
- if (!value.isInt32())
- return false;
-
- out = value.asInt32();
- return true;
- }
-
bool detectPeepHoleBranch()
{
// Check if the block contains precisely one more node.