Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (87430 => 87431)
--- trunk/Source/_javascript_Core/ChangeLog 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-05-26 21:37:05 UTC (rev 87431)
@@ -1,3 +1,53 @@
+2011-05-26 Gavin Barraclough <[email protected]>
+
+ Reviewed by Geoff Garen.
+
+ https://bugs.webkit.org/show_bug.cgi?id=61508
+ DFG JIT - Add support for get by id self caching.
+
+ Change the call out to be an unexpected call (using silent spill/fill functions),
+ add a structure check & compact load to the JIT code, and add repatching mechanisms.
+ Since DFGOperations may want to be be implemented in asm, make these symbols be extern
+ "C". Add an asm wrapper to pass the return address to the optimizing get-by-id operation,
+ so that it can look up its StructureStubInfo.
+
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ - Added new files.
+ * bytecode/StructureStubInfo.h:
+ - Added 'unset' entries to union.
+ * dfg/DFGJITCodeGenerator.h:
+ (JSC::DFG::JITCodeGenerator::appendCallWithExceptionCheck):
+ - Return the call, we need this to populate the StructureStubInfo.
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::compileFunction):
+ - Populate the CodebBlock's StructureStubInfo Vector.
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::JITCompiler::appendCallWithExceptionCheck):
+ - Return the call, we need this to populate the StructureStubInfo.
+ (JSC::DFG::JITCompiler::addPropertyAccess):
+ (JSC::DFG::JITCompiler::PropertyAccessRecord::PropertyAccessRecord):
+ - Add structures to record property access info during compilation.
+ * dfg/DFGOperations.cpp:
+ - Made all external methods extern "C".
+ (JSC::DFG::operationPutByValInternal):
+ - Moved outside of the extern "C" block.
+ * dfg/DFGOperations.h:
+ - Made all external methods extern "C".
+ * dfg/DFGRepatch.cpp: Added.
+ (JSC::DFG::dfgRepatchCall):
+ - repatch a call to link to a new callee function.
+ (JSC::DFG::dfgRepatchGetByIdSelf):
+ - Modify the JIT code to optimize self accesses.
+ (JSC::DFG::tryCacheGetByID):
+ - Internal implementation of dfgRepatchGetByID (factor out failing cases).
+ (JSC::DFG::dfgRepatchGetByID):
+ - Used to optimize 'operationGetByIdOptimize' - repatches to 'operationGetById', and tries to optimize self accesses!
+ * dfg/DFGRepatch.h: Added.
+ - Expose dfgRepatchGetByID.
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ - Changed implementation of GetById ops.
+
2011-05-26 Geoffrey Garen <[email protected]>
Rolled back in http://trac.webkit.org/changeset/87408 with Windows build fixed.
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (87430 => 87431)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2011-05-26 21:37:05 UTC (rev 87431)
@@ -283,6 +283,8 @@
86B99AB9117E391E00DF5A90 /* RopeImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B99AB7117E391E00DF5A90 /* RopeImpl.h */; settings = {ATTRIBUTES = (Private, ); }; };
86B99AE3117E578100DF5A90 /* StringBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B99AE1117E578100DF5A90 /* StringBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
86B99AE4117E578100DF5A90 /* StringImplBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B99AE2117E578100DF5A90 /* StringImplBase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 86BB09C0138E381B0056702F /* DFGRepatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86BB09BE138E381B0056702F /* DFGRepatch.cpp */; };
+ 86BB09C1138E381B0056702F /* DFGRepatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BB09BF138E381B0056702F /* DFGRepatch.h */; };
86C36EEA0EE1289D00B3DF59 /* MacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */; };
86C568E011A213EE0007F7F0 /* MacroAssemblerARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86C568DD11A213EE0007F7F0 /* MacroAssemblerARM.cpp */; };
86C568E111A213EE0007F7F0 /* MacroAssemblerMIPS.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DE11A213EE0007F7F0 /* MacroAssemblerMIPS.h */; };
@@ -964,6 +966,8 @@
86B99AB7117E391E00DF5A90 /* RopeImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RopeImpl.h; sourceTree = "<group>"; };
86B99AE1117E578100DF5A90 /* StringBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringBuffer.h; path = text/StringBuffer.h; sourceTree = "<group>"; };
86B99AE2117E578100DF5A90 /* StringImplBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringImplBase.h; path = text/StringImplBase.h; sourceTree = "<group>"; };
+ 86BB09BE138E381B0056702F /* DFGRepatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGRepatch.cpp; path = dfg/DFGRepatch.cpp; sourceTree = "<group>"; };
+ 86BB09BF138E381B0056702F /* DFGRepatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGRepatch.h; path = dfg/DFGRepatch.h; sourceTree = "<group>"; };
86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssembler.h; sourceTree = "<group>"; };
86C568DD11A213EE0007F7F0 /* MacroAssemblerARM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssemblerARM.cpp; sourceTree = "<group>"; };
86C568DE11A213EE0007F7F0 /* MacroAssemblerMIPS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerMIPS.h; sourceTree = "<group>"; };
@@ -2060,6 +2064,8 @@
86EC9DBF1328DF82002B2AD7 /* DFGOperations.cpp */,
86EC9DC01328DF82002B2AD7 /* DFGOperations.h */,
86EC9DC11328DF82002B2AD7 /* DFGRegisterBank.h */,
+ 86BB09BE138E381B0056702F /* DFGRepatch.cpp */,
+ 86BB09BF138E381B0056702F /* DFGRepatch.h */,
86ECA3F9132DF25A002B2AD7 /* DFGScoreBoard.h */,
86EC9DC21328DF82002B2AD7 /* DFGSpeculativeJIT.cpp */,
86EC9DC31328DF82002B2AD7 /* DFGSpeculativeJIT.h */,
@@ -2540,6 +2546,7 @@
7934BB7F1361979400CB99A1 /* ParallelJobsOpenMP.h in Headers */,
651DCA04136A6FEF00F74194 /* PassTraits.h in Headers */,
14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */,
+ 86BB09C1138E381B0056702F /* DFGRepatch.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2986,6 +2993,7 @@
142D6F1113539A4100B02E86 /* MarkStack.cpp in Sources */,
86AE64A8135E5E1C00963012 /* MacroAssemblerSH4.cpp in Sources */,
7934BB7C1361979400CB99A1 /* ParallelJobsGeneric.cpp in Sources */,
+ 86BB09C0138E381B0056702F /* DFGRepatch.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Modified: trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h (87430 => 87431)
--- trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h 2011-05-26 21:37:05 UTC (rev 87431)
@@ -132,6 +132,10 @@
union {
struct {
+ intptr_t deltaCheckToCall;
+ intptr_t deltaCallToLoad;
+ } unset;
+ struct {
WriteBarrierBase<Structure> baseObjectStructure;
} getByIdSelf;
struct {
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h (87430 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-05-26 21:37:05 UTC (rev 87431)
@@ -161,7 +161,8 @@
void silentSpillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
- ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
+ ASSERT(info.registerFormat() != DataFormatNone);
+ ASSERT(info.registerFormat() != DataFormatDouble);
if (!info.needsSpill() || (info.gpr() == exclude))
return;
@@ -196,7 +197,8 @@
NodeIndex nodeIndex = info.nodeIndex();
Node& node = m_jit.graph()[nodeIndex];
- ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
+ ASSERT(info.registerFormat() != DataFormatNone);
+ ASSERT(info.registerFormat() != DataFormatDouble);
DataFormat registerFormat = info.registerFormat();
if (registerFormat == DataFormatInteger) {
@@ -793,9 +795,9 @@
m_jit.moveDouble(FPRInfo::returnValueFPR, result);
}
- void appendCallWithExceptionCheck(const FunctionPtr& function)
+ JITCompiler::Call appendCallWithExceptionCheck(const FunctionPtr& function)
{
- m_jit.appendCallWithExceptionCheck(function, m_jit.graph()[m_compileIndex].exceptionInfo);
+ return m_jit.appendCallWithExceptionCheck(function, m_jit.graph()[m_compileIndex].exceptionInfo);
}
void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp (87430 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp 2011-05-26 21:37:05 UTC (rev 87431)
@@ -282,6 +282,7 @@
} else {
// If compilation through the SpeculativeJIT failed, throw away the code we generated.
m_calls.clear();
+ m_propertyAccesses.clear();
rewindToLabel(speculativePathBegin);
SpeculationCheckVector noChecks;
@@ -371,6 +372,14 @@
}
}
+ m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size());
+ for (unsigned i = 0; i < m_propertyAccesses.size(); ++i) {
+ StructureStubInfo& info = m_codeBlock->structureStubInfo(i);
+ info.callReturnLocation = linkBuffer.locationOf(m_propertyAccesses[i].m_functionCall);
+ info.u.unset.deltaCheckToCall = m_propertyAccesses[i].m_deltaCheckToCall;
+ info.u.unset.deltaCallToLoad = m_propertyAccesses[i].m_deltaCallToLoad;
+ }
+
// FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs.
linkBuffer.link(callRegisterFileCheck, cti_register_file_check);
linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h (87430 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h 2011-05-26 21:37:05 UTC (rev 87431)
@@ -166,11 +166,12 @@
}
// Add a call out from JIT code, with an exception check.
- void appendCallWithExceptionCheck(const FunctionPtr& function, unsigned exceptionInfo)
+ Call appendCallWithExceptionCheck(const FunctionPtr& function, unsigned exceptionInfo)
{
Call functionCall = call();
Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception));
m_calls.append(CallRecord(functionCall, function, exceptionCheck, exceptionInfo));
+ return functionCall;
}
// Helper methods to check nodes for constants.
@@ -232,6 +233,11 @@
void clearSamplingFlag(int32_t flag);
#endif
+ void addPropertyAccess(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoad)
+ {
+ m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckToCall, deltaCallToLoad));
+ }
+
private:
// These methods used in linking the speculative & non-speculative paths together.
void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary);
@@ -251,6 +257,21 @@
// Vector of calls out from JIT code, including exception handler information.
Vector<CallRecord> m_calls;
+
+ struct PropertyAccessRecord {
+ PropertyAccessRecord(JITCompiler::Call functionCall, intptr_t deltaCheckToCall, intptr_t deltaCallToLoad)
+ : m_functionCall(functionCall)
+ , m_deltaCheckToCall(deltaCheckToCall)
+ , m_deltaCallToLoad(deltaCallToLoad)
+ {
+ }
+
+ JITCompiler::Call m_functionCall;
+ intptr_t m_deltaCheckToCall;
+ intptr_t m_deltaCallToLoad;
+ };
+
+ Vector<PropertyAccessRecord, 4> m_propertyAccesses;
};
} } // namespace JSC::DFG
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (87430 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-05-26 21:37:05 UTC (rev 87431)
@@ -29,13 +29,75 @@
#if ENABLE(DFG_JIT)
#include "CodeBlock.h"
+#include "DFGRepatch.h"
#include "Interpreter.h"
#include "JSByteArray.h"
#include "JSGlobalData.h"
#include "Operations.h"
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \
+ asm( \
+ ".globl _" STRINGIZE(function) "\n" \
+ "_" STRINGIZE(function) ":" "\n" \
+ "mov (%rsp), %" STRINGIZE(register) "\n" \
+ "jmp _" STRINGIZE(function) "WithReturnAddress" "\n" \
+ );
+#define FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx)
+
namespace JSC { namespace DFG {
+template<bool strict>
+ALWAYS_INLINE static void operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+ JSGlobalData* globalData = &exec->globalData();
+
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue property = JSValue::decode(encodedProperty);
+ JSValue value = JSValue::decode(encodedValue);
+
+ if (LIKELY(property.isUInt32())) {
+ uint32_t i = property.asUInt32();
+
+ if (isJSArray(globalData, baseValue)) {
+ JSArray* jsArray = asArray(baseValue);
+ if (jsArray->canSetIndex(i)) {
+ jsArray->setIndex(*globalData, i, value);
+ return;
+ }
+
+ jsArray->JSArray::put(exec, i, value);
+ return;
+ }
+
+ if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
+ JSByteArray* jsByteArray = asByteArray(baseValue);
+ // FIXME: the JITstub used to relink this to an optimized form!
+ if (value.isInt32()) {
+ jsByteArray->setIndex(i, value.asInt32());
+ return;
+ }
+
+ double dValue = 0;
+ if (value.getNumber(dValue)) {
+ jsByteArray->setIndex(i, dValue);
+ return;
+ }
+ }
+
+ baseValue.put(exec, i, value);
+ return;
+ }
+
+ // Don't put to an object if toString throws an exception.
+ Identifier ident(exec, property.toString(exec));
+ if (!globalData->exception) {
+ PutPropertySlot slot(strict);
+ baseValue.put(exec, ident, value, slot);
+ }
+}
+
+extern "C" {
+
EncodedJSValue operationConvertThis(ExecState* exec, EncodedJSValue encodedOp)
{
return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
@@ -101,61 +163,28 @@
return JSValue::encode(baseValue.get(exec, ident));
}
-EncodedJSValue operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* identifier)
+EncodedJSValue operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
{
JSValue baseValue = JSValue::decode(encodedBase);
PropertySlot slot(baseValue);
- return JSValue::encode(baseValue.get(exec, *identifier, slot));
+ return JSValue::encode(baseValue.get(exec, *propertyName, slot));
}
-template<bool strict>
-ALWAYS_INLINE static void operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
+FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdOptimize);
+EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
- JSGlobalData* globalData = &exec->globalData();
-
JSValue baseValue = JSValue::decode(encodedBase);
- JSValue property = JSValue::decode(encodedProperty);
- JSValue value = JSValue::decode(encodedValue);
+ PropertySlot slot(baseValue);
+ JSValue result = baseValue.get(exec, *propertyName, slot);
- if (LIKELY(property.isUInt32())) {
- uint32_t i = property.asUInt32();
+ StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
+ if (stubInfo.seen)
+ dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo);
+ else
+ stubInfo.seen = true;
- if (isJSArray(globalData, baseValue)) {
- JSArray* jsArray = asArray(baseValue);
- if (jsArray->canSetIndex(i)) {
- jsArray->setIndex(*globalData, i, value);
- return;
- }
-
- jsArray->JSArray::put(exec, i, value);
- return;
- }
-
- if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
- JSByteArray* jsByteArray = asByteArray(baseValue);
- // FIXME: the JITstub used to relink this to an optimized form!
- if (value.isInt32()) {
- jsByteArray->setIndex(i, value.asInt32());
- return;
- }
-
- double dValue = 0;
- if (value.getNumber(dValue)) {
- jsByteArray->setIndex(i, dValue);
- return;
- }
- }
-
- baseValue.put(exec, i, value);
- return;
- }
-
- // Don't put to an object if toString throws an exception.
- Identifier ident(exec, property.toString(exec));
- if (!globalData->exception) {
- PutPropertySlot slot(strict);
- baseValue.put(exec, ident, value, slot);
- }
+ return JSValue::encode(result);
}
void operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
@@ -168,28 +197,28 @@
operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
}
-void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(true);
- JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot);
+ JSValue::decode(encodedBase).put(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
-void operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+void operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(false);
- JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot);
+ JSValue::decode(encodedBase).put(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
-void operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+void operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(true);
- JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot);
+ JSValue::decode(encodedBase).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
-void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier)
+void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(false);
- JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot);
+ JSValue::decode(encodedBase).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
bool operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
@@ -240,6 +269,7 @@
return JSValue::decode(encodedOp).toBoolean(exec);
}
+} // extern "C"
} } // namespace JSC::DFG
#endif
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (87430 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-05-26 21:37:05 UTC (rev 87431)
@@ -30,12 +30,9 @@
#include <dfg/DFGJITCompiler.h>
-namespace JSC {
+namespace JSC { namespace DFG {
+extern "C" {
-class Identifier;
-
-namespace DFG {
-
// These typedefs provide typechecking when generating calls out to helper routines;
// this helps prevent calling a helper routine with the wrong arguments!
typedef EncodedJSValue (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
@@ -54,6 +51,7 @@
EncodedJSValue operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
EncodedJSValue operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty);
EncodedJSValue operationGetById(ExecState*, EncodedJSValue encodedBase, Identifier*);
+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 operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
@@ -84,6 +82,7 @@
int32_t dfgConvertJSValueToInt32(ExecState*, EncodedJSValue);
bool dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue);
+} // extern "C"
} } // namespace JSC::DFG
#endif
Added: trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp (0 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp 2011-05-26 21:37:05 UTC (rev 87431)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 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 "DFGRepatch.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGOperations.h"
+#include "RepatchBuffer.h"
+
+namespace JSC { namespace DFG {
+
+static void dfgRepatchCall(CodeBlock* codeblock, CodeLocationCall call, FunctionPtr newCalleeFunction)
+{
+ RepatchBuffer repatchBuffer(codeblock);
+ repatchBuffer.relink(call, newCalleeFunction);
+}
+
+static void dfgRepatchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, size_t offset)
+{
+ RepatchBuffer repatchBuffer(codeBlock);
+
+ // Only optimize once!
+ repatchBuffer.relink(stubInfo.callReturnLocation, operationGetById);
+
+ // Patch the structure check & the offset of the load.
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.u.unset.deltaCheckToCall), structure);
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.u.unset.deltaCallToLoad), sizeof(JSValue) * offset);
+}
+
+static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier&, const PropertySlot& slot, StructureStubInfo& stubInfo)
+{
+ // FIXME: Write a test that proves we need to check for recursion here just
+ // like the interpreter does, then add a check for recursion.
+
+ CodeBlock* codeBlock = exec->codeBlock();
+ JSGlobalData* globalData = &exec->globalData();
+
+ // FIXME: should support length access for Array & String.
+
+ // FIXME: Cache property access for immediates.
+ if (!baseValue.isCell())
+ return false;
+ JSCell* baseCell = baseValue.asCell();
+ Structure* structure = baseCell->structure();
+ if (!slot.isCacheable())
+ return false;
+ if (structure->isUncacheableDictionary())
+ return false;
+
+ // Optimize self access.
+ if (slot.slotBase() == baseValue) {
+ if ((slot.cachedPropertyType() != PropertySlot::Value) || ((slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset))
+ return false;
+
+ dfgRepatchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset());
+ stubInfo.initGetByIdSelf(*globalData, codeBlock->ownerExecutable(), structure);
+ return true;
+ }
+
+ // FIXME: should support prototype & chain accesses!
+ return false;
+}
+
+void dfgRepatchGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
+{
+ bool cached = tryCacheGetByID(exec, baseValue, propertyName, slot, stubInfo);
+ if (!cached)
+ dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById);
+}
+
+} } // namespace JSC::DFG
+
+#endif
Added: trunk/Source/_javascript_Core/dfg/DFGRepatch.h (0 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGRepatch.h (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGRepatch.h 2011-05-26 21:37:05 UTC (rev 87431)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef DFGRepatch_h
+#define DFGRepatch_h
+
+#if ENABLE(DFG_JIT)
+
+#include <dfg/DFGJITCompiler.h>
+
+namespace JSC { namespace DFG {
+
+void dfgRepatchGetByID(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
+
+} } // namespace JSC::DFG
+
+#endif
+#endif
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (87430 => 87431)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-05-26 21:36:22 UTC (rev 87430)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-05-26 21:37:05 UTC (rev 87431)
@@ -185,9 +185,9 @@
GPRReg gpr = allocate();
if (node.isConstant()) {
- m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
JSValue jsValue = constantAsJSValue(nodeIndex);
if (jsValue.isCell()) {
+ m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr);
info.fillJSValue(gpr, DataFormatJSCell);
return gpr;
@@ -805,13 +805,37 @@
}
case GetById: {
- JSValueOperand base(this, node.child1);
+ SpeculateCellOperand base(this, node.child1);
+ GPRTemporary result(this, base);
+
GPRReg baseGPR = base.gpr();
- flushRegisters();
+ GPRReg resultGPR = result.gpr();
- GPRResult result(this);
- callOperation(operationGetById, result.gpr(), baseGPR, identifier(node.identifierNumber()));
- jsValueResult(result.gpr(), m_compileIndex);
+ JITCompiler::DataLabelPtr structureToCompare;
+ JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::Equal, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
+
+ silentSpillAllRegisters(resultGPR, baseGPR);
+ m_jit.move(baseGPR, GPRInfo::argumentGPR1);
+ m_jit.move(JITCompiler::ImmPtr(identifier(node.identifierNumber())), GPRInfo::argumentGPR2);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ JITCompiler::Call functionCall = appendCallWithExceptionCheck(operationGetByIdOptimize);
+ m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+ silentFillAllRegisters(resultGPR);
+
+ JITCompiler::Jump handledByC = m_jit.jump();
+ structureCheck.link(&m_jit);
+
+ m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ JITCompiler::DataLabelCompact loadWithPatch = m_jit.loadPtrWithCompactAddressOffsetPatch(JITCompiler::Address(resultGPR, 0), resultGPR);
+
+ intptr_t checkToCall = m_jit.differenceBetween(structureToCompare, functionCall);
+ intptr_t callToLoad = m_jit.differenceBetween(functionCall, loadWithPatch);
+
+ handledByC.link(&m_jit);
+
+ m_jit.addPropertyAccess(functionCall, checkToCall, callToLoad);
+
+ jsValueResult(resultGPR, m_compileIndex);
break;
}