/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 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
#ifndef MacroAssemblerCodeRef_h
#define MacroAssemblerCodeRef_h
-#include <wtf/Platform.h>
-
+#include "Disassembler.h"
#include "ExecutableAllocator.h"
-#include "PassRefPtr.h"
-#include "RefPtr.h"
-#include "UnusedParam.h"
-
-#if ENABLE(ASSEMBLER)
+#include "LLIntData.h"
+#include <wtf/DataLog.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/PrintStream.h>
+#include <wtf/RefPtr.h>
// ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid
// instruction address on the platform (for example, check any alignment requirements).
-#if PLATFORM_ARM_ARCH(7)
-// ARM/thumb instructions must be 16-bit aligned, but all code pointers to be loaded
-// into the processor are decorated with the bottom bit set, indicating that this is
-// thumb code (as oposed to 32-bit traditional ARM). The first test checks for both
-// decorated and undectorated null, and the second test ensures that the pointer is
-// decorated.
+#if CPU(ARM_THUMB2) && ENABLE(JIT)
+// ARM instructions must be 16-bit aligned. Thumb2 code pointers to be loaded into
+// into the processor are decorated with the bottom bit set, while traditional ARM has
+// the lower bit clear. Since we don't know what kind of pointer, we check for both
+// decorated and undecorated null.
#define ASSERT_VALID_CODE_POINTER(ptr) \
- ASSERT(reinterpret_cast<intptr_t>(ptr) & ~1); \
- ASSERT(reinterpret_cast<intptr_t>(ptr) & 1)
+ ASSERT(reinterpret_cast<intptr_t>(ptr) & ~1)
#define ASSERT_VALID_CODE_OFFSET(offset) \
ASSERT(!(offset & 1)) // Must be multiple of 2.
#else
#define ASSERT_VALID_CODE_OFFSET(offset) // Anything goes!
#endif
+#if CPU(X86) && OS(WINDOWS)
+#define CALLING_CONVENTION_IS_STDCALL 1
+#ifndef CDECL
+#if COMPILER(MSVC)
+#define CDECL __cdecl
+#else
+#define CDECL __attribute__ ((__cdecl))
+#endif // COMPILER(MSVC)
+#endif // CDECL
+#else
+#define CALLING_CONVENTION_IS_STDCALL 0
+#endif
+
+#if CPU(X86)
+#define HAS_FASTCALL_CALLING_CONVENTION 1
+#ifndef FASTCALL
+#if COMPILER(MSVC)
+#define FASTCALL __fastcall
+#else
+#define FASTCALL __attribute__ ((fastcall))
+#endif // COMPILER(MSVC)
+#endif // FASTCALL
+#else
+#define HAS_FASTCALL_CALLING_CONVENTION 0
+#endif // CPU(X86)
+
namespace JSC {
// FunctionPtr:
{
}
+ template<typename returnType>
+ FunctionPtr(returnType(*value)())
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1>
+ FunctionPtr(returnType(*value)(argType1))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2>
+ FunctionPtr(returnType(*value)(argType1, argType2))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3>
+ FunctionPtr(returnType(*value)(argType1, argType2, argType3))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3, typename argType4>
+ FunctionPtr(returnType(*value)(argType1, argType2, argType3, argType4))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3, typename argType4, typename argType5>
+ FunctionPtr(returnType(*value)(argType1, argType2, argType3, argType4, argType5))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+// MSVC doesn't seem to treat functions with different calling conventions as
+// different types; these methods already defined for fastcall, below.
+#if CALLING_CONVENTION_IS_STDCALL && !OS(WINDOWS)
+
+ template<typename returnType>
+ FunctionPtr(returnType (CDECL *value)())
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1>
+ FunctionPtr(returnType (CDECL *value)(argType1))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2>
+ FunctionPtr(returnType (CDECL *value)(argType1, argType2))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3>
+ FunctionPtr(returnType (CDECL *value)(argType1, argType2, argType3))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3, typename argType4>
+ FunctionPtr(returnType (CDECL *value)(argType1, argType2, argType3, argType4))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+#endif
+
+#if HAS_FASTCALL_CALLING_CONVENTION
+
+ template<typename returnType>
+ FunctionPtr(returnType (FASTCALL *value)())
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1>
+ FunctionPtr(returnType (FASTCALL *value)(argType1))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2>
+ FunctionPtr(returnType (FASTCALL *value)(argType1, argType2))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3>
+ FunctionPtr(returnType (FASTCALL *value)(argType1, argType2, argType3))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+
+ template<typename returnType, typename argType1, typename argType2, typename argType3, typename argType4>
+ FunctionPtr(returnType (FASTCALL *value)(argType1, argType2, argType3, argType4))
+ : m_value((void*)value)
+ {
+ ASSERT_VALID_CODE_POINTER(m_value);
+ }
+#endif
+
template<typename FunctionType>
explicit FunctionPtr(FunctionType* value)
- : m_value(reinterpret_cast<void*>(value))
+ // Using a C-ctyle cast here to avoid compiler error on RVTC:
+ // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers
+ // (I guess on RVTC function pointers have a different constness to GCC/MSVC?)
+ : m_value((void*)value)
{
ASSERT_VALID_CODE_POINTER(m_value);
}
}
void* value() const { return m_value; }
+
+ void dump(PrintStream& out) const
+ {
+ out.print(RawPointer(m_value));
+ }
private:
void* m_value;
}
explicit MacroAssemblerCodePtr(void* value)
-#if PLATFORM_ARM_ARCH(7)
+#if CPU(ARM_THUMB2)
// Decorate the pointer as a thumb code pointer.
: m_value(reinterpret_cast<char*>(value) + 1)
#else
{
ASSERT_VALID_CODE_POINTER(m_value);
}
+
+ static MacroAssemblerCodePtr createFromExecutableAddress(void* value)
+ {
+ ASSERT_VALID_CODE_POINTER(value);
+ MacroAssemblerCodePtr result;
+ result.m_value = value;
+ return result;
+ }
+
+ static MacroAssemblerCodePtr createLLIntCodePtr(OpcodeID codeId)
+ {
+ return createFromExecutableAddress(LLInt::getCodePtr(codeId));
+ }
explicit MacroAssemblerCodePtr(ReturnAddressPtr ra)
: m_value(ra.value())
}
void* executableAddress() const { return m_value; }
-#if PLATFORM_ARM_ARCH(7)
+#if CPU(ARM_THUMB2)
// To use this pointer as a data address remove the decoration.
void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return reinterpret_cast<char*>(m_value) - 1; }
#else
void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return m_value; }
#endif
- bool operator!()
+ typedef void* (MacroAssemblerCodePtr::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const
+ {
+ return !!m_value ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
+ }
+
+ bool operator==(const MacroAssemblerCodePtr& other) const
+ {
+ return m_value == other.m_value;
+ }
+
+ void dumpWithName(const char* name, PrintStream& out) const
+ {
+ if (executableAddress() == dataLocation()) {
+ out.print(name, "(", RawPointer(executableAddress()), ")");
+ return;
+ }
+ out.print(name, "(executable = ", RawPointer(executableAddress()), ", dataLocation = ", RawPointer(dataLocation()), ")");
+ }
+
+ void dump(PrintStream& out) const
+ {
+ dumpWithName("CodePtr", out);
+ }
+
+ enum EmptyValueTag { EmptyValue };
+ enum DeletedValueTag { DeletedValue };
+
+ MacroAssemblerCodePtr(EmptyValueTag)
+ : m_value(emptyValue())
+ {
+ }
+
+ MacroAssemblerCodePtr(DeletedValueTag)
+ : m_value(deletedValue())
{
- return !m_value;
}
+
+ bool isEmptyValue() const { return m_value == emptyValue(); }
+ bool isDeletedValue() const { return m_value == deletedValue(); }
+
+ unsigned hash() const { return PtrHash<void*>::hash(m_value); }
private:
+ static void* emptyValue() { return bitwise_cast<void*>(static_cast<intptr_t>(1)); }
+ static void* deletedValue() { return bitwise_cast<void*>(static_cast<intptr_t>(2)); }
+
void* m_value;
};
+struct MacroAssemblerCodePtrHash {
+ static unsigned hash(const MacroAssemblerCodePtr& ptr) { return ptr.hash(); }
+ static bool equal(const MacroAssemblerCodePtr& a, const MacroAssemblerCodePtr& b)
+ {
+ return a == b;
+ }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
// MacroAssemblerCodeRef:
//
// A reference to a section of JIT generated code. A CodeRef consists of a
// pointer to the code, and a ref pointer to the pool from within which it
// was allocated.
class MacroAssemblerCodeRef {
+private:
+ // This is private because it's dangerous enough that we want uses of it
+ // to be easy to find - hence the static create method below.
+ explicit MacroAssemblerCodeRef(MacroAssemblerCodePtr codePtr)
+ : m_codePtr(codePtr)
+ {
+ ASSERT(m_codePtr);
+ }
+
public:
MacroAssemblerCodeRef()
- : m_size(0)
{
}
- MacroAssemblerCodeRef(void* code, PassRefPtr<ExecutablePool> executablePool, size_t size)
- : m_code(code)
- , m_executablePool(executablePool)
- , m_size(size)
+ MacroAssemblerCodeRef(PassRefPtr<ExecutableMemoryHandle> executableMemory)
+ : m_codePtr(executableMemory->start())
+ , m_executableMemory(executableMemory)
+ {
+ ASSERT(m_executableMemory->isManaged());
+ ASSERT(m_executableMemory->start());
+ ASSERT(m_codePtr);
+ }
+
+ // Use this only when you know that the codePtr refers to code that is
+ // already being kept alive through some other means. Typically this means
+ // that codePtr is immortal.
+ static MacroAssemblerCodeRef createSelfManagedCodeRef(MacroAssemblerCodePtr codePtr)
+ {
+ return MacroAssemblerCodeRef(codePtr);
+ }
+
+ // Helper for creating self-managed code refs from LLInt.
+ static MacroAssemblerCodeRef createLLIntCodeRef(OpcodeID codeId)
{
+ return createSelfManagedCodeRef(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(codeId)));
}
- MacroAssemblerCodePtr m_code;
- RefPtr<ExecutablePool> m_executablePool;
- size_t m_size;
+ ExecutableMemoryHandle* executableMemory() const
+ {
+ return m_executableMemory.get();
+ }
+
+ MacroAssemblerCodePtr code() const
+ {
+ return m_codePtr;
+ }
+
+ size_t size() const
+ {
+ if (!m_executableMemory)
+ return 0;
+ return m_executableMemory->sizeInBytes();
+ }
+
+ bool tryToDisassemble(const char* prefix) const
+ {
+ return JSC::tryToDisassemble(m_codePtr, size(), prefix, WTF::dataFile());
+ }
+
+ typedef void* (MacroAssemblerCodeRef::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const
+ {
+ return !!m_codePtr ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
+ }
+
+ void dump(PrintStream& out) const
+ {
+ m_codePtr.dumpWithName("CodeRef", out);
+ }
+
+private:
+ MacroAssemblerCodePtr m_codePtr;
+ RefPtr<ExecutableMemoryHandle> m_executableMemory;
};
} // namespace JSC
-#endif // ENABLE(ASSEMBLER)
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::MacroAssemblerCodePtr> {
+ typedef JSC::MacroAssemblerCodePtrHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::MacroAssemblerCodePtr> : public CustomHashTraits<JSC::MacroAssemblerCodePtr> { };
+
+} // namespace WTF
#endif // MacroAssemblerCodeRef_h