Refactor MASM probe to allow printing of custom types.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Apr 2017 21:42:24 +0000 (21:42 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Apr 2017 21:42:24 +0000 (21:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=171101

Reviewed by JF Bastien.

For example, this allows us to add MASM printing of CodeBlock* and Air::Args.

In general, MASM print can be used like dataLog, except that it generates JITted
code for doing the dataLogging later when the JITted code runs.  MASM print can
print any value type that a specialized Printer template or a setPrinter()
function implemented for that type.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/MacroAssembler.h:

* assembler/MacroAssemblerPrinter.cpp:
(JSC::Printer::printAllRegisters):
(JSC::Printer::printPCRegister):
(JSC::Printer::printRegisterID):
(JSC::Printer::printFPRegisterID):
(JSC::Printer::printAddress):
(JSC::Printer::printMemory):
(JSC::Printer::printCallback):
(JSC::printIndent): Deleted.
(JSC::printCPU): Deleted.
(JSC::printCPURegisters): Deleted.
(JSC::printPC): Deleted.
(JSC::printRegister): Deleted.
(JSC::printMemory): Deleted.
(JSC::MacroAssemblerPrinter::printCallback): Deleted.
* assembler/MacroAssemblerPrinter.h:
(JSC::AllRegisters::AllRegisters):
(JSC::Printer::Printer<AllRegisters>::Printer):
(JSC::Printer::Printer<PCRegister>::Printer):
(JSC::Printer::Printer<MacroAssembler::RegisterID>::Printer):
(JSC::Printer::Printer<MacroAssembler::FPRegisterID>::Printer):
(JSC::Printer::Printer<MacroAssembler::Address>::Printer):
(JSC::Printer::Printer<Memory>::Printer):
(JSC::Printer::Printer<MemWord<IntType>>::Printer):
(JSC::MacroAssembler::print):
(JSC::MacroAssemblerPrinter::print): Deleted.
(JSC::MacroAssemblerPrinter::PrintArg::PrintArg): Deleted.
(JSC::MacroAssemblerPrinter::appendPrintArg): Deleted.
- Refactored to move the underlying PrintRecord (and associated data structures)
  out to Printer.cpp/h.
- MacroAssemblerPrinter.cpp/h now only add custom Printers for MASM types like
  RegisterID and Memory.  It also defines the implementation of
  MacroAssembler::print().

  As before, JIT code that wishes to use MacroAssembler::print() needs to
  #include "MacroAssemblerPrinter.h".

- Also added the ability to specify an optional indentation (in number of chars)
  when MASM printing AllRegisters.  This is useful because AllRegisters prints
  a block of data unlike other printers which print inline.

* assembler/Printer.cpp: Added.
(JSC::Printer::printConstCharString):
(JSC::Printer::printIntptr):
(JSC::Printer::printUintptr):
(JSC::Printer::printPointer):
(JSC::Printer::setPrinter):
* assembler/Printer.h: Added.
(JSC::Printer::Context::Context):
(JSC::Printer::PrintRecord::PrintRecord):
(JSC::Printer::appendPrinter):
(JSC::Printer::makePrintRecordList):
(JSC::Printer::Printer<RawPointer>::Printer):
(JSC::Printer::setPrinter):
(JSC::Printer::Printer::Printer):
- Data structures for creating a list of PrintRecords.  Classes which wish to
  add custom support for MASM printing can #include "Printer.h" and implement
  either:
  1. a specialized Printer template, or
  2. a setPrinter() function.

  See Printer<Reg> and Printer<B3::Air::Tmp> in AirPrintSpecial.h for examples of
  (1).  See CodeBlock's setPrinter() for an example of (2).

* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::print):
* b3/air/AirPrintSpecial.cpp: Added.
(JSC::B3::Air::PrintSpecial::PrintSpecial):
(JSC::B3::Air::PrintSpecial::~PrintSpecial):
(JSC::B3::Air::PrintSpecial::forEachArg):
(JSC::B3::Air::PrintSpecial::isValid):
(JSC::B3::Air::PrintSpecial::admitsStack):
(JSC::B3::Air::PrintSpecial::reportUsedRegisters):
(JSC::B3::Air::PrintSpecial::generate):
(JSC::B3::Air::PrintSpecial::extraEarlyClobberedRegs):
(JSC::B3::Air::PrintSpecial::extraClobberedRegs):
(JSC::B3::Air::PrintSpecial::dumpImpl):
(JSC::B3::Air::PrintSpecial::deepDumpImpl):
(JSC::Printer::printAirArg):
* b3/air/AirPrintSpecial.h: Added.
(JSC::Printer::appendAirArg):
(JSC::Printer::appendAirArgs):
(JSC::Printer::Printer<B3::Air::Tmp>::Printer):
(JSC::Printer::Printer<Reg>::Printer):
- Add the print() operation for use in LowerToAir.  print() will emit a
  PrintSpecial that will ultimately emit a MASM print to print what we want.
- LowerToAir's print() adds the ability to print Air::Args.
- Unlike in the baseline JIT and the DFG, LowerToAir's print() can perturb the
  usage of registers.  This is because PrintSpecial is a patch point, and it
  prevents certain optimizations.  If not used carefully, an attempt to print()
  an Arg by taking a Tmp, can force the B3 Value into a Tmp earlier than it would
  otherwise do so.  So, use LowerToAir's print() with care.

* bytecode/CodeBlock.cpp:
(JSC::setPrinter):
- Now we can MASM print CodeBlock*.
(WTF::printInternal):
- Now we can dataLog CodeBlock* (including null CodeBlock pointers).

* bytecode/CodeBlock.h:

* runtime/VM.cpp:
(JSC::VM::throwException):
- Use the new ability to dataLog CodeBlock*.  No need to do an explicit null
  check before printing anymore.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215642 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/assembler/MacroAssembler.h
Source/JavaScriptCore/assembler/MacroAssemblerPrinter.cpp
Source/JavaScriptCore/assembler/MacroAssemblerPrinter.h
Source/JavaScriptCore/assembler/Printer.cpp [new file with mode: 0644]
Source/JavaScriptCore/assembler/Printer.h [new file with mode: 0644]
Source/JavaScriptCore/b3/B3LowerToAir.cpp
Source/JavaScriptCore/b3/air/AirPrintSpecial.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/air/AirPrintSpecial.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/runtime/VM.cpp

index 724b6f5..319b3e0 100644 (file)
@@ -72,6 +72,7 @@ set(JavaScriptCore_SOURCES
     assembler/MacroAssemblerCodeRef.cpp
     assembler/MacroAssemblerPrinter.cpp
     assembler/MacroAssemblerX86Common.cpp
+    assembler/Printer.cpp
 
     b3/air/AirAllocateRegistersAndStackByLinearScan.cpp
     b3/air/AirAllocateRegistersByGraphColoring.cpp
@@ -105,6 +106,7 @@ set(JavaScriptCore_SOURCES
     b3/air/AirPadInterference.cpp
     b3/air/AirPhaseInsertionSet.cpp
     b3/air/AirPhaseScope.cpp
+    b3/air/AirPrintSpecial.cpp
     b3/air/AirRegLiveness.cpp
     b3/air/AirReportUsedRegisters.cpp
     b3/air/AirSimplifyCFG.cpp
index 7309731..454f9b8 100644 (file)
@@ -1,3 +1,127 @@
+2017-04-20  Mark Lam  <mark.lam@apple.com>
+
+        Refactor MASM probe to allow printing of custom types.
+        https://bugs.webkit.org/show_bug.cgi?id=171101
+
+        Reviewed by JF Bastien.
+
+        For example, this allows us to add MASM printing of CodeBlock* and Air::Args.
+
+        In general, MASM print can be used like dataLog, except that it generates JITted
+        code for doing the dataLogging later when the JITted code runs.  MASM print can
+        print any value type that a specialized Printer template or a setPrinter()
+        function implemented for that type.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * assembler/MacroAssembler.h:
+
+        * assembler/MacroAssemblerPrinter.cpp:
+        (JSC::Printer::printAllRegisters):
+        (JSC::Printer::printPCRegister):
+        (JSC::Printer::printRegisterID):
+        (JSC::Printer::printFPRegisterID):
+        (JSC::Printer::printAddress):
+        (JSC::Printer::printMemory):
+        (JSC::Printer::printCallback):
+        (JSC::printIndent): Deleted.
+        (JSC::printCPU): Deleted.
+        (JSC::printCPURegisters): Deleted.
+        (JSC::printPC): Deleted.
+        (JSC::printRegister): Deleted.
+        (JSC::printMemory): Deleted.
+        (JSC::MacroAssemblerPrinter::printCallback): Deleted.
+        * assembler/MacroAssemblerPrinter.h:
+        (JSC::AllRegisters::AllRegisters):
+        (JSC::Printer::Printer<AllRegisters>::Printer):
+        (JSC::Printer::Printer<PCRegister>::Printer):
+        (JSC::Printer::Printer<MacroAssembler::RegisterID>::Printer):
+        (JSC::Printer::Printer<MacroAssembler::FPRegisterID>::Printer):
+        (JSC::Printer::Printer<MacroAssembler::Address>::Printer):
+        (JSC::Printer::Printer<Memory>::Printer):
+        (JSC::Printer::Printer<MemWord<IntType>>::Printer):
+        (JSC::MacroAssembler::print):
+        (JSC::MacroAssemblerPrinter::print): Deleted.
+        (JSC::MacroAssemblerPrinter::PrintArg::PrintArg): Deleted.
+        (JSC::MacroAssemblerPrinter::appendPrintArg): Deleted.
+        - Refactored to move the underlying PrintRecord (and associated data structures)
+          out to Printer.cpp/h.
+        - MacroAssemblerPrinter.cpp/h now only add custom Printers for MASM types like
+          RegisterID and Memory.  It also defines the implementation of
+          MacroAssembler::print().
+
+          As before, JIT code that wishes to use MacroAssembler::print() needs to
+          #include "MacroAssemblerPrinter.h".
+
+        - Also added the ability to specify an optional indentation (in number of chars)
+          when MASM printing AllRegisters.  This is useful because AllRegisters prints
+          a block of data unlike other printers which print inline.
+
+        * assembler/Printer.cpp: Added.
+        (JSC::Printer::printConstCharString):
+        (JSC::Printer::printIntptr):
+        (JSC::Printer::printUintptr):
+        (JSC::Printer::printPointer):
+        (JSC::Printer::setPrinter):
+        * assembler/Printer.h: Added.
+        (JSC::Printer::Context::Context):
+        (JSC::Printer::PrintRecord::PrintRecord):
+        (JSC::Printer::appendPrinter):
+        (JSC::Printer::makePrintRecordList):
+        (JSC::Printer::Printer<RawPointer>::Printer):
+        (JSC::Printer::setPrinter):
+        (JSC::Printer::Printer::Printer):
+        - Data structures for creating a list of PrintRecords.  Classes which wish to
+          add custom support for MASM printing can #include "Printer.h" and implement
+          either:
+          1. a specialized Printer template, or
+          2. a setPrinter() function.
+
+          See Printer<Reg> and Printer<B3::Air::Tmp> in AirPrintSpecial.h for examples of
+          (1).  See CodeBlock's setPrinter() for an example of (2).
+
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::print):
+        * b3/air/AirPrintSpecial.cpp: Added.
+        (JSC::B3::Air::PrintSpecial::PrintSpecial):
+        (JSC::B3::Air::PrintSpecial::~PrintSpecial):
+        (JSC::B3::Air::PrintSpecial::forEachArg):
+        (JSC::B3::Air::PrintSpecial::isValid):
+        (JSC::B3::Air::PrintSpecial::admitsStack):
+        (JSC::B3::Air::PrintSpecial::reportUsedRegisters):
+        (JSC::B3::Air::PrintSpecial::generate):
+        (JSC::B3::Air::PrintSpecial::extraEarlyClobberedRegs):
+        (JSC::B3::Air::PrintSpecial::extraClobberedRegs):
+        (JSC::B3::Air::PrintSpecial::dumpImpl):
+        (JSC::B3::Air::PrintSpecial::deepDumpImpl):
+        (JSC::Printer::printAirArg):
+        * b3/air/AirPrintSpecial.h: Added.
+        (JSC::Printer::appendAirArg):
+        (JSC::Printer::appendAirArgs):
+        (JSC::Printer::Printer<B3::Air::Tmp>::Printer):
+        (JSC::Printer::Printer<Reg>::Printer):
+        - Add the print() operation for use in LowerToAir.  print() will emit a
+          PrintSpecial that will ultimately emit a MASM print to print what we want.
+        - LowerToAir's print() adds the ability to print Air::Args.
+        - Unlike in the baseline JIT and the DFG, LowerToAir's print() can perturb the
+          usage of registers.  This is because PrintSpecial is a patch point, and it
+          prevents certain optimizations.  If not used carefully, an attempt to print()
+          an Arg by taking a Tmp, can force the B3 Value into a Tmp earlier than it would
+          otherwise do so.  So, use LowerToAir's print() with care.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::setPrinter):
+        - Now we can MASM print CodeBlock*.
+        (WTF::printInternal):
+        - Now we can dataLog CodeBlock* (including null CodeBlock pointers).
+
+        * bytecode/CodeBlock.h:
+
+        * runtime/VM.cpp:
+        (JSC::VM::throwException):
+        - Use the new ability to dataLog CodeBlock*.  No need to do an explicit null
+          check before printing anymore.
+
 2017-04-21  Keith Miller  <keith_miller@apple.com>
 
         Unreviewed, rolling out r215634.
index 24e6c4d..490a606 100644 (file)
                FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4D55B71AE716CA0052E459 /* IterationStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE5068651AE246390009DAB7 /* DeferredSourceDump.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5068641AE246390009DAB7 /* DeferredSourceDump.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE5068671AE25E280009DAB7 /* DeferredSourceDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5068661AE25E280009DAB7 /* DeferredSourceDump.cpp */; };
+               FE5628CD1E99512D00C49E45 /* AirPrintSpecial.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5628CB1E99512400C49E45 /* AirPrintSpecial.cpp */; };
+               FE5628CE1E99513200C49E45 /* AirPrintSpecial.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5628CC1E99512400C49E45 /* AirPrintSpecial.h */; };
                FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */; };
                FE5932A8183C5A2600A1ECCC /* VMEntryScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE6029D91D6E1E4F0030204D /* ExceptionEventLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = FE6029D81D6E1E330030204D /* ExceptionEventLocation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE63DD541EA9B61E00103A69 /* Printer.h in Headers */ = {isa = PBXBuildFile; fileRef = FE63DD531EA9B60E00103A69 /* Printer.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE63DD561EA9BC6700103A69 /* Printer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE63DD551EA9BC5D00103A69 /* Printer.cpp */; };
                FE6491371D78F01D00A694D4 /* ExceptionScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE6491361D78F01300A694D4 /* ExceptionScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE6491391D78F3AF00A694D4 /* ExceptionScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE6491381D78F3A300A694D4 /* ExceptionScope.cpp */; };
                FE68C6371B90DE040042BCB3 /* MacroAssemblerPrinter.h in Headers */ = {isa = PBXBuildFile; fileRef = FE68C6361B90DDD90042BCB3 /* MacroAssemblerPrinter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE4D55B71AE716CA0052E459 /* IterationStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IterationStatus.h; sourceTree = "<group>"; };
                FE5068641AE246390009DAB7 /* DeferredSourceDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeferredSourceDump.h; sourceTree = "<group>"; };
                FE5068661AE25E280009DAB7 /* DeferredSourceDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeferredSourceDump.cpp; sourceTree = "<group>"; };
+               FE5628CB1E99512400C49E45 /* AirPrintSpecial.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirPrintSpecial.cpp; path = b3/air/AirPrintSpecial.cpp; sourceTree = "<group>"; };
+               FE5628CC1E99512400C49E45 /* AirPrintSpecial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirPrintSpecial.h; path = b3/air/AirPrintSpecial.h; sourceTree = "<group>"; };
                FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMEntryScope.cpp; sourceTree = "<group>"; };
                FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMEntryScope.h; sourceTree = "<group>"; };
                FE6029D81D6E1E330030204D /* ExceptionEventLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionEventLocation.h; sourceTree = "<group>"; };
+               FE63DD531EA9B60E00103A69 /* Printer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Printer.h; sourceTree = "<group>"; };
+               FE63DD551EA9BC5D00103A69 /* Printer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Printer.cpp; sourceTree = "<group>"; };
                FE6491361D78F01300A694D4 /* ExceptionScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionScope.h; sourceTree = "<group>"; };
                FE6491381D78F3A300A694D4 /* ExceptionScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExceptionScope.cpp; sourceTree = "<group>"; };
                FE68C6351B90DDD90042BCB3 /* MacroAssemblerPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssemblerPrinter.cpp; sourceTree = "<group>"; };
                                0F2AC56D1E8D7AFF0001EE3F /* AirPhaseInsertionSet.h */,
                                0FEC855E1BDACDC70080FF74 /* AirPhaseScope.cpp */,
                                0FEC855F1BDACDC70080FF74 /* AirPhaseScope.h */,
+                               FE5628CB1E99512400C49E45 /* AirPrintSpecial.cpp */,
+                               FE5628CC1E99512400C49E45 /* AirPrintSpecial.h */,
                                0FF4B4BA1E88449500DBBE86 /* AirRegLiveness.cpp */,
                                0FF4B4BB1E88449500DBBE86 /* AirRegLiveness.h */,
                                0F45703A1BE45F0A0062A629 /* AirReportUsedRegisters.cpp */,
                                860161E20F3A83C100F84710 /* MacroAssemblerX86Common.h */,
                                65860177185A8F5E00030EEE /* MaxFrameExtentForSlowPathCall.h */,
                                86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */,
+                               FE63DD551EA9BC5D00103A69 /* Printer.cpp */,
+                               FE63DD531EA9B60E00103A69 /* Printer.h */,
                                9688CB140ED12B4E001D649F /* X86Assembler.h */,
                        );
                        path = assembler;
                                0F6B8ADD1C4EFAC300969052 /* B3SSACalculator.h in Headers */,
                                0F33FCF81C136E2500323F67 /* B3StackmapGenerationParams.h in Headers */,
                                0FEC85311BDACDAC0080FF74 /* B3StackmapSpecial.h in Headers */,
+                               FE5628CE1E99513200C49E45 /* AirPrintSpecial.h in Headers */,
                                0F338DF21BE93AD10013C88F /* B3StackmapValue.h in Headers */,
                                0F9495881C57F47500413A48 /* B3StackSlot.h in Headers */,
                                0FEC85361BDACDAC0080FF74 /* B3SuccessorCollection.h in Headers */,
                                0F235BEC17178E7300690C7F /* DFGOSRExitBase.h in Headers */,
                                0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */,
                                0FC0977114693AF500CF2442 /* DFGOSRExitCompiler.h in Headers */,
+                               FE63DD541EA9B61E00103A69 /* Printer.h in Headers */,
                                0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */,
                                0F392C8A1B46188400844728 /* DFGOSRExitFuzz.h in Headers */,
                                0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */,
                                7980C16C1E3A940E00B71615 /* DFGRegisteredStructureSet.cpp in Sources */,
                                0F2FCCFB18A60070001A27F8 /* DFGSafepoint.cpp in Sources */,
                                86EC9DD21328DF82002B2AD7 /* DFGSpeculativeJIT.cpp in Sources */,
+                               FE63DD561EA9BC6700103A69 /* Printer.cpp in Sources */,
                                86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */,
                                86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */,
                                0F682FB219BCB36400FA3BAD /* DFGSSACalculator.cpp in Sources */,
                                1440F8920A508B100005F061 /* JSCallbackFunction.cpp in Sources */,
                                14ABDF600A437FEF00ECCA01 /* JSCallbackObject.cpp in Sources */,
                                657CF45819BF6662004ACBF2 /* JSCallee.cpp in Sources */,
+                               FE5628CD1E99512D00C49E45 /* AirPrintSpecial.cpp in Sources */,
                                A7D801A81880D6A80026C39B /* JSCBuiltins.cpp in Sources */,
                                147F39D1107EC37600427A48 /* JSCell.cpp in Sources */,
                                79ABB17D1E5CCB570045B9A6 /* AirDisassembler.cpp in Sources */,
index ee3973a..0050275 100644 (file)
@@ -63,6 +63,13 @@ namespace JSC { typedef MacroAssemblerX86_64 MacroAssemblerBase; };
 
 namespace JSC {
 
+namespace Printer {
+
+struct PrintRecord;
+typedef Vector<PrintRecord> PrintRecordList;
+
+}
+
 class MacroAssembler : public MacroAssemblerBase {
 public:
 
@@ -1820,7 +1827,9 @@ public:
     // This only works if ENABLE(MASM_PROBE). Otherwise, print() is a no-op.
     // See comments in MacroAssemblerPrinter.h for examples of how to use this.
     template<typename... Arguments>
-    void print(Arguments... args);
+    void print(Arguments&&... args);
+
+    void print(Printer::PrintRecordList*);
 };
 
 #if ENABLE(MASM_PROBE)
index 718f10e..c1cfc25 100644 (file)
 #include "MacroAssembler.h"
 
 namespace JSC {
+namespace Printer {
 
 using CPUState = MacroAssembler::CPUState;
 using RegisterID = MacroAssembler::RegisterID;
 using FPRegisterID = MacroAssembler::FPRegisterID;
 
-static void printIndent(int indentation)
+void printAllRegisters(PrintStream& out, Context& context)
 {
-    for (; indentation > 0; indentation--)
-        dataLog("    ");
-}
+    auto& cpu = context.probeContext.cpu;
+    unsigned charsToIndent = context.data.as<unsigned>();
 
-#define INDENT printIndent(indentation)
-    
-void printCPU(CPUState& cpu, int indentation)
-{
-    INDENT, dataLog("cpu: {\n");
-    printCPURegisters(cpu, indentation + 1);
-    INDENT, dataLog("}\n");
-}
+    auto indent = [&] () {
+        for (unsigned i = 0; i < charsToIndent; ++i)
+            out.print(" ");
+    };
+#define INDENT indent()
+
+    INDENT, out.print("cpu: {\n");
 
-void printCPURegisters(CPUState& cpu, int indentation)
-{
 #if USE(JSVALUE32_64)
     #define INTPTR_HEX_VALUE_FORMAT "0x%08lx"
 #else
@@ -61,7 +58,7 @@ void printCPURegisters(CPUState& cpu, int indentation)
 
     #define PRINT_GPREGISTER(_type, _regName) { \
         intptr_t value = reinterpret_cast<intptr_t>(cpu._regName); \
-        INDENT, dataLogF("%6s: " INTPTR_HEX_VALUE_FORMAT "  %ld\n", #_regName, value, value) ; \
+        INDENT, out.printf("    %6s: " INTPTR_HEX_VALUE_FORMAT "  %ld\n", #_regName, value, value) ; \
     }
     FOR_EACH_CPU_GPREGISTER(PRINT_GPREGISTER)
     FOR_EACH_CPU_SPECIAL_REGISTER(PRINT_GPREGISTER)
@@ -71,56 +68,63 @@ void printCPURegisters(CPUState& cpu, int indentation)
     #define PRINT_FPREGISTER(_type, _regName) { \
         uint64_t* u = reinterpret_cast<uint64_t*>(&cpu._regName); \
         double* d = reinterpret_cast<double*>(&cpu._regName); \
-        INDENT, dataLogF("%6s: 0x%016llx  %.13g\n", #_regName, *u, *d); \
+        INDENT, out.printf("    %6s: 0x%016llx  %.13g\n", #_regName, *u, *d); \
     }
     FOR_EACH_CPU_FPREGISTER(PRINT_FPREGISTER)
     #undef PRINT_FPREGISTER
+
+    INDENT, out.print("}\n");
+#undef INDENT
+
 }
 
-static void printPC(CPUState& cpu)
+void printPCRegister(PrintStream& out, Context& context)
 {
-    union {
-        void* voidPtr;
-        intptr_t intptrValue;
-    } u;
+    auto cpu = context.probeContext.cpu;
+    void* value;
 #if CPU(X86) || CPU(X86_64)
-    u.voidPtr = cpu.eip;
+    value = cpu.eip;
 #elif CPU(ARM_TRADITIONAL) || CPU(ARM_THUMB2) || CPU(ARM64)
-    u.voidPtr = cpu.pc;
+    value = cpu.pc;
 #else
 #error "Unsupported CPU"
 #endif
-    dataLogF("pc:<%p %ld>", u.voidPtr, u.intptrValue);
+    out.printf("pc:<%p %ld>", value, bitwise_cast<intptr_t>(value));
 }
 
-void printRegister(CPUState& cpu, RegisterID regID)
+void printRegisterID(PrintStream& out, Context& context)
 {
+    RegisterID regID = context.data.as<RegisterID>();
     const char* name = CPUState::gprName(regID);
-    union {
-        void* voidPtr;
-        intptr_t intptrValue;
-    } u;
-    u.voidPtr = cpu.gpr(regID);
-    dataLogF("%s:<%p %ld>", name, u.voidPtr, u.intptrValue);
+    void* value = context.probeContext.gpr(regID);
+    out.printf("%s:<%p %ld>", name, value, bitwise_cast<intptr_t>(value));
 }
 
-void printRegister(CPUState& cpu, FPRegisterID regID)
+void printFPRegisterID(PrintStream& out, Context& context)
 {
+    FPRegisterID regID = context.data.as<FPRegisterID>();
     const char* name = CPUState::fprName(regID);
-    union {
-        double doubleValue;
-        uint64_t uint64Value;
-    } u;
-    u.doubleValue = cpu.fpr(regID);
-    dataLogF("%s:<0x%016llx %.13g>", name, u.uint64Value, u.doubleValue);
+    double value = context.probeContext.fpr(regID);
+    out.printf("%s:<0x%016llx %.13g>", name, bitwise_cast<uint64_t>(value), value);
 }
 
-void printMemory(CPUState& cpu, const Memory& memory)
+void printAddress(PrintStream& out, Context& context)
 {
+    MacroAssembler::Address address = context.data.as<MacroAssembler::Address>();
+    RegisterID regID = address.base;
+    const char* name = CPUState::gprName(regID);
+    void* value = context.probeContext.gpr(regID);
+    out.printf("Address{base:%s:<%p %ld>, offset:<0x%x %d>", name, value, bitwise_cast<intptr_t>(value), address.offset, address.offset);
+}
+
+void printMemory(PrintStream& out, Context& context)
+{
+    const Memory& memory = context.data.as<Memory>();
+
     uint8_t* ptr = nullptr;
     switch (memory.addressType) {
     case Memory::AddressType::Address: {
-        ptr = reinterpret_cast<uint8_t*>(cpu.gpr(memory.u.address.base));
+        ptr = reinterpret_cast<uint8_t*>(context.probeContext.gpr(memory.u.address.base));
         ptr += memory.u.address.offset;
         break;
     }
@@ -133,22 +137,22 @@ void printMemory(CPUState& cpu, const Memory& memory)
     if (memory.dumpStyle == Memory::SingleWordDump) {
         if (memory.numBytes == sizeof(int8_t)) {
             auto p = reinterpret_cast<int8_t*>(ptr);
-            dataLogF("%p:<0x%02x %d>", p, *p, *p);
+            out.printf("%p:<0x%02x %d>", p, *p, *p);
             return;
         }
         if (memory.numBytes == sizeof(int16_t)) {
             auto p = reinterpret_cast<int16_t*>(ptr);
-            dataLogF("%p:<0x%04x %d>", p, *p, *p);
+            out.printf("%p:<0x%04x %d>", p, *p, *p);
             return;
         }
         if (memory.numBytes == sizeof(int32_t)) {
             auto p = reinterpret_cast<int32_t*>(ptr);
-            dataLogF("%p:<0x%08x %d>", p, *p, *p);
+            out.printf("%p:<0x%08x %d>", p, *p, *p);
             return;
         }
         if (memory.numBytes == sizeof(int64_t)) {
             auto p = reinterpret_cast<int64_t*>(ptr);
-            dataLogF("%p:<0x%016llx %lld>", p, *p, *p);
+            out.printf("%p:<0x%016llx %lld>", p, *p, *p);
             return;
         }
         // Else, unknown word size. Fall thru and dump in the generic way.
@@ -158,58 +162,31 @@ void printMemory(CPUState& cpu, const Memory& memory)
     size_t numBytes = memory.numBytes;
     for (size_t i = 0; i < numBytes; i++) {
         if (!(i % 16))
-            dataLogF("%p: ", &ptr[i]);
+            out.printf("%p: ", &ptr[i]);
         else if (!(i % 4))
-            dataLog(" ");
+            out.printf(" ");
 
-        dataLogF("%02x", ptr[i]);
+        out.printf("%02x", ptr[i]);
 
         if (i % 16 == 15)
-            dataLog("\n");
+            out.print("\n");
     }
     if (numBytes % 16 < 15)
-        dataLog("\n");
+        out.print("\n");
 }
 
-void MacroAssemblerPrinter::printCallback(ProbeContext* context)
+void printCallback(ProbeContext* probeContext)
 {
-    typedef PrintArg Arg;
-    PrintArgsList& argsList =
-    *reinterpret_cast<PrintArgsList*>(context->arg);
-    for (size_t i = 0; i < argsList.size(); i++) {
-        auto& arg = argsList[i];
-        switch (arg.type) {
-        case Arg::Type::AllRegisters:
-            printCPU(context->cpu, 1);
-            break;
-        case Arg::Type::PCRegister:
-            printPC(context->cpu);
-            break;
-        case Arg::Type::RegisterID:
-            printRegister(context->cpu, arg.u.gpRegisterID);
-            break;
-        case Arg::Type::FPRegisterID:
-            printRegister(context->cpu, arg.u.fpRegisterID);
-            break;
-        case Arg::Type::Memory:
-            printMemory(context->cpu, arg.u.memory);
-            break;
-        case Arg::Type::ConstCharPtr:
-            dataLog(arg.u.constCharPtr);
-            break;
-        case Arg::Type::ConstVoidPtr:
-            dataLogF("%p", arg.u.constVoidPtr);
-            break;
-        case Arg::Type::IntptrValue:
-            dataLog(arg.u.intptrValue);
-            break;
-        case Arg::Type::UintptrValue:
-            dataLog(arg.u.uintptrValue);
-            break;
-        }
+    auto& out = WTF::dataFile();
+    PrintRecordList& list = *reinterpret_cast<PrintRecordList*>(probeContext->arg);
+    for (size_t i = 0; i < list.size(); i++) {
+        auto& record = list[i];
+        Context context(*probeContext, record.data);
+        record.printer(out, context);
     }
 }
 
+} // namespace Printer
 } // namespace JSC
 
 #endif // ENABLE(MASM_PROBE)
index 460b49b..fb74f6c 100644 (file)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "MacroAssembler.h"
+#include "Printer.h"
 
 namespace JSC {
 
@@ -54,19 +55,21 @@ namespace JSC {
 //      jit.print("Hello world\n"); // Emits code to print the string.
 //
 //      CodeBlock* cb = ...;
-//      jit.print(cb, "\n");        // Emits code to print the pointer value.
+//      jit.print(cb, "\n");             // Emits code to print the codeBlock value.
+//      jit.print(RawPointer(cb), "\n"); // Emits code to print the pointer value.
 //
 //      RegisterID regID = ...;
 //      jit.print(regID, "\n");     // Emits code to print the register value (not the id).
 //
 //      // Emits code to print all registers. Unlike other items, this prints
 //      // multiple lines as follows:
-//      //      cpu {
-//      //          eax: 0x123456789
-//      //          ebx: 0x000000abc
-//      //          ...
-//      //      }
-//      jit.print(AllRegisters());
+//      //     cpu {
+//      //         eax: 0x123456789
+//      //         ebx: 0x000000abc
+//      //         ...
+//      //     }
+//      unsigned indentation = 4;
+//      jit.print(AllRegisters(indentation));
 //
 //      jit.print(MemWord<uint8_t>(regID), "\n");   // Emits code to print a byte pointed to by the register.
 //      jit.print(MemWord<uint32_t>(regID), "\n");  // Emits code to print a 32-bit word pointed to by the register.
@@ -81,15 +84,19 @@ namespace JSC {
 //      // to print all the items.
 //      jit.print("cb:", cb, " regID:", regID, " cpu:\n", AllRegisters());
 //
-//   The type of values that can be printed is encapsulated in the PrintArg struct below.
+//   The type of values that can be printed is determine by the availability of a
+//   specialized Printer template, or a setPrinter() function for the value type.
 //
 //   Note: print() does not automatically insert a '\n' at the end of the line.
 //   If you want a '\n', you'll have to add it explicitly (as in the examples above).
 
 
-// This is a marker type only used with MacroAssemblerPrinter::print().
-// See MacroAssemblerPrinter::print() below for details.
-struct AllRegisters { };
+struct AllRegisters {
+    explicit AllRegisters(unsigned charsToIndent = 0)
+        : charsToIndent(charsToIndent)
+    { }
+    unsigned charsToIndent;
+};
 struct PCRegister { };
 
 struct Memory {
@@ -107,7 +114,7 @@ struct Memory {
         GenericDump,
     };
 
-    Memory(RegisterID& reg, size_t bytes, DumpStyle style = GenericDump)
+    explicit Memory(RegisterID& reg, size_t bytes, DumpStyle style = GenericDump)
         : addressType(AddressType::Address)
         , dumpStyle(style)
         , numBytes(bytes)
@@ -115,7 +122,7 @@ struct Memory {
         u.address = Address(reg, 0);
     }
 
-    Memory(const Address& address, size_t bytes, DumpStyle style = GenericDump)
+    explicit Memory(const Address& address, size_t bytes, DumpStyle style = GenericDump)
         : addressType(AddressType::Address)
         , dumpStyle(style)
         , numBytes(bytes)
@@ -123,7 +130,7 @@ struct Memory {
         u.address = address;
     }
 
-    Memory(const AbsoluteAddress& address, size_t bytes, DumpStyle style = GenericDump)
+    explicit Memory(const AbsoluteAddress& address, size_t bytes, DumpStyle style = GenericDump)
         : addressType(AddressType::AbsoluteAddress)
         , dumpStyle(style)
         , numBytes(bytes)
@@ -144,164 +151,101 @@ struct Memory {
 
 template <typename IntType>
 struct MemWord : public Memory {
-    MemWord(RegisterID& reg)
+    explicit MemWord(RegisterID& reg)
         : Memory(reg, sizeof(IntType), Memory::SingleWordDump)
     { }
 
-    MemWord(const Address& address)
+    explicit MemWord(const Address& address)
         : Memory(address, sizeof(IntType), Memory::SingleWordDump)
     { }
 
-    MemWord(const AbsoluteAddress& address)
+    explicit MemWord(const AbsoluteAddress& address)
         : Memory(address, sizeof(IntType), Memory::SingleWordDump)
     { }
 };
 
+namespace Printer {
 
-class MacroAssemblerPrinter {
-    using CPUState = MacroAssembler::CPUState;
-    using RegisterID = MacroAssembler::RegisterID;
-    using FPRegisterID = MacroAssembler::FPRegisterID;
-    
-public:
-    template<typename... Arguments>
-    static void print(MacroAssembler* masm, Arguments... args)
-    {
-        auto argsList = std::make_unique<PrintArgsList>();
-        appendPrintArg(argsList.get(), args...);
-        masm->probe(printCallback, argsList.release());
-    }
-    
-private:
-    struct PrintArg {
-
-        enum class Type {
-            AllRegisters,
-            PCRegister,
-            RegisterID,
-            FPRegisterID,
-            Memory,
-            ConstCharPtr,
-            ConstVoidPtr,
-            IntptrValue,
-            UintptrValue,
-        };
-        
-        PrintArg(AllRegisters&)
-            : type(Type::AllRegisters)
-        {
-        }
-        
-        PrintArg(PCRegister&)
-            : type(Type::PCRegister)
-        {
-        }
-        
-        PrintArg(RegisterID regID)
-            : type(Type::RegisterID)
-        {
-            u.gpRegisterID = regID;
-        }
-        
-        PrintArg(FPRegisterID regID)
-            : type(Type::FPRegisterID)
-        {
-            u.fpRegisterID = regID;
-        }
-
-        PrintArg(const Memory& memory)
-            : type(Type::Memory)
-        {
-            u.memory = memory;
-        }
-
-        PrintArg(const char* ptr)
-            : type(Type::ConstCharPtr)
-        {
-            u.constCharPtr = ptr;
-        }
-        
-        PrintArg(const void* ptr)
-            : type(Type::ConstVoidPtr)
-        {
-            u.constVoidPtr = ptr;
-        }
-        
-        PrintArg(int value)
-            : type(Type::IntptrValue)
-        {
-            u.intptrValue = value;
-        }
-        
-        PrintArg(unsigned value)
-            : type(Type::UintptrValue)
-        {
-            u.intptrValue = value;
-        }
-        
-        PrintArg(intptr_t value)
-            : type(Type::IntptrValue)
-        {
-            u.intptrValue = value;
-        }
-        
-        PrintArg(uintptr_t value)
-            : type(Type::UintptrValue)
-        {
-            u.uintptrValue = value;
-        }
-        
-        Type type;
-        union Value {
-            Value() { }
-
-            RegisterID gpRegisterID;
-            FPRegisterID fpRegisterID;
-            Memory memory;
-            const char* constCharPtr;
-            const void* constVoidPtr;
-            intptr_t intptrValue;
-            uintptr_t uintptrValue;
-        } u;
-    };
+// Add some specialized printers.
 
-    typedef Vector<PrintArg> PrintArgsList;
-    
-    template<typename FirstArg, typename... Arguments>
-    static void appendPrintArg(PrintArgsList* argsList, FirstArg& firstArg, Arguments... otherArgs)
-    {
-        argsList->append(PrintArg(firstArg));
-        appendPrintArg(argsList, otherArgs...);
-    }
-    
-    static void appendPrintArg(PrintArgsList*) { }
+void printAllRegisters(PrintStream&, Context&);
+void printPCRegister(PrintStream&, Context&);
+void printRegisterID(PrintStream&, Context&);
+void printFPRegisterID(PrintStream&, Context&);
+void printAddress(PrintStream&, Context&);
+void printMemory(PrintStream&, Context&);
+
+template<>
+struct Printer<AllRegisters> : public PrintRecord {
+    Printer(AllRegisters allRegisters)
+        : PrintRecord(static_cast<uintptr_t>(allRegisters.charsToIndent), printAllRegisters)
+    { }
+};
+
+template<>
+struct Printer<PCRegister> : public PrintRecord {
+    Printer(PCRegister&)
+        : PrintRecord(printPCRegister)
+    { }
+};
+
+template<>
+struct Printer<MacroAssembler::RegisterID> : public PrintRecord {
+    Printer(MacroAssembler::RegisterID id)
+        : PrintRecord(static_cast<uintptr_t>(id), printRegisterID)
+    { }
+};
+
+template<>
+struct Printer<MacroAssembler::FPRegisterID> : public PrintRecord {
+    Printer(MacroAssembler::FPRegisterID id)
+        : PrintRecord(static_cast<uintptr_t>(id), printFPRegisterID)
+    { }
+};
 
-private:
-    static void printCallback(ProbeContext*);
+template<>
+struct Printer<MacroAssembler::Address> : public PrintRecord {
+    Printer(MacroAssembler::Address address)
+        : PrintRecord(Data(&address, sizeof(address)), printAddress)
+    { }
 };
 
+template<>
+struct Printer<Memory> : public PrintRecord {
+    Printer(Memory memory)
+        : PrintRecord(Data(&memory, sizeof(memory)), printMemory)
+    { }
+};
+
+template<typename IntType>
+struct Printer<MemWord<IntType>> : public Printer<Memory> {
+    Printer(MemWord<IntType> word)
+        : Printer<Memory>(word)
+    { }
+};
+
+void printCallback(ProbeContext*);
+
+} // namespace Printer
+
 template<typename... Arguments>
-void MacroAssembler::print(Arguments... args)
+inline void MacroAssembler::print(Arguments&&... arguments)
 {
-    MacroAssemblerPrinter::print(this, args...);
+    auto printRecordList = Printer::makePrintRecordList(std::forward<Arguments>(arguments)...);
+    probe(Printer::printCallback, printRecordList);
 }
 
-
-// These printers will print a block of information. That block may be
-// indented with the specified indentation.
-void printCPU(MacroAssembler::CPUState&, int indentation = 0);
-void printCPURegisters(MacroAssembler::CPUState&, int indentation = 0);
-
-// These printers will print the specified information in line in the
-// print stream. Hence, no indentation will be applied.
-void printRegister(MacroAssembler::CPUState&, MacroAssembler::RegisterID);
-void printRegister(MacroAssembler::CPUState&, MacroAssembler::FPRegisterID);
-void printMemory(MacroAssembler::CPUState&, const Memory&);
+inline void MacroAssembler::print(Printer::PrintRecordList* printRecordList)
+{
+    probe(Printer::printCallback, printRecordList);
+}
 
 #else // ENABLE(MASM_PROBE)
 
 template<typename... Arguments>
-void MacroAssembler::print(Arguments...) { }
+inline void MacroAssembler::print(Arguments&&...) { }
+
+inline void MacroAssembler::print(Printer::PrintRecordList*) { }
 
 #endif // ENABLE(MASM_PROBE)
 
diff --git a/Source/JavaScriptCore/assembler/Printer.cpp b/Source/JavaScriptCore/assembler/Printer.cpp
new file mode 100644 (file)
index 0000000..14b5884
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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 "Printer.h"
+
+namespace JSC {
+namespace Printer {
+
+void printConstCharString(PrintStream& out, Context& context)
+{
+    const char* str = context.data.as<const char*>();
+    out.print(str);
+}
+
+void printIntptr(PrintStream& out, Context& context)
+{
+    out.print(context.data.as<intptr_t>());
+}
+
+void printUintptr(PrintStream& out, Context& context)
+{
+    out.print(context.data.as<uintptr_t>());
+}
+
+void printPointer(PrintStream& out, Context& context)
+{
+    out.print(RawPointer(context.data.as<const void*>()));
+}
+
+void setPrinter(PrintRecord& record, CString&& string)
+{
+    // FIXME: It would be nice if we can release the CStringBuffer from the CString
+    // and take ownership of it here instead of copying it again.
+    record.data.pointer = fastStrDup(string.data());
+    record.printer = printConstCharString;
+}
+
+} // namespace Printer
+} // namespace JSC
diff --git a/Source/JavaScriptCore/assembler/Printer.h b/Source/JavaScriptCore/assembler/Printer.h
new file mode 100644 (file)
index 0000000..2e00111
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include <wtf/PrintStream.h>
+#include <wtf/StringPrintStream.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+struct ProbeContext;
+
+namespace Printer {
+
+struct Context;
+
+union Data {
+    Data()
+    {
+        const intptr_t uninitialized = 0xdeadb0d0;
+        memcpy(&buffer, &uninitialized, sizeof(uninitialized));
+    }
+    Data(uintptr_t value)
+        : Data(&value, sizeof(value))
+    { }
+    Data(const void* pointer)
+        : Data(&pointer, sizeof(pointer))
+    { }
+    Data(void* src, size_t size)
+    {
+        RELEASE_ASSERT(size <= sizeof(buffer));
+        memcpy(&buffer, src, size);
+    }
+
+    template<typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
+    T as() const
+    {
+        return static_cast<T>(value);
+    }
+
+    template<typename T, typename = typename std::enable_if<std::is_pointer<T>::value>::type>
+    const T as(int = 0) const
+    {
+        return reinterpret_cast<const T>(pointer);
+    }
+
+    template<typename T, typename = typename std::enable_if<!std::is_integral<T>::value && !std::is_pointer<T>::value>::type>
+    const T& as() const
+    {
+        static_assert(sizeof(T) <= sizeof(buffer), "size is not sane");
+        return *reinterpret_cast<const T*>(&buffer);
+    }
+
+    uintptr_t value;
+    const void* pointer;
+#if USE(JSVALUE64)
+    uintptr_t buffer[4];
+#elif USE(JSVALUE32_64)
+    uintptr_t buffer[6];
+#endif
+};
+
+struct Context {
+    Context(ProbeContext& probeContext, Data& data)
+        : probeContext(probeContext)
+        , data(data)
+    { }
+
+    ProbeContext& probeContext;
+    Data& data;
+};
+
+typedef void (*Callback)(PrintStream&, Context&);
+
+struct PrintRecord {
+    PrintRecord(Data data, Callback printer)
+        : data(data)
+        , printer(printer)
+    { }
+
+    PrintRecord(Callback printer)
+        : printer(printer)
+    { }
+
+    template<template<class> class Printer, typename T>
+    PrintRecord(const Printer<T>& other)
+    {
+        static_assert(std::is_base_of<PrintRecord, Printer<T>>::value, "Printer should extend PrintRecord");
+        static_assert(sizeof(PrintRecord) == sizeof(Printer<T>), "Printer should be the same size as PrintRecord");
+        data = other.data;
+        printer = other.printer;
+    }
+
+    Data data;
+    Callback printer;
+
+protected:
+    PrintRecord() { }
+};
+
+template<typename T> struct Printer;
+
+typedef Vector<PrintRecord> PrintRecordList;
+
+inline void appendPrinter(PrintRecordList&) { }
+
+template<typename First, typename... Arguments>
+inline void appendPrinter(PrintRecordList& printRecordList, First first, Arguments&&... others)
+{
+    printRecordList.append(Printer<First>(first));
+    appendPrinter(printRecordList, std::forward<Arguments>(others)...);
+}
+
+template<typename... Arguments>
+inline PrintRecordList* makePrintRecordList(Arguments&&... arguments)
+{
+    // FIXME: the current implementation intentionally leaks the PrintRecordList.
+    // We may want to fix this in the future if we want to use the print mechanism
+    // in tests that may compile a lot of prints.
+    // https://bugs.webkit.org/show_bug.cgi?id=171123
+    auto printRecordList = new PrintRecordList();
+    appendPrinter(*printRecordList, std::forward<Arguments>(arguments)...);
+    return printRecordList;
+}
+
+// Some utility functions for specializing printers.
+
+void printConstCharString(PrintStream&, Context&);
+void printIntptr(PrintStream&, Context&);
+void printUintptr(PrintStream&, Context&);
+void printPointer(PrintStream&, Context&);
+
+void setPrinter(PrintRecord&, CString&&);
+
+// Specialized printers.
+
+template<>
+struct Printer<const char*> : public PrintRecord {
+    Printer(const char* str)
+        : PrintRecord(str, printConstCharString)
+    { }
+};
+
+template<>
+struct Printer<char*> : public Printer<const char*> {
+    Printer(char* str)
+        : Printer<const char*>(str)
+    { }
+};
+
+template<>
+struct Printer<RawPointer> : public PrintRecord {
+    Printer(RawPointer rawPointer)
+        : PrintRecord(rawPointer.value(), printPointer)
+    { }
+};
+
+template<typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && std::numeric_limits<T>::is_signed>>
+void setPrinter(PrintRecord& record, T value, intptr_t = 0)
+{
+    record.data.value = static_cast<uintptr_t>(value);
+    record.printer = printIntptr;
+}
+
+template<typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && !std::numeric_limits<T>::is_signed>>
+void setPrinter(PrintRecord& record, T value, uintptr_t = 0)
+{
+    record.data.value = static_cast<uintptr_t>(value);
+    record.printer = printUintptr;
+}
+
+template<typename T>
+struct Printer : public PrintRecord {
+    Printer(T value)
+    {
+        setPrinter(*this, value);
+    }
+};
+
+} // namespace Printer
+
+} // namespace JSC
index 8c6f736..7cf45b5 100644 (file)
@@ -33,6 +33,7 @@
 #include "AirCode.h"
 #include "AirInsertionSet.h"
 #include "AirInstInlines.h"
+#include "AirPrintSpecial.h"
 #include "AirStackSlot.h"
 #include "B3ArgumentRegValue.h"
 #include "B3AtomicValue.h"
@@ -1127,6 +1128,28 @@ private:
         return Air::Oops;
     }
 
+#if ENABLE(MASM_PROBE)
+    template<typename... Arguments>
+    void print(Arguments&&... arguments)
+    {
+        Value* origin = m_value;
+        print(origin, std::forward<Arguments>(arguments)...);
+    }
+
+    template<typename... Arguments>
+    void print(Value* origin, Arguments&&... arguments)
+    {
+        auto printList = Printer::makePrintRecordList(arguments...);
+        auto printSpecial = static_cast<PrintSpecial*>(m_code.addSpecial(std::make_unique<PrintSpecial>(printList)));
+        Inst inst(Patch, origin, Arg::special(printSpecial));
+        Printer::appendAirArgs(inst, std::forward<Arguments>(arguments)...);
+        append(WTFMove(inst));
+    }
+#else
+    template<typename... Arguments>
+    void print(Arguments&&...) { }
+#endif // ENABLE(MASM_PROBE)
+
     template<typename... Arguments>
     void append(Air::Opcode opcode, Arguments&&... arguments)
     {
diff --git a/Source/JavaScriptCore/b3/air/AirPrintSpecial.cpp b/Source/JavaScriptCore/b3/air/AirPrintSpecial.cpp
new file mode 100644 (file)
index 0000000..56a26cc
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 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 "AirPrintSpecial.h"
+
+#if ENABLE(B3_JIT)
+#if ENABLE(MASM_PROBE)
+
+#include "MacroAssemblerPrinter.h"
+
+namespace JSC { namespace B3 { namespace Air {
+
+PrintSpecial::PrintSpecial(Printer::PrintRecordList* list)
+    : m_printRecordList(list)
+{
+}
+
+PrintSpecial::~PrintSpecial()
+{
+}
+
+void PrintSpecial::forEachArg(Inst&, const ScopedLambda<Inst::EachArgCallback>&)
+{
+}
+
+bool PrintSpecial::isValid(Inst&)
+{
+    return true;
+}
+
+bool PrintSpecial::admitsStack(Inst&, unsigned)
+{
+    return false;
+}
+
+void PrintSpecial::reportUsedRegisters(Inst&, const RegisterSet&)
+{
+}
+
+CCallHelpers::Jump PrintSpecial::generate(Inst& inst, CCallHelpers& jit, GenerationContext&)
+{
+    size_t currentArg = 1; // Skip the PrintSpecial arg.
+    for (auto& term : *m_printRecordList) {
+        if (term.printer == Printer::printAirArg) {
+            const Arg& arg = inst.args[currentArg++];
+            switch (arg.kind()) {
+            case Arg::Tmp:
+                term = Printer::Printer<MacroAssembler::RegisterID>(arg.gpr());
+                break;
+            case Arg::Addr:
+                term = Printer::Printer<MacroAssembler::Address>(arg.asAddress());
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
+        }
+    }
+    jit.print(m_printRecordList);
+    return CCallHelpers::Jump();
+}
+
+RegisterSet PrintSpecial::extraEarlyClobberedRegs(Inst&)
+{
+    return RegisterSet();
+}
+
+RegisterSet PrintSpecial::extraClobberedRegs(Inst&)
+{
+    return RegisterSet();
+}
+
+void PrintSpecial::dumpImpl(PrintStream& out) const
+{
+    out.print("Print");
+}
+
+void PrintSpecial::deepDumpImpl(PrintStream& out) const
+{
+    out.print("print for debugging logging.");
+}
+
+} } // namespace B3::Air
+
+namespace Printer {
+
+NO_RETURN void printAirArg(PrintStream&, Context&)
+{
+    // This function is only a placeholder to let PrintSpecial::generate() know that
+    // the Printer needs to be replaced with one for a register, constant, etc. Hence,
+    // this function should never be called.
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace Printer
+
+} // namespace JSC
+
+#endif // ENABLE(MASM_PROBE)
+#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirPrintSpecial.h b/Source/JavaScriptCore/b3/air/AirPrintSpecial.h
new file mode 100644 (file)
index 0000000..74cb573
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#if ENABLE(B3_JIT)
+#if ENABLE(MASM_PROBE)
+
+#include "AirInst.h"
+#include "AirSpecial.h"
+#include "MacroAssemblerPrinter.h"
+
+namespace JSC {
+namespace Printer {
+
+typedef Vector<B3::Air::Arg> ArgList;
+
+// IsSameOrReference::value is true if T is the same type as U or U&. Else, it is false.
+    
+template<typename T, typename U>
+static constexpr auto IsSameOrReferenceHelper(int) -> std::enable_if_t<std::is_same<T, U>::value || std::is_same<T, U&>::value, std::true_type>;
+
+template<typename T, typename U>
+static constexpr std::false_type IsSameOrReferenceHelper(...);
+
+template<class T, typename U>
+struct IsSameOrReference : public std::is_same<decltype(IsSameOrReferenceHelper<T, U>(0)), std::true_type> { };
+
+    
+template<typename T, typename... Arguments, typename = std::enable_if_t<IsSameOrReference<T, B3::Air::Tmp>::value || IsSameOrReference<T, Reg>::value>>
+inline void appendAirArg(B3::Air::Inst& inst, T&& arg)
+{
+    inst.args.append(std::forward<T>(arg));
+}
+
+template<typename T, typename... Arguments, typename = std::enable_if_t<!IsSameOrReference<T, B3::Air::Tmp>::value && !IsSameOrReference<T, Reg>::value>>
+inline void appendAirArg(B3::Air::Inst&, T&&, int = 0) { }
+
+inline void appendAirArgs(B3::Air::Inst&) { }
+
+template<typename T, typename... Arguments>
+inline void appendAirArgs(B3::Air::Inst& inst, T&& t, Arguments&&... others)
+{
+    appendAirArg(inst, std::forward<T>(t));
+    appendAirArgs(inst, std::forward<Arguments>(others)...);
+}
+
+void printAirArg(PrintStream&, Context&);
+
+// Printer<Arg&> is only a place-holder which PrintSpecial::generate() will later
+// replace with a Printer for a register, constant, etc. as appropriate. 
+template<>
+struct Printer<B3::Air::Tmp> : public PrintRecord {
+    Printer(B3::Air::Tmp&)
+        : PrintRecord(printAirArg)
+    { }
+};
+    
+template<>
+struct Printer<Reg> : public PrintRecord {
+    Printer(Reg&)
+        : PrintRecord(printAirArg)
+    { }
+};
+
+} // namespace Printer
+
+namespace B3 { namespace Air {
+
+class PrintSpecial : public Special {
+public:
+    PrintSpecial(Printer::PrintRecordList*);
+    ~PrintSpecial();
+    
+    // You cannot use this register to pass arguments. It just so happens that this register is not
+    // used for arguments in the C calling convention. By the way, this is the only thing that causes
+    // this special to be specific to C calls.
+    static const GPRReg scratchRegister = GPRInfo::nonArgGPR0;
+    
+protected:
+    void forEachArg(Inst&, const ScopedLambda<Inst::EachArgCallback>&) override;
+    bool isValid(Inst&) override;
+    bool admitsStack(Inst&, unsigned argIndex) override;
+    void reportUsedRegisters(Inst&, const RegisterSet&) override;
+    CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&) override;
+    RegisterSet extraEarlyClobberedRegs(Inst&) override;
+    RegisterSet extraClobberedRegs(Inst&) override;
+    
+    void dumpImpl(PrintStream&) const override;
+    void deepDumpImpl(PrintStream&) const override;
+    
+private:
+    static const unsigned specialArgOffset = 0;
+    static const unsigned numSpecialArgs = 1;
+    static const unsigned calleeArgOffset = numSpecialArgs;
+    static const unsigned numCalleeArgs = 1;
+    static const unsigned returnGPArgOffset = numSpecialArgs + numCalleeArgs;
+    static const unsigned numReturnGPArgs = 2;
+    static const unsigned returnFPArgOffset = numSpecialArgs + numCalleeArgs + numReturnGPArgs;
+    static const unsigned numReturnFPArgs = 1;
+    static constexpr unsigned argArgOffset =
+    numSpecialArgs + numCalleeArgs + numReturnGPArgs + numReturnFPArgs;
+    
+    Printer::PrintRecordList* m_printRecordList;
+};
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(MASM_PROBE)
+#endif // ENABLE(B3_JIT)
index 671a466..de8fa03 100644 (file)
@@ -3111,5 +3111,22 @@ BytecodeLivenessAnalysis& CodeBlock::livenessAnalysisSlow()
     }
 }
 
+void setPrinter(Printer::PrintRecord& record, CodeBlock* codeBlock)
+{
+    Printer::setPrinter(record, toCString(codeBlock));
+}
 
 } // namespace JSC
+
+namespace WTF {
+    
+void printInternal(PrintStream& out, JSC::CodeBlock* codeBlock)
+{
+    if (UNLIKELY(!codeBlock)) {
+        out.print("<null codeBlock>");
+        return;
+    }
+    out.print(*codeBlock);
+}
+    
+} // namespace WTF
index 395e748..b42807c 100644 (file)
@@ -60,6 +60,7 @@
 #include "ModuleProgramExecutable.h"
 #include "ObjectAllocationProfile.h"
 #include "Options.h"
+#include "Printer.h"
 #include "ProfilerJettisonReason.h"
 #include "ProgramExecutable.h"
 #include "PutPropertySlot.h"
@@ -1087,4 +1088,13 @@ JSObject* ScriptExecutable::prepareForExecution(VM& vm, JSFunction* function, JS
 #define CODEBLOCK_LOG_EVENT(codeBlock, summary, details) \
     (codeBlock->vm()->logEvent(codeBlock, summary, [&] () { return toCString details; }))
 
+
+void setPrinter(Printer::PrintRecord&, CodeBlock*);
+
 } // namespace JSC
+
+namespace WTF {
+    
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::CodeBlock*);
+
+} // namespace WTF
index 548c019..0ecc3cf 100644 (file)
@@ -605,11 +605,7 @@ void VM::throwException(ExecState* exec, Exception* exception)
 {
     if (Options::breakOnThrow()) {
         CodeBlock* codeBlock = exec->codeBlock();
-        dataLog("Throwing exception in call frame ", RawPointer(exec), " for code block ");
-        if (codeBlock)
-            dataLog(*codeBlock, "\n");
-        else
-            dataLog("<nullptr>\n");
+        dataLog("Throwing exception in call frame ", RawPointer(exec), " for code block ", codeBlock, "\n");
         CRASH();
     }