Title: [134332] trunk/Source/_javascript_Core
Revision
134332
Author
[email protected]
Date
2012-11-12 17:55:42 -0800 (Mon, 12 Nov 2012)

Log Message

Patching of jumps to stubs should use jump replacement rather than branch destination overwrite
https://bugs.webkit.org/show_bug.cgi?id=101909

Reviewed by Geoffrey Garen.

This saves a few instructions in inline cases, on those architectures where it is
easy to figure out where to put the jump replacement. Sub-1% speed-up across the
board.

* assembler/MacroAssemblerARMv7.h:
(MacroAssemblerARMv7):
(JSC::MacroAssemblerARMv7::canJumpReplacePatchableBranchPtrWithPatch):
(JSC::MacroAssemblerARMv7::startOfPatchableBranchPtrWithPatch):
(JSC::MacroAssemblerARMv7::revertJumpReplacementToPatchableBranchPtrWithPatch):
* assembler/MacroAssemblerX86.h:
(JSC::MacroAssemblerX86::canJumpReplacePatchableBranchPtrWithPatch):
(MacroAssemblerX86):
(JSC::MacroAssemblerX86::startOfPatchableBranchPtrWithPatch):
(JSC::MacroAssemblerX86::revertJumpReplacementToPatchableBranchPtrWithPatch):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::canJumpReplacePatchableBranchPtrWithPatch):
(MacroAssemblerX86_64):
(JSC::MacroAssemblerX86_64::startOfPatchableBranchPtrWithPatch):
(JSC::MacroAssemblerX86_64::revertJumpReplacementToPatchableBranchPtrWithPatch):
* assembler/RepatchBuffer.h:
(JSC::RepatchBuffer::startOfPatchableBranchPtrWithPatch):
(RepatchBuffer):
(JSC::RepatchBuffer::replaceWithJump):
(JSC::RepatchBuffer::revertJumpReplacementToPatchableBranchPtrWithPatch):
* assembler/X86Assembler.h:
(X86Assembler):
(JSC::X86Assembler::revertJumpTo_movq_i64r):
(JSC::X86Assembler::revertJumpTo_cmpl_im_force32):
(X86InstructionFormatter):
* bytecode/StructureStubInfo.h:
* dfg/DFGRepatch.cpp:
(JSC::DFG::replaceWithJump):
(DFG):
(JSC::DFG::tryCacheGetByID):
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::tryBuildGetByIDProtoList):
(JSC::DFG::tryCachePutByID):
(JSC::DFG::dfgResetGetByID):
(JSC::DFG::dfgResetPutByID):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (134331 => 134332)


--- trunk/Source/_javascript_Core/ChangeLog	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-11-13 01:55:42 UTC (rev 134332)
@@ -1,3 +1,50 @@
+2012-11-12  Filip Pizlo  <[email protected]>
+
+        Patching of jumps to stubs should use jump replacement rather than branch destination overwrite
+        https://bugs.webkit.org/show_bug.cgi?id=101909
+
+        Reviewed by Geoffrey Garen.
+
+        This saves a few instructions in inline cases, on those architectures where it is
+        easy to figure out where to put the jump replacement. Sub-1% speed-up across the
+        board.
+
+        * assembler/MacroAssemblerARMv7.h:
+        (MacroAssemblerARMv7):
+        (JSC::MacroAssemblerARMv7::canJumpReplacePatchableBranchPtrWithPatch):
+        (JSC::MacroAssemblerARMv7::startOfPatchableBranchPtrWithPatch):
+        (JSC::MacroAssemblerARMv7::revertJumpReplacementToPatchableBranchPtrWithPatch):
+        * assembler/MacroAssemblerX86.h:
+        (JSC::MacroAssemblerX86::canJumpReplacePatchableBranchPtrWithPatch):
+        (MacroAssemblerX86):
+        (JSC::MacroAssemblerX86::startOfPatchableBranchPtrWithPatch):
+        (JSC::MacroAssemblerX86::revertJumpReplacementToPatchableBranchPtrWithPatch):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::canJumpReplacePatchableBranchPtrWithPatch):
+        (MacroAssemblerX86_64):
+        (JSC::MacroAssemblerX86_64::startOfPatchableBranchPtrWithPatch):
+        (JSC::MacroAssemblerX86_64::revertJumpReplacementToPatchableBranchPtrWithPatch):
+        * assembler/RepatchBuffer.h:
+        (JSC::RepatchBuffer::startOfPatchableBranchPtrWithPatch):
+        (RepatchBuffer):
+        (JSC::RepatchBuffer::replaceWithJump):
+        (JSC::RepatchBuffer::revertJumpReplacementToPatchableBranchPtrWithPatch):
+        * assembler/X86Assembler.h:
+        (X86Assembler):
+        (JSC::X86Assembler::revertJumpTo_movq_i64r):
+        (JSC::X86Assembler::revertJumpTo_cmpl_im_force32):
+        (X86InstructionFormatter):
+        * bytecode/StructureStubInfo.h:
+        * dfg/DFGRepatch.cpp:
+        (JSC::DFG::replaceWithJump):
+        (DFG):
+        (JSC::DFG::tryCacheGetByID):
+        (JSC::DFG::tryBuildGetByIDList):
+        (JSC::DFG::tryBuildGetByIDProtoList):
+        (JSC::DFG::tryCachePutByID):
+        (JSC::DFG::dfgResetGetByID):
+        (JSC::DFG::dfgResetPutByID):
+
 2012-11-11  Filip Pizlo  <[email protected]>
 
         DFG ArithMul overflow check elimination is too aggressive

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h (134331 => 134332)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h	2012-11-13 01:55:42 UTC (rev 134332)
@@ -1758,6 +1758,18 @@
     {
         return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
     }
+    
+    static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
+    
+    static CodeLocationLabel startOfPatchableBranchPtrWithPatch(CodeLocationDataLabelPtr label)
+    {
+        UNREACHABLE_FOR_PLATFORM();
+    }
+    
+    static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
+    {
+        UNREACHABLE_FOR_PLATFORM();
+    }
 
 protected:
     ALWAYS_INLINE Jump jump()

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h (134331 => 134332)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h	2012-11-13 01:55:42 UTC (rev 134332)
@@ -253,6 +253,25 @@
         return FunctionPtr(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(call.dataLocation()) + offset));
     }
 
+    static bool canJumpReplacePatchableBranchPtrWithPatch() { return true; }
+    
+    static CodeLocationLabel startOfPatchableBranchPtrWithPatch(CodeLocationDataLabelPtr label)
+    {
+        const int opcodeBytes = 1;
+        const int modRMBytes = 1;
+        const int offsetBytes = 0;
+        const int immediateBytes = 4;
+        const int totalBytes = opcodeBytes + modRMBytes + offsetBytes + immediateBytes;
+        ASSERT(totalBytes >= maxJumpReplacementSize());
+        return label.labelAtOffset(-totalBytes);
+    }
+    
+    static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address address, void* initialValue)
+    {
+        ASSERT(!address.offset);
+        X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), 0, address.base);
+    }
+
 private:
     friend class LinkBuffer;
     friend class RepatchBuffer;

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (134331 => 134332)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2012-11-13 01:55:42 UTC (rev 134332)
@@ -585,6 +585,23 @@
 
     static RegisterID scratchRegisterForBlinding() { return scratchRegister; }
 
+    static bool canJumpReplacePatchableBranchPtrWithPatch() { return true; }
+    
+    static CodeLocationLabel startOfPatchableBranchPtrWithPatch(CodeLocationDataLabelPtr label)
+    {
+        const int rexBytes = 1;
+        const int opcodeBytes = 1;
+        const int immediateBytes = 8;
+        const int totalBytes = rexBytes + opcodeBytes + immediateBytes;
+        ASSERT(totalBytes >= maxJumpReplacementSize());
+        return label.labelAtOffset(-totalBytes);
+    }
+    
+    static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address, void* initialValue)
+    {
+        X86Assembler::revertJumpTo_movq_i64r(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), scratchRegister);
+    }
+
 private:
     friend class LinkBuffer;
     friend class RepatchBuffer;

Modified: trunk/Source/_javascript_Core/assembler/RepatchBuffer.h (134331 => 134332)


--- trunk/Source/_javascript_Core/assembler/RepatchBuffer.h	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/assembler/RepatchBuffer.h	2012-11-13 01:55:42 UTC (rev 134332)
@@ -141,6 +141,24 @@
             replaceWithAddressComputation(label);
     }
 
+    static CodeLocationLabel startOfPatchableBranchPtrWithPatch(CodeLocationDataLabelPtr label)
+    {
+        return MacroAssembler::startOfPatchableBranchPtrWithPatch(label);
+    }
+    
+    void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
+    {
+        MacroAssembler::replaceWithJump(instructionStart, destination);
+    }
+    
+    // This is a *bit* of a silly API, since we currently always also repatch the
+    // immediate after calling this. But I'm fine with that, since this just feels
+    // less yucky.
+    void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, MacroAssembler::Address address, void* value)
+    {
+        MacroAssembler::revertJumpReplacementToPatchableBranchPtrWithPatch(instructionStart, address, value);
+    }
+
 private:
     void* m_start;
     size_t m_size;

Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (134331 => 134332)


--- trunk/Source/_javascript_Core/assembler/X86Assembler.h	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h	2012-11-13 01:55:42 UTC (rev 134332)
@@ -1883,6 +1883,44 @@
         return 5;
     }
     
+#if CPU(X86_64)
+    static void revertJumpTo_movq_i64r(void* instructionStart, int64_t imm, RegisterID dst)
+    {
+        const int rexBytes = 1;
+        const int opcodeBytes = 1;
+        ASSERT(rexBytes + opcodeBytes <= maxJumpReplacementSize());
+        uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
+        ptr[0] = PRE_REX | (1 << 3) | (dst >> 3);
+        ptr[1] = OP_MOV_EAXIv | (dst & 7);
+        
+        union {
+            uint64_t asWord;
+            uint8_t asBytes[8];
+        } u;
+        u.asWord = imm;
+        for (unsigned i = rexBytes + opcodeBytes; i < static_cast<unsigned>(maxJumpReplacementSize()); ++i)
+            ptr[i] = u.asBytes[i - rexBytes - opcodeBytes];
+    }
+#endif
+    
+    static void revertJumpTo_cmpl_im_force32(void* instructionStart, int32_t imm, int offset, RegisterID dst)
+    {
+        ASSERT_UNUSED(offset, !offset);
+        const int opcodeBytes = 1;
+        const int modRMBytes = 1;
+        ASSERT(opcodeBytes + modRMBytes <= maxJumpReplacementSize());
+        uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
+        ptr[0] = OP_GROUP1_EvIz;
+        ptr[1] = (X86InstructionFormatter::ModRmMemoryNoDisp << 6) | (GROUP1_OP_CMP << 3) | dst;
+        union {
+            uint32_t asWord;
+            uint8_t asBytes[4];
+        } u;
+        u.asWord = imm;
+        for (unsigned i = opcodeBytes + modRMBytes; i < static_cast<unsigned>(maxJumpReplacementSize()); ++i)
+            ptr[i] = u.asBytes[i - opcodeBytes - modRMBytes];
+    }
+    
     static void replaceWithLoad(void* instructionStart)
     {
         uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
@@ -1982,6 +2020,13 @@
 
     public:
 
+        enum ModRmMode {
+            ModRmMemoryNoDisp,
+            ModRmMemoryDisp8,
+            ModRmMemoryDisp32,
+            ModRmRegister,
+        };
+
         // Legacy prefix bytes:
         //
         // These are emmitted prior to the instruction.
@@ -2352,13 +2397,6 @@
         inline void emitRexIfNeeded(int, int, int) {}
 #endif
 
-        enum ModRmMode {
-            ModRmMemoryNoDisp,
-            ModRmMemoryDisp8,
-            ModRmMemoryDisp32,
-            ModRmRegister,
-        };
-
         void putModRm(ModRmMode mode, int reg, RegisterID rm)
         {
             m_buffer.putByteUnchecked((mode << 6) | ((reg & 7) << 3) | (rm & 7));

Modified: trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h (134331 => 134332)


--- trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/bytecode/StructureStubInfo.h	2012-11-13 01:55:42 UTC (rev 134332)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions

Modified: trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp (134331 => 134332)


--- trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp	2012-11-13 01:26:17 UTC (rev 134331)
+++ trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp	2012-11-13 01:55:42 UTC (rev 134332)
@@ -114,6 +114,23 @@
         failureCases, scratchGPR);
 }
 
+static void replaceWithJump(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo, const MacroAssemblerCodePtr target)
+{
+    if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) {
+        repatchBuffer.replaceWithJump(
+            RepatchBuffer::startOfPatchableBranchPtrWithPatch(
+                stubInfo.callReturnLocation.dataLabelPtrAtOffset(
+                    -(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall)),
+            CodeLocationLabel(target));
+        return;
+    }
+    
+    repatchBuffer.relink(
+        stubInfo.callReturnLocation.jumpAtOffset(
+            stubInfo.patch.dfg.deltaCallToStructCheck),
+        CodeLocationLabel(target));
+}
+
 static void emitRestoreScratch(MacroAssembler& stubJit, bool needToRestoreScratch, GPRReg scratchGPR, MacroAssembler::Jump& success, MacroAssembler::Jump& fail, MacroAssembler::JumpList failureCases)
 {
     if (needToRestoreScratch) {
@@ -284,7 +301,7 @@
                  stubInfo.patch.dfg.deltaCallToDone).executableAddress()));
         
         RepatchBuffer repatchBuffer(codeBlock);
-        repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
+        replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code());
         repatchBuffer.relink(stubInfo.callReturnLocation, operationGetById);
         
         return true;
@@ -334,7 +351,7 @@
     generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase), stubInfo.stubRoutine);
     
     RepatchBuffer repatchBuffer(codeBlock);
-    repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
+    replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code());
     repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList);
     
     stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain, count, true);
@@ -518,9 +535,11 @@
         
         polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, isDirect);
         
-        CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck);
         RepatchBuffer repatchBuffer(codeBlock);
-        repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code()));
+        repatchBuffer.relink(
+            stubInfo.callReturnLocation.jumpAtOffset(
+                stubInfo.patch.dfg.deltaCallToStructCheck),
+            CodeLocationLabel(stubRoutine->code().code()));
         
         if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
             return true;
@@ -584,9 +603,8 @@
         
         polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true);
         
-        CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck);
         RepatchBuffer repatchBuffer(codeBlock);
-        repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code()));
+        replaceWithJump(repatchBuffer, stubInfo, stubRoutine->code().code());
         
         if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
             return true;
@@ -976,7 +994,10 @@
                 stubInfo.stubRoutine);
             
             RepatchBuffer repatchBuffer(codeBlock);
-            repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code()));
+            repatchBuffer.relink(
+                stubInfo.callReturnLocation.jumpAtOffset(
+                    stubInfo.patch.dfg.deltaCallToStructCheck),
+                CodeLocationLabel(stubInfo.stubRoutine->code().code()));
             repatchBuffer.relink(stubInfo.callReturnLocation, appropriateListBuildingPutByIdFunction(slot, putKind));
             
             stubInfo.initPutByIdTransition(*globalData, codeBlock->ownerExecutable(), oldStructure, structure, prototypeChain, putKind == Direct);
@@ -1118,7 +1139,16 @@
 void dfgResetGetByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo)
 {
     repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdOptimize);
-    repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1));
+    CodeLocationDataLabelPtr structureLabel = stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall);
+    if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) {
+        repatchBuffer.revertJumpReplacementToPatchableBranchPtrWithPatch(
+            RepatchBuffer::startOfPatchableBranchPtrWithPatch(structureLabel),
+            MacroAssembler::Address(
+                static_cast<MacroAssembler::RegisterID>(stubInfo.patch.dfg.baseGPR),
+                JSCell::structureOffset()),
+            reinterpret_cast<void*>(-1));
+    }
+    repatchBuffer.repatch(structureLabel, reinterpret_cast<void*>(-1));
 #if USE(JSVALUE64)
     repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0);
 #else
@@ -1143,7 +1173,16 @@
         optimizedFunction = operationPutByIdDirectNonStrictOptimize;
     }
     repatchBuffer.relink(stubInfo.callReturnLocation, optimizedFunction);
-    repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1));
+    CodeLocationDataLabelPtr structureLabel = stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall);
+    if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) {
+        repatchBuffer.revertJumpReplacementToPatchableBranchPtrWithPatch(
+            RepatchBuffer::startOfPatchableBranchPtrWithPatch(structureLabel),
+            MacroAssembler::Address(
+                static_cast<MacroAssembler::RegisterID>(stubInfo.patch.dfg.baseGPR),
+                JSCell::structureOffset()),
+            reinterpret_cast<void*>(-1));
+    }
+    repatchBuffer.repatch(structureLabel, reinterpret_cast<void*>(-1));
 #if USE(JSVALUE64)
     repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0);
 #else
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to