X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/93a3786624b2768d89bfa27e46598dc64e2fb70a..refs/heads/master:/assembler/AbstractMacroAssembler.h diff --git a/assembler/AbstractMacroAssembler.h b/assembler/AbstractMacroAssembler.h index 71b9d1f..6e82dcc 100644 --- a/assembler/AbstractMacroAssembler.h +++ b/assembler/AbstractMacroAssembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012, 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,28 +26,22 @@ #ifndef AbstractMacroAssembler_h #define AbstractMacroAssembler_h +#include "AbortReason.h" #include "AssemblerBuffer.h" #include "CodeLocation.h" #include "MacroAssemblerCodeRef.h" +#include "Options.h" +#include "WeakRandom.h" #include #include #if ENABLE(ASSEMBLER) - -#if PLATFORM(QT) -#define ENABLE_JIT_CONSTANT_BLINDING 0 -#endif - -#ifndef ENABLE_JIT_CONSTANT_BLINDING -#define ENABLE_JIT_CONSTANT_BLINDING 1 -#endif - namespace JSC { -inline bool isARMv7s() +inline bool isARMv7IDIVSupported() { -#if CPU(APPLE_ARMV7S) +#if HAVE(ARM_IDIV_INSTRUCTIONS) return true; #else return false; @@ -72,7 +66,21 @@ inline bool isX86() #endif } -class JumpReplacementWatchpoint; +inline bool optimizeForARMv7IDIVSupported() +{ + return isARMv7IDIVSupported() && Options::enableArchitectureSpecificOptimizations(); +} + +inline bool optimizeForARM64() +{ + return isARM64() && Options::enableArchitectureSpecificOptimizations(); +} + +inline bool optimizeForX86() +{ + return isX86() && Options::enableArchitectureSpecificOptimizations(); +} + class LinkBuffer; class RepatchBuffer; class Watchpoint; @@ -80,10 +88,11 @@ namespace DFG { struct OSRExit; } -template +template class AbstractMacroAssembler { public: friend class JITWriteBarrierBase; + typedef AbstractMacroAssembler AbstractMacroAssemblerType; typedef AssemblerType AssemblerType_T; typedef MacroAssemblerCodePtr CodePtr; @@ -92,6 +101,13 @@ public: class Jump; typedef typename AssemblerType::RegisterID RegisterID; + typedef typename AssemblerType::FPRegisterID FPRegisterID; + + static RegisterID firstRegister() { return AssemblerType::firstRegister(); } + static RegisterID lastRegister() { return AssemblerType::lastRegister(); } + + static FPRegisterID firstFPRegister() { return AssemblerType::firstFPRegister(); } + static FPRegisterID lastFPRegister() { return AssemblerType::lastFPRegister(); } // Section 1: MacroAssembler operand types // @@ -104,6 +120,13 @@ public: TimesFour, TimesEight, }; + + static Scale timesPtr() + { + if (sizeof(void*) == 4) + return TimesFour; + return TimesEight; + } // Address: // @@ -114,7 +137,12 @@ public: , offset(offset) { } - + + Address withOffset(int32_t additionalOffset) + { + return Address(base, offset + additionalOffset); + } + RegisterID base; int32_t offset; }; @@ -177,6 +205,11 @@ public: RegisterID index; Scale scale; int32_t offset; + + BaseIndex withOffset(int32_t additionalOffset) + { + return BaseIndex(base, index, scale, offset + additionalOffset); + } }; // AbsoluteAddress: @@ -226,12 +259,7 @@ public: const void* m_value; }; - struct ImmPtr : -#if ENABLE(JIT_CONSTANT_BLINDING) - private TrustedImmPtr -#else - public TrustedImmPtr -#endif + struct ImmPtr : private TrustedImmPtr { explicit ImmPtr(const void* value) : TrustedImmPtr(value) @@ -266,13 +294,7 @@ public: }; - struct Imm32 : -#if ENABLE(JIT_CONSTANT_BLINDING) - private TrustedImm32 -#else - public TrustedImm32 -#endif - { + struct Imm32 : private TrustedImm32 { explicit Imm32(int32_t value) : TrustedImm32(value) { @@ -311,12 +333,7 @@ public: int64_t m_value; }; - struct Imm64 : -#if ENABLE(JIT_CONSTANT_BLINDING) - private TrustedImm64 -#else - public TrustedImm64 -#endif + struct Imm64 : private TrustedImm64 { explicit Imm64(int64_t value) : TrustedImm64(value) @@ -344,11 +361,10 @@ public: // A Label records a point in the generated instruction stream, typically such that // it may be used as a destination for a jump. class Label { - template + template friend class AbstractMacroAssembler; friend struct DFG::OSRExit; friend class Jump; - friend class JumpReplacementWatchpoint; friend class MacroAssemblerCodeRef; friend class LinkBuffer; friend class Watchpoint; @@ -358,7 +374,7 @@ public: { } - Label(AbstractMacroAssembler* masm) + Label(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { masm->invalidateAllTempRegisters(); @@ -380,7 +396,7 @@ public: // // addPtr(TrustedImmPtr(i), a, b) class ConvertibleLoadLabel { - template + template friend class AbstractMacroAssembler; friend class LinkBuffer; @@ -389,7 +405,7 @@ public: { } - ConvertibleLoadLabel(AbstractMacroAssembler* masm) + ConvertibleLoadLabel(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.labelIgnoringWatchpoints()) { } @@ -404,7 +420,7 @@ public: // A DataLabelPtr is used to refer to a location in the code containing a pointer to be // patched after the code has been generated. class DataLabelPtr { - template + template friend class AbstractMacroAssembler; friend class LinkBuffer; public: @@ -412,7 +428,7 @@ public: { } - DataLabelPtr(AbstractMacroAssembler* masm) + DataLabelPtr(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { } @@ -425,10 +441,10 @@ public: // DataLabel32: // - // A DataLabelPtr is used to refer to a location in the code containing a pointer to be + // A DataLabel32 is used to refer to a location in the code containing a 32-bit constant to be // patched after the code has been generated. class DataLabel32 { - template + template friend class AbstractMacroAssembler; friend class LinkBuffer; public: @@ -436,7 +452,7 @@ public: { } - DataLabel32(AbstractMacroAssembler* masm) + DataLabel32(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { } @@ -452,7 +468,7 @@ public: // A DataLabelCompact is used to refer to a location in the code containing a // compact immediate to be patched after the code has been generated. class DataLabelCompact { - template + template friend class AbstractMacroAssembler; friend class LinkBuffer; public: @@ -460,7 +476,7 @@ public: { } - DataLabelCompact(AbstractMacroAssembler* masm) + DataLabelCompact(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { } @@ -470,6 +486,8 @@ public: { } + AssemblerLabel label() const { return m_label; } + private: AssemblerLabel m_label; }; @@ -481,7 +499,7 @@ public: // relative offset such that when executed it will call to the desired // destination. class Call { - template + template friend class AbstractMacroAssembler; public: @@ -525,7 +543,7 @@ public: // relative offset such that when executed it will jump to the desired // destination. class Jump { - template + template friend class AbstractMacroAssembler; friend class Call; friend struct DFG::OSRExit; @@ -590,7 +608,7 @@ public: return result; } - void link(AbstractMacroAssembler* masm) const + void link(AbstractMacroAssemblerType* masm) const { masm->invalidateAllTempRegisters(); @@ -614,7 +632,7 @@ public: #endif } - void linkTo(Label label, AbstractMacroAssembler* masm) const + void linkTo(Label label, AbstractMacroAssemblerType* masm) const { #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION) masm->checkRegisterAllocationAgainstBranchRange(label.m_label.m_offset, m_label.m_offset); @@ -682,10 +700,11 @@ public: JumpList(Jump jump) { - append(jump); + if (jump.isSet()) + append(jump); } - void link(AbstractMacroAssembler* masm) + void link(AbstractMacroAssemblerType* masm) { size_t size = m_jumps.size(); for (size_t i = 0; i < size; ++i) @@ -693,7 +712,7 @@ public: m_jumps.clear(); } - void linkTo(Label label, AbstractMacroAssembler* masm) + void linkTo(Label label, AbstractMacroAssemblerType* masm) { size_t size = m_jumps.size(); for (size_t i = 0; i < size; ++i) @@ -775,7 +794,7 @@ public: { } - void check(unsigned low, unsigned high) + void checkOffsets(unsigned low, unsigned high) { RELEASE_ASSERT_WITH_MESSAGE(!(low <= m_offset && m_offset <= high), "Unsafe branch over register allocation at instruction offset %u in jump offset range %u..%u", m_offset, low, high); } @@ -801,7 +820,7 @@ public: size_t size = m_registerAllocationForOffsets.size(); for (size_t i = 0; i < size; ++i) - m_registerAllocationForOffsets[i].check(offset1, offset2); + m_registerAllocationForOffsets[i].checkOffsets(offset1, offset2); } #endif @@ -822,14 +841,198 @@ public: { AssemblerType::cacheFlush(code, size); } + +#if ENABLE(MASM_PROBE) + + struct CPUState { + #define DECLARE_REGISTER(_type, _regName) \ + _type _regName; + FOR_EACH_CPU_REGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + + static const char* registerName(RegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case RegisterID::_regName: \ + return #_regName; + FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + static const char* registerName(FPRegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case FPRegisterID::_regName: \ + return #_regName; + FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + void* registerValue(RegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case RegisterID::_regName: \ + return _regName; + FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + double registerValue(FPRegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case FPRegisterID::_regName: \ + return _regName; + FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + }; + + struct ProbeContext; + typedef void (*ProbeFunction)(struct ProbeContext*); + + struct ProbeContext { + ProbeFunction probeFunction; + void* arg1; + void* arg2; + CPUState cpu; + + void print(int indentation = 0) + { + #define INDENT MacroAssemblerType::printIndent(indentation) + + INDENT, dataLogF("ProbeContext %p {\n", this); + indentation++; + { + INDENT, dataLogF("probeFunction: %p\n", probeFunction); + INDENT, dataLogF("arg1: %p %llu\n", arg1, reinterpret_cast(arg1)); + INDENT, dataLogF("arg2: %p %llu\n", arg2, reinterpret_cast(arg2)); + MacroAssemblerType::printCPU(cpu, indentation); + } + indentation--; + INDENT, dataLog("}\n"); + + #undef INDENT + } + }; + + static void printIndent(int indentation) + { + for (; indentation > 0; indentation--) + dataLog(" "); + } + + static void printCPU(CPUState& cpu, int indentation = 0) + { + #define INDENT printIndent(indentation) + + INDENT, dataLog("cpu: {\n"); + MacroAssemblerType::printCPURegisters(cpu, indentation + 1); + INDENT, dataLog("}\n"); + + #undef INDENT + } + + // This is a marker type only used with print(). See print() below for details. + struct AllRegisters { }; + + // Emits code which will print debugging info at runtime. The type of values that + // can be printed is encapsulated in the PrintArg struct below. Here are some + // examples: + // + // print("Hello world\n"); // Emits code to print the string. + // + // CodeBlock* cb = ...; + // print(cb); // Emits code to print the pointer value. + // + // RegisterID regID = ...; + // print(regID); // 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 + // // ... + // // } + // print(AllRegisters()); + // + // // Print multiple things at once. This incurs the probe overhead only once + // // to print all the items. + // print("cb:", cb, " regID:", regID, " cpu:\n", AllRegisters()); + + template + void print(Arguments... args) + { + printInternal(static_cast(this), args...); + } + + // This function will be called by printCPU() to print the contents of the + // target specific registers which are saved away in the CPUState struct. + // printCPURegisters() should make use of printIndentation() to print the + // registers with the appropriate amount of indentation. + // + // Note: printCPURegisters() should be implemented by the target specific + // MacroAssembler. This prototype is only provided here to document the + // interface. + + static void printCPURegisters(CPUState&, int indentation = 0); + + // This function will be called by print() to print the contents of a + // specific register (from the CPUState) in line with other items in the + // print stream. Hence, no indentation is needed. + // + // Note: printRegister() should be implemented by the target specific + // MacroAssembler. These prototypes are only provided here to document their + // interface. + + static void printRegister(CPUState&, RegisterID); + static void printRegister(CPUState&, FPRegisterID); + + // This function emits code to preserve the CPUState (e.g. registers), + // call a user supplied probe function, and restore the CPUState before + // continuing with other JIT generated code. + // + // The user supplied probe function will be called with a single pointer to + // a ProbeContext struct (defined above) which contains, among other things, + // the preserved CPUState. This allows the user probe function to inspect + // the CPUState at that point in the JIT generated code. + // + // If the user probe function alters the register values in the ProbeContext, + // the altered values will be loaded into the CPU registers when the probe + // returns. + // + // The ProbeContext is stack allocated and is only valid for the duration + // of the call to the user probe function. + // + // Note: probe() should be implemented by the target specific MacroAssembler. + // This prototype is only provided here to document the interface. + + void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); + +#endif // ENABLE(MASM_PROBE) + + AssemblerType m_assembler; + protected: AbstractMacroAssembler() : m_randomSource(cryptographicallyRandomNumber()) { + invalidateAllTempRegisters(); } - AssemblerType m_assembler; - uint32_t random() { return m_randomSource.getUint32(); @@ -841,11 +1044,18 @@ protected: Vector m_registerAllocationForOffsets; #endif -#if ENABLE(JIT_CONSTANT_BLINDING) - static bool scratchRegisterForBlinding() { return false; } - static bool shouldBlindForSpecificArch(uint32_t) { return true; } - static bool shouldBlindForSpecificArch(uint64_t) { return true; } -#endif + static bool haveScratchRegisterForBlinding() + { + return false; + } + static RegisterID scratchRegisterForBlinding() + { + UNREACHABLE_FOR_PLATFORM(); + return firstRegister(); + } + static bool canBlind() { return false; } + static bool shouldBlindForSpecificArch(uint32_t) { return false; } + static bool shouldBlindForSpecificArch(uint64_t) { return false; } class CachedTempRegister { friend class DataLabelPtr; @@ -855,7 +1065,7 @@ protected: friend class Label; public: - CachedTempRegister(AbstractMacroAssembler* masm, RegisterID registerID) + CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID) : m_masm(masm) , m_registerID(registerID) , m_value(0) @@ -883,7 +1093,7 @@ protected: ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); } private: - AbstractMacroAssembler* m_masm; + AbstractMacroAssemblerType* m_masm; RegisterID m_registerID; intptr_t m_value; unsigned m_validBit; @@ -973,7 +1183,143 @@ protected: { AssemblerType::replaceWithAddressComputation(label.dataLocation()); } -}; + +private: + +#if ENABLE(MASM_PROBE) + + struct PrintArg { + + enum class Type { + AllRegisters, + RegisterID, + FPRegisterID, + ConstCharPtr, + ConstVoidPtr, + IntptrValue, + UintptrValue, + }; + + PrintArg(AllRegisters&) + : type(Type::AllRegisters) + { + } + + PrintArg(RegisterID regID) + : type(Type::RegisterID) + { + u.gpRegisterID = regID; + } + + PrintArg(FPRegisterID regID) + : type(Type::FPRegisterID) + { + u.fpRegisterID = regID; + } + + 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 { + RegisterID gpRegisterID; + FPRegisterID fpRegisterID; + const char* constCharPtr; + const void* constVoidPtr; + intptr_t intptrValue; + uintptr_t uintptrValue; + } u; + }; + + typedef Vector PrintArgsList; + + template + static void appendPrintArg(PrintArgsList* argsList, FirstArg& firstArg, Arguments... otherArgs) + { + argsList->append(PrintArg(firstArg)); + appendPrintArg(argsList, otherArgs...); + } + + static void appendPrintArg(PrintArgsList*) { } + + + template + static void printInternal(MacroAssemblerType* masm, Arguments... args) + { + auto argsList = std::make_unique(); + appendPrintArg(argsList.get(), args...); + masm->probe(printCallback, argsList.release()); + } + + static void printCallback(ProbeContext* context) + { + typedef PrintArg Arg; + PrintArgsList& argsList = + *reinterpret_cast(context->arg1); + for (size_t i = 0; i < argsList.size(); i++) { + auto& arg = argsList[i]; + switch (arg.type) { + case Arg::Type::AllRegisters: + MacroAssemblerType::printCPU(context->cpu); + break; + case Arg::Type::RegisterID: + MacroAssemblerType::printRegister(context->cpu, arg.u.gpRegisterID); + break; + case Arg::Type::FPRegisterID: + MacroAssemblerType::printRegister(context->cpu, arg.u.fpRegisterID); + 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; + } + } + } + +#endif // ENABLE(MASM_PROBE) + +}; // class AbstractMacroAssembler } // namespace JSC