зеркало из https://github.com/mozilla/pjs.git
Bug 564953: Port of Yarr regexp engine and Nitro macroassembler. No PPC support. (r=gal,lw)
This commit is contained in:
Родитель
0a7922e78a
Коммит
9975411941
|
@ -68,7 +68,6 @@ _TEST_FILES = \
|
|||
gZipOfflineChild.html^headers^ \
|
||||
gZipOfflineChild.cacheManifest \
|
||||
gZipOfflineChild.cacheManifest^headers^ \
|
||||
test_bug452451.html \
|
||||
$(NULL)
|
||||
|
||||
ifeq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
|
||||
|
|
|
@ -287,6 +287,50 @@ endif
|
|||
|
||||
endif # ENABLE_TRACEJIT
|
||||
|
||||
###############################################
|
||||
# BEGIN include sources for the Nitro assembler
|
||||
#
|
||||
VPATH += $(srcdir)/assembler \
|
||||
$(srcdir)/assembler/wtf \
|
||||
$(srcdir)/assembler/jit \
|
||||
$(srcdir)/assembler/assembler \
|
||||
$(srcdir)/yarr \
|
||||
$(srcdir)/yarr/yarr \
|
||||
$(srcdir)/yarr/pcre \
|
||||
$(srcdir)/yarr/wtf \
|
||||
|
||||
CPPSRCS += Assertions.cpp \
|
||||
ExecutableAllocatorPosix.cpp \
|
||||
ExecutableAllocatorWin.cpp \
|
||||
ExecutableAllocator.cpp \
|
||||
ARMAssembler.cpp \
|
||||
MacroAssemblerARM.cpp \
|
||||
RegexCompiler.cpp \
|
||||
RegexJIT.cpp \
|
||||
pcre_compile.cpp \
|
||||
pcre_exec.cpp \
|
||||
pcre_tables.cpp \
|
||||
pcre_xclass.cpp \
|
||||
pcre_ucp_searchfuncs.cpp
|
||||
|
||||
ifeq (86, $(findstring 86,$(TARGET_CPU)))
|
||||
ifeq (x86_64, $(TARGET_CPU))
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
ASFILES += TrampolineMasmX64.asm
|
||||
endif
|
||||
#CPPSRCS += only_on_x86_64.cpp
|
||||
else
|
||||
#CPPSRCS += only_on_x86.cpp
|
||||
endif
|
||||
endif
|
||||
ifeq (arm, $(TARGET_CPU))
|
||||
#CPPSRCS += only_on_arm.cpp
|
||||
endif
|
||||
#
|
||||
# END enclude sources for the Nitro assembler
|
||||
#############################################
|
||||
|
||||
|
||||
ifdef JS_HAS_CTYPES
|
||||
VPATH += $(srcdir)/ctypes
|
||||
|
||||
|
@ -735,3 +779,18 @@ update-nanojit:
|
|||
|
||||
.PHONY: update-nanojit
|
||||
endif
|
||||
|
||||
###############################################
|
||||
# BEGIN kludges for the Nitro assembler
|
||||
#
|
||||
|
||||
INCLUDES += -I$(srcdir)/assembler -I$(srcdir)/yarr
|
||||
#
|
||||
# Needed to "configure" it correctly. Unfortunately these
|
||||
# flags wind up being applied to all code in js/src, not just
|
||||
# the code in js/src/assembler.
|
||||
CXXFLAGS += -DENABLE_ASSEMBLER=1 -DUSE_SYSTEM_MALLOC=1 -DENABLE_JIT=1
|
||||
|
||||
#
|
||||
# END kludges for the Nitro assembler
|
||||
###############################################
|
||||
|
|
|
@ -0,0 +1,929 @@
|
|||
|
||||
// A short test program with which to experiment with the assembler.
|
||||
|
||||
//satisfies CPU(X86_64)
|
||||
//#define WTF_CPU_X86_64
|
||||
|
||||
// satisfies ENABLE(ASSEMBLER)
|
||||
#define ENABLE_ASSEMBLER 1
|
||||
|
||||
// satisfies ENABLE(JIT)
|
||||
#define ENABLE_JIT 1
|
||||
|
||||
#define USE_SYSTEM_MALLOC 1
|
||||
// leads to FORCE_SYSTEM_MALLOC in wtf/FastMalloc.cpp
|
||||
|
||||
#include <jit/ExecutableAllocator.h>
|
||||
#include <assembler/LinkBuffer.h>
|
||||
#include <assembler/CodeLocation.h>
|
||||
#include <assembler/RepatchBuffer.h>
|
||||
|
||||
#include <assembler/MacroAssembler.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Temporary scaffolding for selecting the arch
|
||||
#undef ARCH_x86
|
||||
#undef ARCH_amd64
|
||||
#undef ARCH_arm
|
||||
|
||||
#if defined(__APPLE__) && defined(__i386__)
|
||||
# define ARCH_x86 1
|
||||
#elif defined(__APPLE__) && defined(__x86_64__)
|
||||
# define ARCH_amd64 1
|
||||
#elif defined(__linux__) && defined(__i386__)
|
||||
# define ARCH_x86 1
|
||||
#elif defined(__linux__) && defined(__x86_64__)
|
||||
# define ARCH_amd64 1
|
||||
#elif defined(__linux__) && defined(__arm__)
|
||||
# define ARCH_arm 1
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||
# define ARCH_x86 1
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// just somewhere convenient to put a breakpoint, before
|
||||
// running gdb
|
||||
#if WTF_COMPILER_GCC
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
void pre_run ( void ) { }
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//// test1 (simple straight line code)
|
||||
#if WTF_COMPILER_GCC
|
||||
|
||||
void test1 ( void )
|
||||
{
|
||||
printf("\n------------ Test 1 (straight line code) ------------\n\n" );
|
||||
|
||||
// Create new assembler
|
||||
JSC::MacroAssembler* am = new JSC::MacroAssembler();
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15;
|
||||
// dump some instructions into it
|
||||
// xor %r15,%r15
|
||||
// add $0x7b,%r15
|
||||
// add $0x141,%r15
|
||||
// retq
|
||||
am->xorPtr(areg,areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_x86)
|
||||
JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi;
|
||||
// dump some instructions into it
|
||||
// xor %edi,%edi
|
||||
// add $0x7b,%edi
|
||||
// add $0x141,%edi
|
||||
// ret
|
||||
am->xorPtr(areg,areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_arm)
|
||||
JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8;
|
||||
// eors r8, r8, r8
|
||||
// adds r8, r8, #123 ; 0x7b
|
||||
// mov r3, #256 ; 0x100
|
||||
// orr r3, r3, #65 ; 0x41
|
||||
// adds r8, r8, r3
|
||||
// mov pc, lr
|
||||
am->xorPtr(areg,areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
// prepare a link buffer, into which we can copy the completed insns
|
||||
JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
|
||||
|
||||
// intermediate step .. get the pool suited for the size of code in 'am'
|
||||
//WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
|
||||
JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
|
||||
|
||||
// constructor for LinkBuffer asks ep to allocate r-x memory,
|
||||
// then copies it there.
|
||||
JSC::LinkBuffer patchBuffer(am, ep);
|
||||
|
||||
// finalize
|
||||
JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
|
||||
|
||||
// cr now holds a pointer to the final runnable code.
|
||||
void* entry = cr.m_code.executableAddress();
|
||||
|
||||
printf("disas %p %p\n",
|
||||
entry, (char*)entry + cr.m_size);
|
||||
pre_run();
|
||||
|
||||
unsigned long result = 0x55555555;
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
// call the generated piece of code. It puts its result in r15.
|
||||
__asm__ __volatile__(
|
||||
"callq *%1" "\n\t"
|
||||
"movq %%r15, %0" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "r15","cc"
|
||||
);
|
||||
#endif
|
||||
#if defined(ARCH_x86)
|
||||
// call the generated piece of code. It puts its result in edi.
|
||||
__asm__ __volatile__(
|
||||
"calll *%1" "\n\t"
|
||||
"movl %%edi, %0" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "edi","cc"
|
||||
);
|
||||
#endif
|
||||
#if defined(ARCH_arm)
|
||||
// call the generated piece of code. It puts its result in r8.
|
||||
__asm__ __volatile__(
|
||||
"blx %1" "\n\t"
|
||||
"mov %0, %%r8" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "r8","cc"
|
||||
);
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
printf("value computed is %lu (expected 444)\n", result);
|
||||
printf("\n");
|
||||
|
||||
delete eal;
|
||||
delete am;
|
||||
}
|
||||
|
||||
#endif /* WTF_COMPILER_GCC */
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//// test2 (a simple counting-down loop)
|
||||
#if WTF_COMPILER_GCC
|
||||
|
||||
void test2 ( void )
|
||||
{
|
||||
printf("\n------------ Test 2 (mini loop) ------------\n\n" );
|
||||
|
||||
// Create new assembler
|
||||
JSC::MacroAssembler* am = new JSC::MacroAssembler();
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15;
|
||||
// xor %r15,%r15
|
||||
// add $0x7b,%r15
|
||||
// add $0x141,%r15
|
||||
// sub $0x1,%r15
|
||||
// mov $0x0,%r11
|
||||
// cmp %r11,%r15
|
||||
// jne 0x7ff6d3e6a00e
|
||||
// retq
|
||||
// so r15 always winds up being zero
|
||||
am->xorPtr(areg,areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
|
||||
|
||||
JSC::MacroAssembler::Label loopHeadLabel(am);
|
||||
am->subPtr(JSC::MacroAssembler::Imm32(1), areg);
|
||||
|
||||
JSC::MacroAssembler::Jump j
|
||||
= am->branchPtr(JSC::MacroAssembler::NotEqual,
|
||||
areg, JSC::MacroAssembler::ImmPtr(0));
|
||||
j.linkTo(loopHeadLabel, am);
|
||||
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_x86)
|
||||
JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi;
|
||||
// xor %edi,%edi
|
||||
// add $0x7b,%edi
|
||||
// add $0x141,%edi
|
||||
// sub $0x1,%edi
|
||||
// test %edi,%edi
|
||||
// jne 0xf7f9700b
|
||||
// ret
|
||||
// so edi always winds up being zero
|
||||
am->xorPtr(areg,areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
|
||||
|
||||
JSC::MacroAssembler::Label loopHeadLabel(am);
|
||||
am->subPtr(JSC::MacroAssembler::Imm32(1), areg);
|
||||
|
||||
JSC::MacroAssembler::Jump j
|
||||
= am->branchPtr(JSC::MacroAssembler::NotEqual,
|
||||
areg, JSC::MacroAssembler::ImmPtr(0));
|
||||
j.linkTo(loopHeadLabel, am);
|
||||
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_arm)
|
||||
JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8;
|
||||
// eors r8, r8, r8
|
||||
// adds r8, r8, #123 ; 0x7b
|
||||
// mov r3, #256 ; 0x100
|
||||
// orr r3, r3, #65 ; 0x41
|
||||
// adds r8, r8, r3
|
||||
// subs r8, r8, #1 ; 0x1
|
||||
// ldr r3, [pc, #8] ; 0x40026028
|
||||
// cmp r8, r3
|
||||
// bne 0x40026014
|
||||
// mov pc, lr
|
||||
// andeq r0, r0, r0 // DATA (0)
|
||||
// andeq r0, r0, r4, lsl r0 // DATA (?? what's this for?)
|
||||
// so r8 always winds up being zero
|
||||
am->xorPtr(areg,areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
|
||||
|
||||
JSC::MacroAssembler::Label loopHeadLabel(am);
|
||||
am->subPtr(JSC::MacroAssembler::Imm32(1), areg);
|
||||
|
||||
JSC::MacroAssembler::Jump j
|
||||
= am->branchPtr(JSC::MacroAssembler::NotEqual,
|
||||
areg, JSC::MacroAssembler::ImmPtr(0));
|
||||
j.linkTo(loopHeadLabel, am);
|
||||
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
// prepare a link buffer, into which we can copy the completed insns
|
||||
JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
|
||||
|
||||
// intermediate step .. get the pool suited for the size of code in 'am'
|
||||
//WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
|
||||
JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
|
||||
|
||||
// constructor for LinkBuffer asks ep to allocate r-x memory,
|
||||
// then copies it there.
|
||||
JSC::LinkBuffer patchBuffer(am, ep);
|
||||
|
||||
// finalize
|
||||
JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
|
||||
|
||||
// cr now holds a pointer to the final runnable code.
|
||||
void* entry = cr.m_code.executableAddress();
|
||||
|
||||
printf("disas %p %p\n",
|
||||
entry, (char*)entry + cr.m_size);
|
||||
pre_run();
|
||||
|
||||
unsigned long result = 0x55555555;
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
// call the generated piece of code. It puts its result in r15.
|
||||
__asm__ __volatile__(
|
||||
"callq *%1" "\n\t"
|
||||
"movq %%r15, %0" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "r15","cc"
|
||||
);
|
||||
#endif
|
||||
#if defined(ARCH_x86)
|
||||
// call the generated piece of code. It puts its result in edi.
|
||||
__asm__ __volatile__(
|
||||
"calll *%1" "\n\t"
|
||||
"movl %%edi, %0" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "edi","cc"
|
||||
);
|
||||
#endif
|
||||
#if defined(ARCH_arm)
|
||||
// call the generated piece of code. It puts its result in r8.
|
||||
__asm__ __volatile__(
|
||||
"blx %1" "\n\t"
|
||||
"mov %0, %%r8" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "r8","cc"
|
||||
);
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
printf("value computed is %lu (expected 0)\n", result);
|
||||
printf("\n");
|
||||
|
||||
delete eal;
|
||||
delete am;
|
||||
}
|
||||
|
||||
#endif /* WTF_COMPILER_GCC */
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//// test3 (if-then-else)
|
||||
#if WTF_COMPILER_GCC
|
||||
|
||||
void test3 ( void )
|
||||
{
|
||||
printf("\n------------ Test 3 (if-then-else) ------------\n\n" );
|
||||
|
||||
// Create new assembler
|
||||
JSC::MacroAssembler* am = new JSC::MacroAssembler();
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15;
|
||||
// mov $0x64,%r15d
|
||||
// mov $0x0,%r11
|
||||
// cmp %r11,%r15
|
||||
// jne 0x7ff6d3e6a024
|
||||
// mov $0x40,%r15d
|
||||
// jmpq 0x7ff6d3e6a02a
|
||||
// mov $0x4,%r15d
|
||||
// retq
|
||||
// so r15 ends up being 4
|
||||
|
||||
// put a value in reg
|
||||
am->move(JSC::MacroAssembler::Imm32(100), areg);
|
||||
|
||||
// test, and conditionally jump to 'else' branch
|
||||
JSC::MacroAssembler::Jump jToElse
|
||||
= am->branchPtr(JSC::MacroAssembler::NotEqual,
|
||||
areg, JSC::MacroAssembler::ImmPtr(0));
|
||||
|
||||
// 'then' branch
|
||||
am->move(JSC::MacroAssembler::Imm32(64), areg);
|
||||
JSC::MacroAssembler::Jump jToAfter
|
||||
= am->jump();
|
||||
|
||||
// 'else' branch
|
||||
JSC::MacroAssembler::Label elseLbl(am);
|
||||
am->move(JSC::MacroAssembler::Imm32(4), areg);
|
||||
|
||||
// after
|
||||
JSC::MacroAssembler::Label afterLbl(am);
|
||||
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_x86)
|
||||
JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi;
|
||||
// mov $0x64,%edi
|
||||
// test %edi,%edi
|
||||
// jne 0xf7f22017
|
||||
// mov $0x40,%edi
|
||||
// jmp 0xf7f2201c
|
||||
// mov $0x4,%edi
|
||||
// ret
|
||||
// so edi ends up being 4
|
||||
|
||||
// put a value in reg
|
||||
am->move(JSC::MacroAssembler::Imm32(100), areg);
|
||||
|
||||
// test, and conditionally jump to 'else' branch
|
||||
JSC::MacroAssembler::Jump jToElse
|
||||
= am->branchPtr(JSC::MacroAssembler::NotEqual,
|
||||
areg, JSC::MacroAssembler::ImmPtr(0));
|
||||
|
||||
// 'then' branch
|
||||
am->move(JSC::MacroAssembler::Imm32(64), areg);
|
||||
JSC::MacroAssembler::Jump jToAfter
|
||||
= am->jump();
|
||||
|
||||
// 'else' branch
|
||||
JSC::MacroAssembler::Label elseLbl(am);
|
||||
am->move(JSC::MacroAssembler::Imm32(4), areg);
|
||||
|
||||
// after
|
||||
JSC::MacroAssembler::Label afterLbl(am);
|
||||
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_arm)
|
||||
JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8;
|
||||
// mov r8, #100 ; 0x64
|
||||
// ldr r3, [pc, #20] ; 0x40026020
|
||||
// cmp r8, r3
|
||||
// bne 0x40026018
|
||||
// mov r8, #64 ; 0x40
|
||||
// b 0x4002601c
|
||||
// mov r8, #4 ; 0x4
|
||||
// mov pc, lr
|
||||
// andeq r0, r0, r0 // DATA
|
||||
// andeq r0, r0, r8, lsl r0 // DATA
|
||||
// andeq r0, r0, r12, lsl r0 // DATA
|
||||
// ldr r3, [r3, -r3] // DATA
|
||||
// so r8 ends up being 4
|
||||
|
||||
// put a value in reg
|
||||
am->move(JSC::MacroAssembler::Imm32(100), areg);
|
||||
|
||||
// test, and conditionally jump to 'else' branch
|
||||
JSC::MacroAssembler::Jump jToElse
|
||||
= am->branchPtr(JSC::MacroAssembler::NotEqual,
|
||||
areg, JSC::MacroAssembler::ImmPtr(0));
|
||||
|
||||
// 'then' branch
|
||||
am->move(JSC::MacroAssembler::Imm32(64), areg);
|
||||
JSC::MacroAssembler::Jump jToAfter
|
||||
= am->jump();
|
||||
|
||||
// 'else' branch
|
||||
JSC::MacroAssembler::Label elseLbl(am);
|
||||
am->move(JSC::MacroAssembler::Imm32(4), areg);
|
||||
|
||||
// after
|
||||
JSC::MacroAssembler::Label afterLbl(am);
|
||||
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
// set branch targets appropriately
|
||||
jToElse.linkTo(elseLbl, am);
|
||||
jToAfter.linkTo(afterLbl, am);
|
||||
|
||||
// prepare a link buffer, into which we can copy the completed insns
|
||||
JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
|
||||
|
||||
// intermediate step .. get the pool suited for the size of code in 'am'
|
||||
//WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
|
||||
JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
|
||||
|
||||
// constructor for LinkBuffer asks ep to allocate r-x memory,
|
||||
// then copies it there.
|
||||
JSC::LinkBuffer patchBuffer(am, ep);
|
||||
|
||||
// finalize
|
||||
JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
|
||||
|
||||
// cr now holds a pointer to the final runnable code.
|
||||
void* entry = cr.m_code.executableAddress();
|
||||
|
||||
printf("disas %p %p\n",
|
||||
entry, (char*)entry + cr.m_size);
|
||||
pre_run();
|
||||
|
||||
unsigned long result = 0x55555555;
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
// call the generated piece of code. It puts its result in r15.
|
||||
__asm__ __volatile__(
|
||||
"callq *%1" "\n\t"
|
||||
"movq %%r15, %0" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "r15","cc"
|
||||
);
|
||||
#endif
|
||||
#if defined(ARCH_x86)
|
||||
// call the generated piece of code. It puts its result in edi.
|
||||
__asm__ __volatile__(
|
||||
"calll *%1" "\n\t"
|
||||
"movl %%edi, %0" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "edi","cc"
|
||||
);
|
||||
#endif
|
||||
#if defined(ARCH_arm)
|
||||
// call the generated piece of code. It puts its result in r8.
|
||||
__asm__ __volatile__(
|
||||
"blx %1" "\n\t"
|
||||
"mov %0, %%r8" "\n"
|
||||
:/*out*/ "=r"(result)
|
||||
:/*in*/ "r"(entry)
|
||||
:/*trash*/ "r8","cc"
|
||||
);
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
printf("value computed is %lu (expected 4)\n", result);
|
||||
printf("\n");
|
||||
|
||||
delete eal;
|
||||
delete am;
|
||||
}
|
||||
|
||||
#endif /* WTF_COMPILER_GCC */
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//// test4 (callable function)
|
||||
|
||||
void test4 ( void )
|
||||
{
|
||||
printf("\n------------ Test 4 (callable fn) ------------\n\n" );
|
||||
|
||||
// Create new assembler
|
||||
JSC::MacroAssembler* am = new JSC::MacroAssembler();
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
// ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
|
||||
// push %rbp
|
||||
// mov %rsp,%rbp
|
||||
// push %rbx
|
||||
// push %r12
|
||||
// push %r13
|
||||
// push %r14
|
||||
// push %r15
|
||||
// xor %rax,%rax
|
||||
// add $0x7b,%rax
|
||||
// add $0x141,%rax
|
||||
// pop %r15
|
||||
// pop %r14
|
||||
// pop %r13
|
||||
// pop %r12
|
||||
// pop %rbx
|
||||
// mov %rbp,%rsp
|
||||
// pop %rbp
|
||||
// retq
|
||||
// callable as a normal function, returns 444
|
||||
|
||||
JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax;
|
||||
am->push(JSC::X86Registers::ebp);
|
||||
am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
|
||||
am->push(JSC::X86Registers::ebx);
|
||||
am->push(JSC::X86Registers::r12);
|
||||
am->push(JSC::X86Registers::r13);
|
||||
am->push(JSC::X86Registers::r14);
|
||||
am->push(JSC::X86Registers::r15);
|
||||
|
||||
am->xorPtr(rreg,rreg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), rreg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), rreg);
|
||||
|
||||
am->pop(JSC::X86Registers::r15);
|
||||
am->pop(JSC::X86Registers::r14);
|
||||
am->pop(JSC::X86Registers::r13);
|
||||
am->pop(JSC::X86Registers::r12);
|
||||
am->pop(JSC::X86Registers::ebx);
|
||||
am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
|
||||
am->pop(JSC::X86Registers::ebp);
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_x86)
|
||||
// ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
|
||||
// push %ebp
|
||||
// mov %esp,%ebp
|
||||
// push %ebx
|
||||
// push %esi
|
||||
// push %edi
|
||||
// xor %eax,%eax
|
||||
// add $0x7b,%eax
|
||||
// add $0x141,%eax
|
||||
// pop %edi
|
||||
// pop %esi
|
||||
// pop %ebx
|
||||
// mov %ebp,%esp
|
||||
// pop %ebp
|
||||
// ret
|
||||
// callable as a normal function, returns 444
|
||||
|
||||
JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax;
|
||||
|
||||
am->push(JSC::X86Registers::ebp);
|
||||
am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
|
||||
am->push(JSC::X86Registers::ebx);
|
||||
am->push(JSC::X86Registers::esi);
|
||||
am->push(JSC::X86Registers::edi);
|
||||
|
||||
am->xorPtr(rreg,rreg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), rreg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), rreg);
|
||||
|
||||
am->pop(JSC::X86Registers::edi);
|
||||
am->pop(JSC::X86Registers::esi);
|
||||
am->pop(JSC::X86Registers::ebx);
|
||||
am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
|
||||
am->pop(JSC::X86Registers::ebp);
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_arm)
|
||||
// ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
|
||||
// push {r4} ; (str r4, [sp, #-4]!)
|
||||
// push {r5} ; (str r5, [sp, #-4]!)
|
||||
// push {r6} ; (str r6, [sp, #-4]!)
|
||||
// push {r7} ; (str r7, [sp, #-4]!)
|
||||
// push {r8} ; (str r8, [sp, #-4]!)
|
||||
// push {r9} ; (str r9, [sp, #-4]!)
|
||||
// push {r10} ; (str r10, [sp, #-4]!)
|
||||
// push {r11} ; (str r11, [sp, #-4]!)
|
||||
// eors r0, r0, r0
|
||||
// adds r0, r0, #123 ; 0x7b
|
||||
// mov r3, #256 ; 0x100
|
||||
// orr r3, r3, #65 ; 0x41
|
||||
// adds r0, r0, r3
|
||||
// pop {r11} ; (ldr r11, [sp], #4)
|
||||
// pop {r10} ; (ldr r10, [sp], #4)
|
||||
// pop {r9} ; (ldr r9, [sp], #4)
|
||||
// pop {r8} ; (ldr r8, [sp], #4)
|
||||
// pop {r7} ; (ldr r7, [sp], #4)
|
||||
// pop {r6} ; (ldr r6, [sp], #4)
|
||||
// pop {r5} ; (ldr r5, [sp], #4)
|
||||
// pop {r4} ; (ldr r4, [sp], #4)
|
||||
// mov pc, lr
|
||||
// callable as a normal function, returns 444
|
||||
|
||||
JSC::ARMRegisters::RegisterID rreg = JSC::ARMRegisters::r0;
|
||||
|
||||
am->push(JSC::ARMRegisters::r4);
|
||||
am->push(JSC::ARMRegisters::r5);
|
||||
am->push(JSC::ARMRegisters::r6);
|
||||
am->push(JSC::ARMRegisters::r7);
|
||||
am->push(JSC::ARMRegisters::r8);
|
||||
am->push(JSC::ARMRegisters::r9);
|
||||
am->push(JSC::ARMRegisters::r10);
|
||||
am->push(JSC::ARMRegisters::r11);
|
||||
|
||||
am->xorPtr(rreg,rreg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(123), rreg);
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(321), rreg);
|
||||
|
||||
am->pop(JSC::ARMRegisters::r11);
|
||||
am->pop(JSC::ARMRegisters::r10);
|
||||
am->pop(JSC::ARMRegisters::r9);
|
||||
am->pop(JSC::ARMRegisters::r8);
|
||||
am->pop(JSC::ARMRegisters::r7);
|
||||
am->pop(JSC::ARMRegisters::r6);
|
||||
am->pop(JSC::ARMRegisters::r5);
|
||||
am->pop(JSC::ARMRegisters::r4);
|
||||
|
||||
am->ret();
|
||||
#endif
|
||||
|
||||
// prepare a link buffer, into which we can copy the completed insns
|
||||
JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
|
||||
|
||||
// intermediate step .. get the pool suited for the size of code in 'am'
|
||||
//WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
|
||||
JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
|
||||
|
||||
// constructor for LinkBuffer asks ep to allocate r-x memory,
|
||||
// then copies it there.
|
||||
JSC::LinkBuffer patchBuffer(am, ep);
|
||||
|
||||
// now fix up any branches/calls
|
||||
//JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube );
|
||||
|
||||
// finalize
|
||||
JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
|
||||
|
||||
// cr now holds a pointer to the final runnable code.
|
||||
void* entry = cr.m_code.executableAddress();
|
||||
|
||||
printf("disas %p %p\n",
|
||||
entry, (char*)entry + cr.m_size);
|
||||
pre_run();
|
||||
|
||||
// call the function
|
||||
unsigned long (*fn)(void) = (unsigned long (*)())entry;
|
||||
unsigned long result = fn();
|
||||
|
||||
printf("\n");
|
||||
printf("value computed is %lu (expected 444)\n", result);
|
||||
printf("\n");
|
||||
|
||||
delete eal;
|
||||
delete am;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//// test5 (call in, out, repatch)
|
||||
|
||||
// a function which we will call from the JIT generated code
|
||||
unsigned long cube ( unsigned long x ) { return x * x * x; }
|
||||
unsigned long square ( unsigned long x ) { return x * x; }
|
||||
|
||||
void test5 ( void )
|
||||
{
|
||||
printf("\n--------- Test 5 (call in, out, repatch) ---------\n\n" );
|
||||
|
||||
// Create new assembler
|
||||
JSC::MacroAssembler* am = new JSC::MacroAssembler();
|
||||
JSC::MacroAssembler::Call cl;
|
||||
ptrdiff_t offset_of_call_insn;
|
||||
|
||||
#if defined(ARCH_amd64)
|
||||
// ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
|
||||
// and then call a non-JIT-generated helper from within
|
||||
// this code
|
||||
// push %rbp
|
||||
// mov %rsp,%rbp
|
||||
// push %rbx
|
||||
// push %r12
|
||||
// push %r13
|
||||
// push %r14
|
||||
// push %r15
|
||||
// mov $0x9,%edi
|
||||
// mov $0x40187e,%r11
|
||||
// callq *%r11
|
||||
// pop %r15
|
||||
// pop %r14
|
||||
// pop %r13
|
||||
// pop %r12
|
||||
// pop %rbx
|
||||
// mov %rbp,%rsp
|
||||
// pop %rbp
|
||||
// retq
|
||||
JSC::MacroAssembler::Label startOfFnLbl(am);
|
||||
am->push(JSC::X86Registers::ebp);
|
||||
am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
|
||||
am->push(JSC::X86Registers::ebx);
|
||||
am->push(JSC::X86Registers::r12);
|
||||
am->push(JSC::X86Registers::r13);
|
||||
am->push(JSC::X86Registers::r14);
|
||||
am->push(JSC::X86Registers::r15);
|
||||
|
||||
// let's compute cube(9). Move $9 to the first arg reg.
|
||||
am->move(JSC::MacroAssembler::Imm32(9), JSC::X86Registers::edi);
|
||||
cl = am->JSC::MacroAssembler::call();
|
||||
|
||||
// result is now in %rax. Leave it ther and just return.
|
||||
|
||||
am->pop(JSC::X86Registers::r15);
|
||||
am->pop(JSC::X86Registers::r14);
|
||||
am->pop(JSC::X86Registers::r13);
|
||||
am->pop(JSC::X86Registers::r12);
|
||||
am->pop(JSC::X86Registers::ebx);
|
||||
am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
|
||||
am->pop(JSC::X86Registers::ebp);
|
||||
am->ret();
|
||||
|
||||
offset_of_call_insn
|
||||
= am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl);
|
||||
if (0) printf("XXXXXXXX offset = %lu\n", offset_of_call_insn);
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_x86)
|
||||
// ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
|
||||
// and then call a non-JIT-generated helper from within
|
||||
// this code
|
||||
// push %ebp
|
||||
// mov %esp,%ebp
|
||||
// push %ebx
|
||||
// push %esi
|
||||
// push %edi
|
||||
// push $0x9
|
||||
// call 0x80490e9 <_Z4cubem>
|
||||
// add $0x4,%esp
|
||||
// pop %edi
|
||||
// pop %esi
|
||||
// pop %ebx
|
||||
// mov %ebp,%esp
|
||||
// pop %ebp
|
||||
// ret
|
||||
JSC::MacroAssembler::Label startOfFnLbl(am);
|
||||
am->push(JSC::X86Registers::ebp);
|
||||
am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
|
||||
am->push(JSC::X86Registers::ebx);
|
||||
am->push(JSC::X86Registers::esi);
|
||||
am->push(JSC::X86Registers::edi);
|
||||
|
||||
// let's compute cube(9). Push $9 on the stack.
|
||||
am->push(JSC::MacroAssembler::Imm32(9));
|
||||
cl = am->JSC::MacroAssembler::call();
|
||||
am->addPtr(JSC::MacroAssembler::Imm32(4), JSC::X86Registers::esp);
|
||||
// result is now in %eax. Leave it there and just return.
|
||||
|
||||
am->pop(JSC::X86Registers::edi);
|
||||
am->pop(JSC::X86Registers::esi);
|
||||
am->pop(JSC::X86Registers::ebx);
|
||||
am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
|
||||
am->pop(JSC::X86Registers::ebp);
|
||||
am->ret();
|
||||
|
||||
offset_of_call_insn
|
||||
= am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl);
|
||||
if (0) printf("XXXXXXXX offset = %lu\n",
|
||||
(unsigned long)offset_of_call_insn);
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_arm)
|
||||
// ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
|
||||
// push {r4} ; (str r4, [sp, #-4]!)
|
||||
// push {r5} ; (str r5, [sp, #-4]!)
|
||||
// push {r6} ; (str r6, [sp, #-4]!)
|
||||
// push {r7} ; (str r7, [sp, #-4]!)
|
||||
// push {r8} ; (str r8, [sp, #-4]!)
|
||||
// push {r9} ; (str r9, [sp, #-4]!)
|
||||
// push {r10} ; (str r10, [sp, #-4]!)
|
||||
// push {r11} ; (str r11, [sp, #-4]!)
|
||||
// eors r0, r0, r0
|
||||
// adds r0, r0, #123 ; 0x7b
|
||||
// mov r3, #256 ; 0x100
|
||||
// orr r3, r3, #65 ; 0x41
|
||||
// adds r0, r0, r3
|
||||
// pop {r11} ; (ldr r11, [sp], #4)
|
||||
// pop {r10} ; (ldr r10, [sp], #4)
|
||||
// pop {r9} ; (ldr r9, [sp], #4)
|
||||
// pop {r8} ; (ldr r8, [sp], #4)
|
||||
// pop {r7} ; (ldr r7, [sp], #4)
|
||||
// pop {r6} ; (ldr r6, [sp], #4)
|
||||
// pop {r5} ; (ldr r5, [sp], #4)
|
||||
// pop {r4} ; (ldr r4, [sp], #4)
|
||||
// mov pc, lr
|
||||
// callable as a normal function, returns 444
|
||||
JSC::MacroAssembler::Label startOfFnLbl(am);
|
||||
am->push(JSC::ARMRegisters::r4);
|
||||
am->push(JSC::ARMRegisters::r5);
|
||||
am->push(JSC::ARMRegisters::r6);
|
||||
am->push(JSC::ARMRegisters::r7);
|
||||
am->push(JSC::ARMRegisters::r8);
|
||||
am->push(JSC::ARMRegisters::r9);
|
||||
am->push(JSC::ARMRegisters::r10);
|
||||
am->push(JSC::ARMRegisters::r11);
|
||||
am->push(JSC::ARMRegisters::lr);
|
||||
|
||||
// let's compute cube(9). Get $9 into r0.
|
||||
am->move(JSC::MacroAssembler::Imm32(9), JSC::ARMRegisters::r0);
|
||||
cl = am->JSC::MacroAssembler::call();
|
||||
// result is now in r0. Leave it there and just return.
|
||||
|
||||
am->pop(JSC::ARMRegisters::lr);
|
||||
am->pop(JSC::ARMRegisters::r11);
|
||||
am->pop(JSC::ARMRegisters::r10);
|
||||
am->pop(JSC::ARMRegisters::r9);
|
||||
am->pop(JSC::ARMRegisters::r8);
|
||||
am->pop(JSC::ARMRegisters::r7);
|
||||
am->pop(JSC::ARMRegisters::r6);
|
||||
am->pop(JSC::ARMRegisters::r5);
|
||||
am->pop(JSC::ARMRegisters::r4);
|
||||
am->ret();
|
||||
|
||||
offset_of_call_insn
|
||||
= am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl);
|
||||
if (0) printf("XXXXXXXX offset = %lu\n",
|
||||
(unsigned long)offset_of_call_insn);
|
||||
#endif
|
||||
|
||||
// prepare a link buffer, into which we can copy the completed insns
|
||||
JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
|
||||
|
||||
// intermediate step .. get the pool suited for the size of code in 'am'
|
||||
//WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
|
||||
JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
|
||||
|
||||
// constructor for LinkBuffer asks ep to allocate r-x memory,
|
||||
// then copies it there.
|
||||
JSC::LinkBuffer patchBuffer(am, ep);
|
||||
|
||||
// now fix up any branches/calls
|
||||
JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube );
|
||||
patchBuffer.link(cl, target);
|
||||
|
||||
JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
|
||||
|
||||
// cr now holds a pointer to the final runnable code.
|
||||
void* entry = cr.m_code.executableAddress();
|
||||
|
||||
printf("disas %p %p\n",
|
||||
entry, (char*)entry + cr.m_size);
|
||||
|
||||
|
||||
pre_run();
|
||||
|
||||
printf("\n");
|
||||
|
||||
unsigned long (*fn)() = (unsigned long(*)())entry;
|
||||
unsigned long result = fn();
|
||||
|
||||
printf("value computed is %lu (expected 729)\n", result);
|
||||
printf("\n");
|
||||
|
||||
// now repatch the call in the JITted code to go elsewhere
|
||||
JSC::JITCode jc = JSC::JITCode::JITCode(entry, cr.m_size);
|
||||
JSC::CodeBlock cb = JSC::CodeBlock::CodeBlock(jc);
|
||||
|
||||
// the address of the call insn, that we want to prod
|
||||
JSC::MacroAssemblerCodePtr cp
|
||||
= JSC::MacroAssemblerCodePtr( ((char*)entry) + offset_of_call_insn );
|
||||
|
||||
JSC::RepatchBuffer repatchBuffer(&cb);
|
||||
repatchBuffer.relink( JSC::CodeLocationCall(cp),
|
||||
JSC::FunctionPtr::FunctionPtr( &square ));
|
||||
|
||||
result = fn();
|
||||
printf("value computed is %lu (expected 81)\n", result);
|
||||
printf("\n\n");
|
||||
|
||||
delete eal;
|
||||
delete am;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
#if WTF_COMPILER_GCC
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
#endif
|
||||
test4();
|
||||
test5();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* Copyright (C) 2009 University of Szeged
|
||||
* 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL
|
||||
|
||||
#include "ARMAssembler.h"
|
||||
|
||||
namespace JSC {
|
||||
|
||||
// Patching helpers
|
||||
|
||||
void ARMAssembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
|
||||
{
|
||||
ARMWord *ldr = reinterpret_cast<ARMWord*>(loadAddr);
|
||||
ARMWord diff = reinterpret_cast<ARMWord*>(constPoolAddr) - ldr;
|
||||
ARMWord index = (*ldr & 0xfff) >> 1;
|
||||
|
||||
ASSERT(diff >= 1);
|
||||
if (diff >= 2 || index > 0) {
|
||||
diff = (diff + index - 2) * sizeof(ARMWord);
|
||||
ASSERT(diff <= 0xfff);
|
||||
*ldr = (*ldr & ~0xfff) | diff;
|
||||
} else
|
||||
*ldr = (*ldr & ~(0xfff | ARMAssembler::DT_UP)) | sizeof(ARMWord);
|
||||
}
|
||||
|
||||
// Handle immediates
|
||||
|
||||
ARMWord ARMAssembler::getOp2(ARMWord imm)
|
||||
{
|
||||
int rol;
|
||||
|
||||
if (imm <= 0xff)
|
||||
return OP2_IMM | imm;
|
||||
|
||||
if ((imm & 0xff000000) == 0) {
|
||||
imm <<= 8;
|
||||
rol = 8;
|
||||
}
|
||||
else {
|
||||
imm = (imm << 24) | (imm >> 8);
|
||||
rol = 0;
|
||||
}
|
||||
|
||||
if ((imm & 0xff000000) == 0) {
|
||||
imm <<= 8;
|
||||
rol += 4;
|
||||
}
|
||||
|
||||
if ((imm & 0xf0000000) == 0) {
|
||||
imm <<= 4;
|
||||
rol += 2;
|
||||
}
|
||||
|
||||
if ((imm & 0xc0000000) == 0) {
|
||||
imm <<= 2;
|
||||
rol += 1;
|
||||
}
|
||||
|
||||
if ((imm & 0x00ffffff) == 0)
|
||||
return OP2_IMM | (imm >> 24) | (rol << 8);
|
||||
|
||||
return INVALID_IMM;
|
||||
}
|
||||
|
||||
int ARMAssembler::genInt(int reg, ARMWord imm, bool positive)
|
||||
{
|
||||
// Step1: Search a non-immediate part
|
||||
ARMWord mask;
|
||||
ARMWord imm1;
|
||||
ARMWord imm2;
|
||||
int rol;
|
||||
|
||||
mask = 0xff000000;
|
||||
rol = 8;
|
||||
while(1) {
|
||||
if ((imm & mask) == 0) {
|
||||
imm = (imm << rol) | (imm >> (32 - rol));
|
||||
rol = 4 + (rol >> 1);
|
||||
break;
|
||||
}
|
||||
rol += 2;
|
||||
mask >>= 2;
|
||||
if (mask & 0x3) {
|
||||
// rol 8
|
||||
imm = (imm << 8) | (imm >> 24);
|
||||
mask = 0xff00;
|
||||
rol = 24;
|
||||
while (1) {
|
||||
if ((imm & mask) == 0) {
|
||||
imm = (imm << rol) | (imm >> (32 - rol));
|
||||
rol = (rol >> 1) - 8;
|
||||
break;
|
||||
}
|
||||
rol += 2;
|
||||
mask >>= 2;
|
||||
if (mask & 0x3)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT((imm & 0xff) == 0);
|
||||
|
||||
if ((imm & 0xff000000) == 0) {
|
||||
imm1 = OP2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);
|
||||
imm2 = OP2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
|
||||
} else if (imm & 0xc0000000) {
|
||||
imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
|
||||
imm <<= 8;
|
||||
rol += 4;
|
||||
|
||||
if ((imm & 0xff000000) == 0) {
|
||||
imm <<= 8;
|
||||
rol += 4;
|
||||
}
|
||||
|
||||
if ((imm & 0xf0000000) == 0) {
|
||||
imm <<= 4;
|
||||
rol += 2;
|
||||
}
|
||||
|
||||
if ((imm & 0xc0000000) == 0) {
|
||||
imm <<= 2;
|
||||
rol += 1;
|
||||
}
|
||||
|
||||
if ((imm & 0x00ffffff) == 0)
|
||||
imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
if ((imm & 0xf0000000) == 0) {
|
||||
imm <<= 4;
|
||||
rol += 2;
|
||||
}
|
||||
|
||||
if ((imm & 0xc0000000) == 0) {
|
||||
imm <<= 2;
|
||||
rol += 1;
|
||||
}
|
||||
|
||||
imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
|
||||
imm <<= 8;
|
||||
rol += 4;
|
||||
|
||||
if ((imm & 0xf0000000) == 0) {
|
||||
imm <<= 4;
|
||||
rol += 2;
|
||||
}
|
||||
|
||||
if ((imm & 0xc0000000) == 0) {
|
||||
imm <<= 2;
|
||||
rol += 1;
|
||||
}
|
||||
|
||||
if ((imm & 0x00ffffff) == 0)
|
||||
imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (positive) {
|
||||
mov_r(reg, imm1);
|
||||
orr_r(reg, reg, imm2);
|
||||
} else {
|
||||
mvn_r(reg, imm1);
|
||||
bic_r(reg, reg, imm2);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert)
|
||||
{
|
||||
ARMWord tmp;
|
||||
|
||||
// Do it by 1 instruction
|
||||
tmp = getOp2(imm);
|
||||
if (tmp != INVALID_IMM)
|
||||
return tmp;
|
||||
|
||||
tmp = getOp2(~imm);
|
||||
if (tmp != INVALID_IMM) {
|
||||
if (invert)
|
||||
return tmp | OP2_INV_IMM;
|
||||
mvn_r(tmpReg, tmp);
|
||||
return tmpReg;
|
||||
}
|
||||
|
||||
return encodeComplexImm(imm, tmpReg);
|
||||
}
|
||||
|
||||
void ARMAssembler::moveImm(ARMWord imm, int dest)
|
||||
{
|
||||
ARMWord tmp;
|
||||
|
||||
// Do it by 1 instruction
|
||||
tmp = getOp2(imm);
|
||||
if (tmp != INVALID_IMM) {
|
||||
mov_r(dest, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = getOp2(~imm);
|
||||
if (tmp != INVALID_IMM) {
|
||||
mvn_r(dest, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
encodeComplexImm(imm, dest);
|
||||
}
|
||||
|
||||
ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest)
|
||||
{
|
||||
#if WTF_ARM_ARCH_VERSION >= 7
|
||||
ARMWord tmp = getImm16Op2(imm);
|
||||
if (tmp != INVALID_IMM) {
|
||||
movw_r(dest, tmp);
|
||||
return dest;
|
||||
}
|
||||
movw_r(dest, getImm16Op2(imm & 0xffff));
|
||||
movt_r(dest, getImm16Op2(imm >> 16));
|
||||
return dest;
|
||||
#else
|
||||
// Do it by 2 instruction
|
||||
if (genInt(dest, imm, true))
|
||||
return dest;
|
||||
if (genInt(dest, ~imm, false))
|
||||
return dest;
|
||||
|
||||
ldr_imm(dest, imm);
|
||||
return dest;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Memory load/store helpers
|
||||
|
||||
void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes)
|
||||
{
|
||||
ARMWord transferFlag = bytes ? DT_BYTE : 0;
|
||||
if (offset >= 0) {
|
||||
if (offset <= 0xfff)
|
||||
dtr_u(isLoad, srcDst, base, offset | transferFlag);
|
||||
else if (offset <= 0xfffff) {
|
||||
add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff) | transferFlag);
|
||||
} else {
|
||||
ARMWord reg = getImm(offset, ARMRegisters::S0);
|
||||
dtr_ur(isLoad, srcDst, base, reg | transferFlag);
|
||||
}
|
||||
} else {
|
||||
offset = -offset;
|
||||
if (offset <= 0xfff)
|
||||
dtr_d(isLoad, srcDst, base, offset);
|
||||
else if (offset <= 0xfffff) {
|
||||
sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
|
||||
dtr_d(isLoad, srcDst, ARMRegisters::S0, offset & 0xfff);
|
||||
} else {
|
||||
ARMWord reg = getImm(offset, ARMRegisters::S0);
|
||||
dtr_dr(isLoad, srcDst, base, reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
|
||||
{
|
||||
ARMWord op2;
|
||||
|
||||
ASSERT(scale >= 0 && scale <= 3);
|
||||
op2 = lsl(index, scale);
|
||||
|
||||
if (offset >= 0 && offset <= 0xfff) {
|
||||
add_r(ARMRegisters::S0, base, op2);
|
||||
dtr_u(isLoad, srcDst, ARMRegisters::S0, offset);
|
||||
return;
|
||||
}
|
||||
if (offset <= 0 && offset >= -0xfff) {
|
||||
add_r(ARMRegisters::S0, base, op2);
|
||||
dtr_d(isLoad, srcDst, ARMRegisters::S0, -offset);
|
||||
return;
|
||||
}
|
||||
|
||||
ldr_un_imm(ARMRegisters::S0, offset);
|
||||
add_r(ARMRegisters::S0, ARMRegisters::S0, op2);
|
||||
dtr_ur(isLoad, srcDst, base, ARMRegisters::S0);
|
||||
}
|
||||
|
||||
void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset)
|
||||
{
|
||||
if (offset & 0x3) {
|
||||
if (offset <= 0x3ff && offset >= 0) {
|
||||
fdtr_u(isLoad, srcDst, base, offset >> 2);
|
||||
return;
|
||||
}
|
||||
if (offset <= 0x3ffff && offset >= 0) {
|
||||
add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8));
|
||||
fdtr_u(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
|
||||
return;
|
||||
}
|
||||
offset = -offset;
|
||||
|
||||
if (offset <= 0x3ff && offset >= 0) {
|
||||
fdtr_d(isLoad, srcDst, base, offset >> 2);
|
||||
return;
|
||||
}
|
||||
if (offset <= 0x3ffff && offset >= 0) {
|
||||
sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8));
|
||||
fdtr_d(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
|
||||
return;
|
||||
}
|
||||
offset = -offset;
|
||||
}
|
||||
|
||||
ldr_un_imm(ARMRegisters::S0, offset);
|
||||
add_r(ARMRegisters::S0, ARMRegisters::S0, base);
|
||||
fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0);
|
||||
}
|
||||
|
||||
void* ARMAssembler::executableCopy(ExecutablePool* allocator)
|
||||
{
|
||||
// 64-bit alignment is required for next constant pool and JIT code as well
|
||||
m_buffer.flushWithoutBarrier(true);
|
||||
if (m_buffer.uncheckedSize() & 0x7)
|
||||
bkpt(0);
|
||||
|
||||
char* data = reinterpret_cast<char*>(m_buffer.executableCopy(allocator));
|
||||
|
||||
for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
|
||||
// The last bit is set if the constant must be placed on constant pool.
|
||||
int pos = (*iter) & (~0x1);
|
||||
ARMWord* ldrAddr = reinterpret_cast<ARMWord*>(data + pos);
|
||||
ARMWord offset = *getLdrImmAddress(ldrAddr);
|
||||
if (offset != 0xffffffff) {
|
||||
JmpSrc jmpSrc(pos);
|
||||
linkBranch(data, jmpSrc, data + offset, ((*iter) & 1));
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,556 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef AbstractMacroAssembler_h
|
||||
#define AbstractMacroAssembler_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
#include "assembler/assembler/MacroAssemblerCodeRef.h"
|
||||
#include "assembler/assembler/CodeLocation.h"
|
||||
#include "jsstdint.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class LinkBuffer;
|
||||
class RepatchBuffer;
|
||||
|
||||
template <class AssemblerType>
|
||||
class AbstractMacroAssembler {
|
||||
public:
|
||||
typedef AssemblerType AssemblerType_T;
|
||||
|
||||
typedef MacroAssemblerCodePtr CodePtr;
|
||||
typedef MacroAssemblerCodeRef CodeRef;
|
||||
|
||||
class Jump;
|
||||
|
||||
typedef typename AssemblerType::RegisterID RegisterID;
|
||||
typedef typename AssemblerType::FPRegisterID FPRegisterID;
|
||||
typedef typename AssemblerType::JmpSrc JmpSrc;
|
||||
typedef typename AssemblerType::JmpDst JmpDst;
|
||||
|
||||
|
||||
// Section 1: MacroAssembler operand types
|
||||
//
|
||||
// The following types are used as operands to MacroAssembler operations,
|
||||
// describing immediate and memory operands to the instructions to be planted.
|
||||
|
||||
|
||||
enum Scale {
|
||||
TimesOne,
|
||||
TimesTwo,
|
||||
TimesFour,
|
||||
TimesEight
|
||||
};
|
||||
|
||||
// Address:
|
||||
//
|
||||
// Describes a simple base-offset address.
|
||||
struct Address {
|
||||
explicit Address(RegisterID base, int32_t offset = 0)
|
||||
: base(base)
|
||||
, offset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterID base;
|
||||
int32_t offset;
|
||||
};
|
||||
|
||||
struct ExtendedAddress {
|
||||
explicit ExtendedAddress(RegisterID base, intptr_t offset = 0)
|
||||
: base(base)
|
||||
, offset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterID base;
|
||||
intptr_t offset;
|
||||
};
|
||||
|
||||
// ImplicitAddress:
|
||||
//
|
||||
// This class is used for explicit 'load' and 'store' operations
|
||||
// (as opposed to situations in which a memory operand is provided
|
||||
// to a generic operation, such as an integer arithmetic instruction).
|
||||
//
|
||||
// In the case of a load (or store) operation we want to permit
|
||||
// addresses to be implicitly constructed, e.g. the two calls:
|
||||
//
|
||||
// load32(Address(addrReg), destReg);
|
||||
// load32(addrReg, destReg);
|
||||
//
|
||||
// Are equivalent, and the explicit wrapping of the Address in the former
|
||||
// is unnecessary.
|
||||
struct ImplicitAddress {
|
||||
ImplicitAddress(RegisterID base)
|
||||
: base(base)
|
||||
, offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
ImplicitAddress(Address address)
|
||||
: base(address.base)
|
||||
, offset(address.offset)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterID base;
|
||||
int32_t offset;
|
||||
};
|
||||
|
||||
// BaseIndex:
|
||||
//
|
||||
// Describes a complex addressing mode.
|
||||
struct BaseIndex {
|
||||
BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
|
||||
: base(base)
|
||||
, index(index)
|
||||
, scale(scale)
|
||||
, offset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterID base;
|
||||
RegisterID index;
|
||||
Scale scale;
|
||||
int32_t offset;
|
||||
};
|
||||
|
||||
// AbsoluteAddress:
|
||||
//
|
||||
// Describes an memory operand given by a pointer. For regular load & store
|
||||
// operations an unwrapped void* will be used, rather than using this.
|
||||
struct AbsoluteAddress {
|
||||
explicit AbsoluteAddress(void* ptr)
|
||||
: m_ptr(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
void* m_ptr;
|
||||
};
|
||||
|
||||
// ImmPtr:
|
||||
//
|
||||
// A pointer sized immediate operand to an instruction - this is wrapped
|
||||
// in a class requiring explicit construction in order to differentiate
|
||||
// from pointers used as absolute addresses to memory operations
|
||||
struct ImmPtr {
|
||||
explicit ImmPtr(const void* value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
intptr_t asIntptr()
|
||||
{
|
||||
return reinterpret_cast<intptr_t>(m_value);
|
||||
}
|
||||
|
||||
const void* m_value;
|
||||
};
|
||||
|
||||
// Imm32:
|
||||
//
|
||||
// A 32bit immediate operand to an instruction - this is wrapped in a
|
||||
// class requiring explicit construction in order to prevent RegisterIDs
|
||||
// (which are implemented as an enum) from accidentally being passed as
|
||||
// immediate values.
|
||||
struct Imm32 {
|
||||
explicit Imm32(int32_t value)
|
||||
: m_value(value)
|
||||
#if WTF_CPU_ARM || WTF_CPU_MIPS
|
||||
, m_isPointer(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
#if !WTF_CPU_X86_64
|
||||
explicit Imm32(ImmPtr ptr)
|
||||
: m_value(ptr.asIntptr())
|
||||
#if WTF_CPU_ARM
|
||||
, m_isPointer(true)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t m_value;
|
||||
#if WTF_CPU_ARM
|
||||
// We rely on being able to regenerate code to recover exception handling
|
||||
// information. Since ARMv7 supports 16-bit immediates there is a danger
|
||||
// that if pointer values change the layout of the generated code will change.
|
||||
// To avoid this problem, always generate pointers (and thus Imm32s constructed
|
||||
// from ImmPtrs) with a code sequence that is able to represent any pointer
|
||||
// value - don't use a more compact form in these cases.
|
||||
// Same for MIPS.
|
||||
bool m_isPointer;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Section 2: MacroAssembler code buffer handles
|
||||
//
|
||||
// The following types are used to reference items in the code buffer
|
||||
// during JIT code generation. For example, the type Jump is used to
|
||||
// track the location of a jump instruction so that it may later be
|
||||
// linked to a label marking its destination.
|
||||
|
||||
|
||||
// Label:
|
||||
//
|
||||
// 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<class TemplateAssemblerType>
|
||||
friend class AbstractMacroAssembler;
|
||||
friend class Jump;
|
||||
friend class MacroAssemblerCodeRef;
|
||||
friend class LinkBuffer;
|
||||
|
||||
public:
|
||||
Label()
|
||||
{
|
||||
}
|
||||
|
||||
Label(AbstractMacroAssembler<AssemblerType>* masm)
|
||||
: m_label(masm->m_assembler.label())
|
||||
{
|
||||
}
|
||||
|
||||
bool isUsed() const { return m_label.isUsed(); }
|
||||
void used() { m_label.used(); }
|
||||
bool isValid() const { return m_label.isValid(); }
|
||||
private:
|
||||
JmpDst m_label;
|
||||
};
|
||||
|
||||
// DataLabelPtr:
|
||||
//
|
||||
// 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<class TemplateAssemblerType>
|
||||
friend class AbstractMacroAssembler;
|
||||
friend class LinkBuffer;
|
||||
public:
|
||||
DataLabelPtr()
|
||||
{
|
||||
}
|
||||
|
||||
DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
|
||||
: m_label(masm->m_assembler.label())
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
JmpDst m_label;
|
||||
};
|
||||
|
||||
// DataLabel32:
|
||||
//
|
||||
// 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 DataLabel32 {
|
||||
template<class TemplateAssemblerType>
|
||||
friend class AbstractMacroAssembler;
|
||||
friend class LinkBuffer;
|
||||
public:
|
||||
DataLabel32()
|
||||
{
|
||||
}
|
||||
|
||||
DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
|
||||
: m_label(masm->m_assembler.label())
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
JmpDst m_label;
|
||||
};
|
||||
|
||||
// Call:
|
||||
//
|
||||
// A Call object is a reference to a call instruction that has been planted
|
||||
// into the code buffer - it is typically used to link the call, setting the
|
||||
// relative offset such that when executed it will call to the desired
|
||||
// destination.
|
||||
class Call {
|
||||
template<class TemplateAssemblerType>
|
||||
friend class AbstractMacroAssembler;
|
||||
|
||||
public:
|
||||
enum Flags {
|
||||
None = 0x0,
|
||||
Linkable = 0x1,
|
||||
Near = 0x2,
|
||||
LinkableNear = 0x3
|
||||
};
|
||||
|
||||
Call()
|
||||
: m_flags(None)
|
||||
{
|
||||
}
|
||||
|
||||
Call(JmpSrc jmp, Flags flags)
|
||||
: m_jmp(jmp)
|
||||
, m_flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
bool isFlagSet(Flags flag)
|
||||
{
|
||||
return !!(m_flags & flag);
|
||||
}
|
||||
|
||||
static Call fromTailJump(Jump jump)
|
||||
{
|
||||
return Call(jump.m_jmp, Linkable);
|
||||
}
|
||||
|
||||
JmpSrc m_jmp;
|
||||
private:
|
||||
Flags m_flags;
|
||||
};
|
||||
|
||||
// Jump:
|
||||
//
|
||||
// A jump object is a reference to a jump instruction that has been planted
|
||||
// into the code buffer - it is typically used to link the jump, setting the
|
||||
// relative offset such that when executed it will jump to the desired
|
||||
// destination.
|
||||
class Jump {
|
||||
template<class TemplateAssemblerType>
|
||||
friend class AbstractMacroAssembler;
|
||||
friend class Call;
|
||||
friend class LinkBuffer;
|
||||
public:
|
||||
Jump()
|
||||
{
|
||||
}
|
||||
|
||||
Jump(JmpSrc jmp)
|
||||
: m_jmp(jmp)
|
||||
{
|
||||
}
|
||||
|
||||
void link(AbstractMacroAssembler<AssemblerType>* masm)
|
||||
{
|
||||
masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
|
||||
}
|
||||
|
||||
void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
|
||||
{
|
||||
masm->m_assembler.linkJump(m_jmp, label.m_label);
|
||||
}
|
||||
|
||||
private:
|
||||
JmpSrc m_jmp;
|
||||
};
|
||||
|
||||
// JumpList:
|
||||
//
|
||||
// A JumpList is a set of Jump objects.
|
||||
// All jumps in the set will be linked to the same destination.
|
||||
class JumpList {
|
||||
friend class LinkBuffer;
|
||||
|
||||
public:
|
||||
typedef js::Vector<Jump, 16 ,js::SystemAllocPolicy > JumpVector;
|
||||
|
||||
void link(AbstractMacroAssembler<AssemblerType>* masm)
|
||||
{
|
||||
size_t size = m_jumps.length();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
m_jumps[i].link(masm);
|
||||
m_jumps.clear();
|
||||
}
|
||||
|
||||
void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
|
||||
{
|
||||
size_t size = m_jumps.length();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
m_jumps[i].linkTo(label, masm);
|
||||
m_jumps.clear();
|
||||
}
|
||||
|
||||
void append(Jump jump)
|
||||
{
|
||||
m_jumps.append(jump);
|
||||
}
|
||||
|
||||
void append(JumpList& other)
|
||||
{
|
||||
m_jumps.append(other.m_jumps.begin(), other.m_jumps.length());
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return !m_jumps.length();
|
||||
}
|
||||
|
||||
const JumpVector& jumps() { return m_jumps; }
|
||||
|
||||
private:
|
||||
JumpVector m_jumps;
|
||||
};
|
||||
|
||||
|
||||
// Section 3: Misc admin methods
|
||||
|
||||
static CodePtr trampolineAt(CodeRef ref, Label label)
|
||||
{
|
||||
return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label));
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return m_assembler.size();
|
||||
}
|
||||
|
||||
unsigned char *buffer()
|
||||
{
|
||||
return m_assembler.buffer();
|
||||
}
|
||||
|
||||
Label label()
|
||||
{
|
||||
return Label(this);
|
||||
}
|
||||
|
||||
Label align()
|
||||
{
|
||||
m_assembler.align(16);
|
||||
return Label(this);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(Label from, Jump to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(Label from, Call to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(Label from, Label to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(Label from, DataLabel32 to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
|
||||
}
|
||||
|
||||
ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
|
||||
{
|
||||
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
|
||||
}
|
||||
|
||||
protected:
|
||||
AssemblerType m_assembler;
|
||||
|
||||
friend class LinkBuffer;
|
||||
friend class RepatchBuffer;
|
||||
|
||||
static void linkJump(void* code, Jump jump, CodeLocationLabel target)
|
||||
{
|
||||
AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
|
||||
}
|
||||
|
||||
static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
|
||||
{
|
||||
AssemblerType::linkPointer(code, label, value);
|
||||
}
|
||||
|
||||
static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
|
||||
{
|
||||
return AssemblerType::getRelocatedAddress(code, label);
|
||||
}
|
||||
|
||||
static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
|
||||
{
|
||||
return AssemblerType::getRelocatedAddress(code, label);
|
||||
}
|
||||
|
||||
static unsigned getLinkerCallReturnOffset(Call call)
|
||||
{
|
||||
return AssemblerType::getCallReturnOffset(call.m_jmp);
|
||||
}
|
||||
|
||||
static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
|
||||
{
|
||||
AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
|
||||
}
|
||||
|
||||
static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
|
||||
{
|
||||
AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
|
||||
}
|
||||
|
||||
static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
|
||||
{
|
||||
AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
|
||||
}
|
||||
|
||||
static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
|
||||
{
|
||||
AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
|
||||
}
|
||||
|
||||
static void repatchLoadPtrToLEA(CodeLocationInstruction instruction)
|
||||
{
|
||||
AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation());
|
||||
}
|
||||
|
||||
static void repatchLEAToLoadPtr(CodeLocationInstruction instruction)
|
||||
{
|
||||
AssemblerType::repatchLEAToLoadPtr(instruction.dataLocation());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // AbstractMacroAssembler_h
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef AssemblerBuffer_h
|
||||
#define AssemblerBuffer_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
#include <string.h>
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
#include "jsstdint.h"
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class AssemblerBuffer {
|
||||
static const int inlineCapacity = 256;
|
||||
public:
|
||||
AssemblerBuffer()
|
||||
: m_buffer(m_inlineBuffer)
|
||||
, m_capacity(inlineCapacity)
|
||||
, m_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
~AssemblerBuffer()
|
||||
{
|
||||
if (m_buffer != m_inlineBuffer)
|
||||
free(m_buffer);
|
||||
}
|
||||
|
||||
void ensureSpace(int space)
|
||||
{
|
||||
if (m_size > m_capacity - space)
|
||||
grow();
|
||||
}
|
||||
|
||||
bool isAligned(int alignment) const
|
||||
{
|
||||
return !(m_size & (alignment - 1));
|
||||
}
|
||||
|
||||
void putByteUnchecked(int value)
|
||||
{
|
||||
ASSERT(!(m_size > m_capacity - 4));
|
||||
m_buffer[m_size] = char(value);
|
||||
m_size++;
|
||||
}
|
||||
|
||||
void putByte(int value)
|
||||
{
|
||||
if (m_size > m_capacity - 4)
|
||||
grow();
|
||||
putByteUnchecked(value);
|
||||
}
|
||||
|
||||
void putShortUnchecked(int value)
|
||||
{
|
||||
ASSERT(!(m_size > m_capacity - 4));
|
||||
*reinterpret_cast<short*>(&m_buffer[m_size]) = short(value);
|
||||
m_size += 2;
|
||||
}
|
||||
|
||||
void putShort(int value)
|
||||
{
|
||||
if (m_size > m_capacity - 4)
|
||||
grow();
|
||||
putShortUnchecked(value);
|
||||
}
|
||||
|
||||
void putIntUnchecked(int value)
|
||||
{
|
||||
ASSERT(!(m_size > m_capacity - 4));
|
||||
*reinterpret_cast<int*>(&m_buffer[m_size]) = value;
|
||||
m_size += 4;
|
||||
}
|
||||
|
||||
void putInt64Unchecked(int64_t value)
|
||||
{
|
||||
ASSERT(!(m_size > m_capacity - 8));
|
||||
*reinterpret_cast<int64_t*>(&m_buffer[m_size]) = value;
|
||||
m_size += 8;
|
||||
}
|
||||
|
||||
void putInt(int value)
|
||||
{
|
||||
if (m_size > m_capacity - 4)
|
||||
grow();
|
||||
putIntUnchecked(value);
|
||||
}
|
||||
|
||||
void* data() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void* executableCopy(ExecutablePool* allocator)
|
||||
{
|
||||
if (!m_size)
|
||||
return 0;
|
||||
|
||||
void* result = allocator->alloc(m_size);
|
||||
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
ExecutableAllocator::makeWritable(result, m_size);
|
||||
|
||||
return memcpy(result, m_buffer, m_size);
|
||||
}
|
||||
|
||||
unsigned char *buffer() const {
|
||||
return reinterpret_cast<unsigned char *>(m_buffer);
|
||||
}
|
||||
|
||||
protected:
|
||||
void append(const char* data, int size)
|
||||
{
|
||||
if (m_size > m_capacity - size)
|
||||
grow(size);
|
||||
|
||||
memcpy(m_buffer + m_size, data, size);
|
||||
m_size += size;
|
||||
}
|
||||
|
||||
void grow(int extraCapacity = 0)
|
||||
{
|
||||
m_capacity += m_capacity / 2 + extraCapacity;
|
||||
|
||||
if (m_buffer == m_inlineBuffer) {
|
||||
char* newBuffer = static_cast<char*>(malloc(m_capacity));
|
||||
m_buffer = static_cast<char*>(memcpy(newBuffer, m_buffer, m_size));
|
||||
} else
|
||||
m_buffer = static_cast<char*>(realloc(m_buffer, m_capacity));
|
||||
}
|
||||
|
||||
char m_inlineBuffer[inlineCapacity];
|
||||
char* m_buffer;
|
||||
int m_capacity;
|
||||
int m_size;
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // AssemblerBuffer_h
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright (C) 2009 University of Szeged
|
||||
* 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef AssemblerBufferWithConstantPool_h
|
||||
#define AssemblerBufferWithConstantPool_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
#include "AssemblerBuffer.h"
|
||||
#include "assembler/wtf/SegmentedVector.h"
|
||||
|
||||
#define ASSEMBLER_HAS_CONSTANT_POOL 1
|
||||
|
||||
namespace JSC {
|
||||
|
||||
/*
|
||||
On a constant pool 4 or 8 bytes data can be stored. The values can be
|
||||
constants or addresses. The addresses should be 32 or 64 bits. The constants
|
||||
should be double-precisions float or integer numbers which are hard to be
|
||||
encoded as few machine instructions.
|
||||
|
||||
TODO: The pool is desinged to handle both 32 and 64 bits values, but
|
||||
currently only the 4 bytes constants are implemented and tested.
|
||||
|
||||
The AssemblerBuffer can contain multiple constant pools. Each pool is inserted
|
||||
into the instruction stream - protected by a jump instruction from the
|
||||
execution flow.
|
||||
|
||||
The flush mechanism is called when no space remain to insert the next instruction
|
||||
into the pool. Three values are used to determine when the constant pool itself
|
||||
have to be inserted into the instruction stream (Assembler Buffer):
|
||||
|
||||
- maxPoolSize: size of the constant pool in bytes, this value cannot be
|
||||
larger than the maximum offset of a PC relative memory load
|
||||
|
||||
- barrierSize: size of jump instruction in bytes which protects the
|
||||
constant pool from execution
|
||||
|
||||
- maxInstructionSize: maximum length of a machine instruction in bytes
|
||||
|
||||
There are some callbacks which solve the target architecture specific
|
||||
address handling:
|
||||
|
||||
- TYPE patchConstantPoolLoad(TYPE load, int value):
|
||||
patch the 'load' instruction with the index of the constant in the
|
||||
constant pool and return the patched instruction.
|
||||
|
||||
- void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr):
|
||||
patch the a PC relative load instruction at 'loadAddr' address with the
|
||||
final relative offset. The offset can be computed with help of
|
||||
'constPoolAddr' (the address of the constant pool) and index of the
|
||||
constant (which is stored previously in the load instruction itself).
|
||||
|
||||
- TYPE placeConstantPoolBarrier(int size):
|
||||
return with a constant pool barrier instruction which jumps over the
|
||||
constant pool.
|
||||
|
||||
The 'put*WithConstant*' functions should be used to place a data into the
|
||||
constant pool.
|
||||
*/
|
||||
|
||||
template <int maxPoolSize, int barrierSize, int maxInstructionSize, class AssemblerType>
|
||||
class AssemblerBufferWithConstantPool: public AssemblerBuffer {
|
||||
typedef SegmentedVector<uint32_t, 512> LoadOffsets;
|
||||
public:
|
||||
enum {
|
||||
UniqueConst,
|
||||
ReusableConst,
|
||||
UnusedEntry
|
||||
};
|
||||
|
||||
AssemblerBufferWithConstantPool()
|
||||
: AssemblerBuffer()
|
||||
, m_numConsts(0)
|
||||
, m_maxDistance(maxPoolSize)
|
||||
, m_lastConstDelta(0)
|
||||
{
|
||||
m_pool = static_cast<uint32_t*>(malloc(maxPoolSize));
|
||||
m_mask = static_cast<char*>(malloc(maxPoolSize / sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
~AssemblerBufferWithConstantPool()
|
||||
{
|
||||
free(m_mask);
|
||||
free(m_pool);
|
||||
}
|
||||
|
||||
void ensureSpace(int space)
|
||||
{
|
||||
flushIfNoSpaceFor(space);
|
||||
AssemblerBuffer::ensureSpace(space);
|
||||
}
|
||||
|
||||
void ensureSpace(int insnSpace, int constSpace)
|
||||
{
|
||||
flushIfNoSpaceFor(insnSpace, constSpace);
|
||||
AssemblerBuffer::ensureSpace(insnSpace);
|
||||
}
|
||||
|
||||
bool isAligned(int alignment)
|
||||
{
|
||||
flushIfNoSpaceFor(alignment);
|
||||
return AssemblerBuffer::isAligned(alignment);
|
||||
}
|
||||
|
||||
void putByteUnchecked(int value)
|
||||
{
|
||||
AssemblerBuffer::putByteUnchecked(value);
|
||||
correctDeltas(1);
|
||||
}
|
||||
|
||||
void putByte(int value)
|
||||
{
|
||||
flushIfNoSpaceFor(1);
|
||||
AssemblerBuffer::putByte(value);
|
||||
correctDeltas(1);
|
||||
}
|
||||
|
||||
void putShortUnchecked(int value)
|
||||
{
|
||||
AssemblerBuffer::putShortUnchecked(value);
|
||||
correctDeltas(2);
|
||||
}
|
||||
|
||||
void putShort(int value)
|
||||
{
|
||||
flushIfNoSpaceFor(2);
|
||||
AssemblerBuffer::putShort(value);
|
||||
correctDeltas(2);
|
||||
}
|
||||
|
||||
void putIntUnchecked(int value)
|
||||
{
|
||||
AssemblerBuffer::putIntUnchecked(value);
|
||||
correctDeltas(4);
|
||||
}
|
||||
|
||||
void putInt(int value)
|
||||
{
|
||||
flushIfNoSpaceFor(4);
|
||||
AssemblerBuffer::putInt(value);
|
||||
correctDeltas(4);
|
||||
}
|
||||
|
||||
void putInt64Unchecked(int64_t value)
|
||||
{
|
||||
AssemblerBuffer::putInt64Unchecked(value);
|
||||
correctDeltas(8);
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
flushIfNoSpaceFor(maxInstructionSize, sizeof(uint64_t));
|
||||
return AssemblerBuffer::size();
|
||||
}
|
||||
|
||||
int uncheckedSize()
|
||||
{
|
||||
return AssemblerBuffer::size();
|
||||
}
|
||||
|
||||
void* executableCopy(ExecutablePool* allocator)
|
||||
{
|
||||
flushConstantPool(false);
|
||||
return AssemblerBuffer::executableCopy(allocator);
|
||||
}
|
||||
|
||||
void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false)
|
||||
{
|
||||
flushIfNoSpaceFor(4, 4);
|
||||
|
||||
m_loadOffsets.append(AssemblerBuffer::size());
|
||||
if (isReusable)
|
||||
for (int i = 0; i < m_numConsts; ++i) {
|
||||
if (m_mask[i] == ReusableConst && m_pool[i] == constant) {
|
||||
AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, i));
|
||||
correctDeltas(4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_pool[m_numConsts] = constant;
|
||||
m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst);
|
||||
|
||||
AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts));
|
||||
++m_numConsts;
|
||||
|
||||
correctDeltas(4, 4);
|
||||
}
|
||||
|
||||
// This flushing mechanism can be called after any unconditional jumps.
|
||||
void flushWithoutBarrier(bool isForced = false)
|
||||
{
|
||||
// Flush if constant pool is more than 60% full to avoid overuse of this function.
|
||||
if (isForced || 5 * m_numConsts > 3 * maxPoolSize / sizeof(uint32_t))
|
||||
flushConstantPool(false);
|
||||
}
|
||||
|
||||
uint32_t* poolAddress()
|
||||
{
|
||||
return m_pool;
|
||||
}
|
||||
|
||||
int sizeOfConstantPool()
|
||||
{
|
||||
return m_numConsts;
|
||||
}
|
||||
|
||||
private:
|
||||
void correctDeltas(int insnSize)
|
||||
{
|
||||
m_maxDistance -= insnSize;
|
||||
m_lastConstDelta -= insnSize;
|
||||
if (m_lastConstDelta < 0)
|
||||
m_lastConstDelta = 0;
|
||||
}
|
||||
|
||||
void correctDeltas(int insnSize, int constSize)
|
||||
{
|
||||
correctDeltas(insnSize);
|
||||
|
||||
m_maxDistance -= m_lastConstDelta;
|
||||
m_lastConstDelta = constSize;
|
||||
}
|
||||
|
||||
void flushConstantPool(bool useBarrier = true)
|
||||
{
|
||||
if (m_numConsts == 0)
|
||||
return;
|
||||
int alignPool = (AssemblerBuffer::size() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1);
|
||||
|
||||
if (alignPool)
|
||||
alignPool = sizeof(uint64_t) - alignPool;
|
||||
|
||||
// Callback to protect the constant pool from execution
|
||||
if (useBarrier)
|
||||
AssemblerBuffer::putInt(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool));
|
||||
|
||||
if (alignPool) {
|
||||
if (alignPool & 1)
|
||||
AssemblerBuffer::putByte(AssemblerType::padForAlign8);
|
||||
if (alignPool & 2)
|
||||
AssemblerBuffer::putShort(AssemblerType::padForAlign16);
|
||||
if (alignPool & 4)
|
||||
AssemblerBuffer::putInt(AssemblerType::padForAlign32);
|
||||
}
|
||||
|
||||
int constPoolOffset = AssemblerBuffer::size();
|
||||
append(reinterpret_cast<char*>(m_pool), m_numConsts * sizeof(uint32_t));
|
||||
|
||||
// Patch each PC relative load
|
||||
for (LoadOffsets::Iterator iter = m_loadOffsets.begin(); iter != m_loadOffsets.end(); ++iter) {
|
||||
void* loadAddr = reinterpret_cast<void*>(m_buffer + *iter);
|
||||
AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast<void*>(m_buffer + constPoolOffset));
|
||||
}
|
||||
|
||||
m_loadOffsets.clear();
|
||||
m_numConsts = 0;
|
||||
m_maxDistance = maxPoolSize;
|
||||
}
|
||||
|
||||
void flushIfNoSpaceFor(int nextInsnSize)
|
||||
{
|
||||
if (m_numConsts == 0)
|
||||
return;
|
||||
int lastConstDelta = m_lastConstDelta > nextInsnSize ? m_lastConstDelta - nextInsnSize : 0;
|
||||
if ((m_maxDistance < nextInsnSize + lastConstDelta + barrierSize + (int)sizeof(uint32_t)))
|
||||
flushConstantPool();
|
||||
}
|
||||
|
||||
void flushIfNoSpaceFor(int nextInsnSize, int nextConstSize)
|
||||
{
|
||||
if (m_numConsts == 0)
|
||||
return;
|
||||
if ((m_maxDistance < nextInsnSize + m_lastConstDelta + nextConstSize + barrierSize + (int)sizeof(uint32_t)) ||
|
||||
(m_numConsts * sizeof(uint32_t) + nextConstSize >= maxPoolSize))
|
||||
flushConstantPool();
|
||||
}
|
||||
|
||||
uint32_t* m_pool;
|
||||
char* m_mask;
|
||||
LoadOffsets m_loadOffsets;
|
||||
|
||||
int m_numConsts;
|
||||
int m_maxDistance;
|
||||
int m_lastConstDelta;
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // AssemblerBufferWithConstantPool_h
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CodeLocation_h
|
||||
#define CodeLocation_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
#include "assembler/assembler/MacroAssemblerCodeRef.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class CodeLocationInstruction;
|
||||
class CodeLocationLabel;
|
||||
class CodeLocationJump;
|
||||
class CodeLocationCall;
|
||||
class CodeLocationNearCall;
|
||||
class CodeLocationDataLabel32;
|
||||
class CodeLocationDataLabelPtr;
|
||||
|
||||
// The CodeLocation* types are all pretty much do-nothing wrappers around
|
||||
// CodePtr (or MacroAssemblerCodePtr, to give it its full name). These
|
||||
// classes only exist to provide type-safety when linking and patching code.
|
||||
//
|
||||
// The one new piece of functionallity introduced by these classes is the
|
||||
// ability to create (or put another way, to re-discover) another CodeLocation
|
||||
// at an offset from one you already know. When patching code to optimize it
|
||||
// we often want to patch a number of instructions that are short, fixed
|
||||
// offsets apart. To reduce memory overhead we will only retain a pointer to
|
||||
// one of the instructions, and we will use the *AtOffset methods provided by
|
||||
// CodeLocationCommon to find the other points in the code to modify.
|
||||
class CodeLocationCommon : public MacroAssemblerCodePtr {
|
||||
public:
|
||||
CodeLocationInstruction instructionAtOffset(int offset);
|
||||
CodeLocationLabel labelAtOffset(int offset);
|
||||
CodeLocationJump jumpAtOffset(int offset);
|
||||
CodeLocationCall callAtOffset(int offset);
|
||||
CodeLocationNearCall nearCallAtOffset(int offset);
|
||||
CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset);
|
||||
CodeLocationDataLabel32 dataLabel32AtOffset(int offset);
|
||||
|
||||
protected:
|
||||
CodeLocationCommon()
|
||||
{
|
||||
}
|
||||
|
||||
CodeLocationCommon(MacroAssemblerCodePtr location)
|
||||
: MacroAssemblerCodePtr(location)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CodeLocationInstruction : public CodeLocationCommon {
|
||||
public:
|
||||
CodeLocationInstruction() {}
|
||||
explicit CodeLocationInstruction(MacroAssemblerCodePtr location)
|
||||
: CodeLocationCommon(location) {}
|
||||
explicit CodeLocationInstruction(void* location)
|
||||
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
|
||||
};
|
||||
|
||||
class CodeLocationLabel : public CodeLocationCommon {
|
||||
public:
|
||||
CodeLocationLabel() {}
|
||||
explicit CodeLocationLabel(MacroAssemblerCodePtr location)
|
||||
: CodeLocationCommon(location) {}
|
||||
explicit CodeLocationLabel(void* location)
|
||||
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
|
||||
};
|
||||
|
||||
class CodeLocationJump : public CodeLocationCommon {
|
||||
public:
|
||||
CodeLocationJump() {}
|
||||
explicit CodeLocationJump(MacroAssemblerCodePtr location)
|
||||
: CodeLocationCommon(location) {}
|
||||
explicit CodeLocationJump(void* location)
|
||||
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
|
||||
};
|
||||
|
||||
class CodeLocationCall : public CodeLocationCommon {
|
||||
public:
|
||||
CodeLocationCall() {}
|
||||
explicit CodeLocationCall(MacroAssemblerCodePtr location)
|
||||
: CodeLocationCommon(location) {}
|
||||
explicit CodeLocationCall(void* location)
|
||||
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
|
||||
};
|
||||
|
||||
class CodeLocationNearCall : public CodeLocationCommon {
|
||||
public:
|
||||
CodeLocationNearCall() {}
|
||||
explicit CodeLocationNearCall(MacroAssemblerCodePtr location)
|
||||
: CodeLocationCommon(location) {}
|
||||
explicit CodeLocationNearCall(void* location)
|
||||
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
|
||||
};
|
||||
|
||||
class CodeLocationDataLabel32 : public CodeLocationCommon {
|
||||
public:
|
||||
CodeLocationDataLabel32() {}
|
||||
explicit CodeLocationDataLabel32(MacroAssemblerCodePtr location)
|
||||
: CodeLocationCommon(location) {}
|
||||
explicit CodeLocationDataLabel32(void* location)
|
||||
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
|
||||
};
|
||||
|
||||
class CodeLocationDataLabelPtr : public CodeLocationCommon {
|
||||
public:
|
||||
CodeLocationDataLabelPtr() {}
|
||||
explicit CodeLocationDataLabelPtr(MacroAssemblerCodePtr location)
|
||||
: CodeLocationCommon(location) {}
|
||||
explicit CodeLocationDataLabelPtr(void* location)
|
||||
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
|
||||
};
|
||||
|
||||
inline CodeLocationInstruction CodeLocationCommon::instructionAtOffset(int offset)
|
||||
{
|
||||
ASSERT_VALID_CODE_OFFSET(offset);
|
||||
return CodeLocationInstruction(reinterpret_cast<char*>(dataLocation()) + offset);
|
||||
}
|
||||
|
||||
inline CodeLocationLabel CodeLocationCommon::labelAtOffset(int offset)
|
||||
{
|
||||
ASSERT_VALID_CODE_OFFSET(offset);
|
||||
return CodeLocationLabel(reinterpret_cast<char*>(dataLocation()) + offset);
|
||||
}
|
||||
|
||||
inline CodeLocationJump CodeLocationCommon::jumpAtOffset(int offset)
|
||||
{
|
||||
ASSERT_VALID_CODE_OFFSET(offset);
|
||||
return CodeLocationJump(reinterpret_cast<char*>(dataLocation()) + offset);
|
||||
}
|
||||
|
||||
inline CodeLocationCall CodeLocationCommon::callAtOffset(int offset)
|
||||
{
|
||||
ASSERT_VALID_CODE_OFFSET(offset);
|
||||
return CodeLocationCall(reinterpret_cast<char*>(dataLocation()) + offset);
|
||||
}
|
||||
|
||||
inline CodeLocationNearCall CodeLocationCommon::nearCallAtOffset(int offset)
|
||||
{
|
||||
ASSERT_VALID_CODE_OFFSET(offset);
|
||||
return CodeLocationNearCall(reinterpret_cast<char*>(dataLocation()) + offset);
|
||||
}
|
||||
|
||||
inline CodeLocationDataLabelPtr CodeLocationCommon::dataLabelPtrAtOffset(int offset)
|
||||
{
|
||||
ASSERT_VALID_CODE_OFFSET(offset);
|
||||
return CodeLocationDataLabelPtr(reinterpret_cast<char*>(dataLocation()) + offset);
|
||||
}
|
||||
|
||||
inline CodeLocationDataLabel32 CodeLocationCommon::dataLabel32AtOffset(int offset)
|
||||
{
|
||||
ASSERT_VALID_CODE_OFFSET(offset);
|
||||
return CodeLocationDataLabel32(reinterpret_cast<char*>(dataLocation()) + offset);
|
||||
}
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // CodeLocation_h
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LinkBuffer_h
|
||||
#define LinkBuffer_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
#include <assembler/MacroAssembler.h>
|
||||
|
||||
namespace JSC {
|
||||
|
||||
// LinkBuffer:
|
||||
//
|
||||
// This class assists in linking code generated by the macro assembler, once code generation
|
||||
// has been completed, and the code has been copied to is final location in memory. At this
|
||||
// time pointers to labels within the code may be resolved, and relative offsets to external
|
||||
// addresses may be fixed.
|
||||
//
|
||||
// Specifically:
|
||||
// * Jump objects may be linked to external targets,
|
||||
// * The address of Jump objects may taken, such that it can later be relinked.
|
||||
// * The return address of a Call may be acquired.
|
||||
// * The address of a Label pointing into the code may be resolved.
|
||||
// * The value referenced by a DataLabel may be set.
|
||||
//
|
||||
class LinkBuffer {
|
||||
typedef MacroAssemblerCodeRef CodeRef;
|
||||
typedef MacroAssembler::Label Label;
|
||||
typedef MacroAssembler::Jump Jump;
|
||||
typedef MacroAssembler::JumpList JumpList;
|
||||
typedef MacroAssembler::Call Call;
|
||||
typedef MacroAssembler::DataLabel32 DataLabel32;
|
||||
typedef MacroAssembler::DataLabelPtr DataLabelPtr;
|
||||
|
||||
public:
|
||||
LinkBuffer(MacroAssembler* masm, ExecutablePool* executablePool)
|
||||
: m_executablePool(executablePool)
|
||||
//, m_code(masm->m_assembler.executableCopy(m_executablePool.get()))
|
||||
, m_code(masm->m_assembler.executableCopy(m_executablePool))
|
||||
, m_size(masm->m_assembler.size())
|
||||
#ifndef NDEBUG
|
||||
, m_completed(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
~LinkBuffer()
|
||||
{
|
||||
if (m_executablePool)
|
||||
m_executablePool->release();
|
||||
ASSERT(m_completed);
|
||||
}
|
||||
|
||||
// These methods are used to link or set values at code generation time.
|
||||
|
||||
void link(Call call, FunctionPtr function)
|
||||
{
|
||||
ASSERT(call.isFlagSet(Call::Linkable));
|
||||
MacroAssembler::linkCall(code(), call, function);
|
||||
}
|
||||
|
||||
void link(Jump jump, CodeLocationLabel label)
|
||||
{
|
||||
MacroAssembler::linkJump(code(), jump, label);
|
||||
}
|
||||
|
||||
void link(JumpList list, CodeLocationLabel label)
|
||||
{
|
||||
for (unsigned i = 0; i < list.m_jumps.length(); ++i)
|
||||
MacroAssembler::linkJump(code(), list.m_jumps[i], label);
|
||||
}
|
||||
|
||||
void patch(DataLabelPtr label, void* value)
|
||||
{
|
||||
MacroAssembler::linkPointer(code(), label.m_label, value);
|
||||
}
|
||||
|
||||
void patch(DataLabelPtr label, CodeLocationLabel value)
|
||||
{
|
||||
MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress());
|
||||
}
|
||||
|
||||
// These methods are used to obtain handles to allow the code to be relinked / repatched later.
|
||||
|
||||
CodeLocationCall locationOf(Call call)
|
||||
{
|
||||
ASSERT(call.isFlagSet(Call::Linkable));
|
||||
ASSERT(!call.isFlagSet(Call::Near));
|
||||
return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
|
||||
}
|
||||
|
||||
CodeLocationNearCall locationOfNearCall(Call call)
|
||||
{
|
||||
ASSERT(call.isFlagSet(Call::Linkable));
|
||||
ASSERT(call.isFlagSet(Call::Near));
|
||||
return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
|
||||
}
|
||||
|
||||
CodeLocationLabel locationOf(Label label)
|
||||
{
|
||||
return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label));
|
||||
}
|
||||
|
||||
CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
|
||||
{
|
||||
return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label));
|
||||
}
|
||||
|
||||
CodeLocationDataLabel32 locationOf(DataLabel32 label)
|
||||
{
|
||||
return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label));
|
||||
}
|
||||
|
||||
// This method obtains the return address of the call, given as an offset from
|
||||
// the start of the code.
|
||||
unsigned returnAddressOffset(Call call)
|
||||
{
|
||||
return MacroAssembler::getLinkerCallReturnOffset(call);
|
||||
}
|
||||
|
||||
// Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called
|
||||
// once to complete generation of the code. 'finalizeCode()' is suited to situations
|
||||
// where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is
|
||||
// suited to adding to an existing allocation.
|
||||
CodeRef finalizeCode()
|
||||
{
|
||||
performFinalization();
|
||||
|
||||
m_executablePool->addRef();
|
||||
return CodeRef(m_code, m_executablePool, m_size);
|
||||
}
|
||||
CodeLocationLabel finalizeCodeAddendum()
|
||||
{
|
||||
performFinalization();
|
||||
|
||||
return CodeLocationLabel(code());
|
||||
}
|
||||
|
||||
private:
|
||||
// Keep this private! - the underlying code should only be obtained externally via
|
||||
// finalizeCode() or finalizeCodeAddendum().
|
||||
void* code()
|
||||
{
|
||||
return m_code;
|
||||
}
|
||||
|
||||
void performFinalization()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
ASSERT(!m_completed);
|
||||
m_completed = true;
|
||||
#endif
|
||||
|
||||
ExecutableAllocator::makeExecutable(code(), m_size);
|
||||
ExecutableAllocator::cacheFlush(code(), m_size);
|
||||
}
|
||||
|
||||
ExecutablePool* m_executablePool;
|
||||
void* m_code;
|
||||
size_t m_size;
|
||||
#ifndef NDEBUG
|
||||
bool m_completed;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // LinkBuffer_h
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MacroAssembler_h
|
||||
#define MacroAssembler_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
#if WTF_CPU_ARM_THUMB2
|
||||
#include "MacroAssemblerARMv7.h"
|
||||
namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; }
|
||||
|
||||
#elif WTF_CPU_ARM_TRADITIONAL
|
||||
#include "MacroAssemblerARM.h"
|
||||
namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; }
|
||||
|
||||
#elif WTF_CPU_MIPS
|
||||
#include "MacroAssemblerMIPS.h"
|
||||
namespace JSC { typedef MacroAssemblerMIPS MacroAssemblerBase; }
|
||||
|
||||
#elif WTF_CPU_X86
|
||||
#include "MacroAssemblerX86.h"
|
||||
namespace JSC { typedef MacroAssemblerX86 MacroAssemblerBase; }
|
||||
|
||||
#elif WTF_CPU_X86_64
|
||||
#include "MacroAssemblerX86_64.h"
|
||||
namespace JSC { typedef MacroAssemblerX86_64 MacroAssemblerBase; }
|
||||
|
||||
#else
|
||||
#error "The MacroAssembler is not supported on this platform."
|
||||
#endif
|
||||
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class MacroAssembler : public MacroAssemblerBase {
|
||||
public:
|
||||
|
||||
using MacroAssemblerBase::pop;
|
||||
using MacroAssemblerBase::jump;
|
||||
using MacroAssemblerBase::branch32;
|
||||
using MacroAssemblerBase::branch16;
|
||||
#if WTF_CPU_X86_64
|
||||
using MacroAssemblerBase::branchPtr;
|
||||
using MacroAssemblerBase::branchTestPtr;
|
||||
#endif
|
||||
|
||||
|
||||
// Platform agnostic onvenience functions,
|
||||
// described in terms of other macro assembly methods.
|
||||
void pop()
|
||||
{
|
||||
addPtr(Imm32(sizeof(void*)), stackPointerRegister);
|
||||
}
|
||||
|
||||
void peek(RegisterID dest, int index = 0)
|
||||
{
|
||||
loadPtr(Address(stackPointerRegister, (index * sizeof(void*))), dest);
|
||||
}
|
||||
|
||||
void poke(RegisterID src, int index = 0)
|
||||
{
|
||||
storePtr(src, Address(stackPointerRegister, (index * sizeof(void*))));
|
||||
}
|
||||
|
||||
void poke(Imm32 value, int index = 0)
|
||||
{
|
||||
store32(value, Address(stackPointerRegister, (index * sizeof(void*))));
|
||||
}
|
||||
|
||||
void poke(ImmPtr imm, int index = 0)
|
||||
{
|
||||
storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*))));
|
||||
}
|
||||
|
||||
|
||||
// Backwards banches, these are currently all implemented using existing forwards branch mechanisms.
|
||||
void branchPtr(Condition cond, RegisterID op1, ImmPtr imm, Label target)
|
||||
{
|
||||
branchPtr(cond, op1, imm).linkTo(target, this);
|
||||
}
|
||||
|
||||
void branch32(Condition cond, RegisterID op1, RegisterID op2, Label target)
|
||||
{
|
||||
branch32(cond, op1, op2).linkTo(target, this);
|
||||
}
|
||||
|
||||
void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target)
|
||||
{
|
||||
branch32(cond, op1, imm).linkTo(target, this);
|
||||
}
|
||||
|
||||
void branch32(Condition cond, RegisterID left, Address right, Label target)
|
||||
{
|
||||
branch32(cond, left, right).linkTo(target, this);
|
||||
}
|
||||
|
||||
void branch16(Condition cond, BaseIndex left, RegisterID right, Label target)
|
||||
{
|
||||
branch16(cond, left, right).linkTo(target, this);
|
||||
}
|
||||
|
||||
void branchTestPtr(Condition cond, RegisterID reg, Label target)
|
||||
{
|
||||
branchTestPtr(cond, reg).linkTo(target, this);
|
||||
}
|
||||
|
||||
void jump(Label target)
|
||||
{
|
||||
jump().linkTo(target, this);
|
||||
}
|
||||
|
||||
|
||||
// Ptr methods
|
||||
// On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents.
|
||||
// FIXME: should this use a test for 32-bitness instead of this specific exception?
|
||||
#if !WTF_CPU_X86_64
|
||||
void addPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
add32(src, dest);
|
||||
}
|
||||
|
||||
void addPtr(Imm32 imm32, Address address)
|
||||
{
|
||||
add32(imm32, address);
|
||||
}
|
||||
|
||||
void addPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
add32(imm, srcDest);
|
||||
}
|
||||
|
||||
void addPtr(ImmPtr imm, RegisterID dest)
|
||||
{
|
||||
add32(Imm32(imm), dest);
|
||||
}
|
||||
|
||||
void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
|
||||
{
|
||||
add32(imm, src, dest);
|
||||
}
|
||||
|
||||
void andPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
and32(src, dest);
|
||||
}
|
||||
|
||||
void andPtr(Address address, RegisterID srcDest)
|
||||
{
|
||||
and32(address, srcDest);
|
||||
}
|
||||
|
||||
void andPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
and32(imm, srcDest);
|
||||
}
|
||||
|
||||
void andPtr(ImmPtr ptr, RegisterID srcDest)
|
||||
{
|
||||
and32(Imm32(ptr), srcDest);
|
||||
}
|
||||
|
||||
void notPtr(RegisterID srcDest)
|
||||
{
|
||||
not32(srcDest);
|
||||
}
|
||||
|
||||
void orPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
or32(src, dest);
|
||||
}
|
||||
|
||||
void orPtr(ImmPtr imm, RegisterID dest)
|
||||
{
|
||||
or32(Imm32(imm), dest);
|
||||
}
|
||||
|
||||
void orPtr(Imm32 imm, RegisterID dest)
|
||||
{
|
||||
or32(imm, dest);
|
||||
}
|
||||
|
||||
void orPtr(Address address, RegisterID srcDest)
|
||||
{
|
||||
or32(address, srcDest);
|
||||
}
|
||||
|
||||
void subPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
sub32(src, dest);
|
||||
}
|
||||
|
||||
void subPtr(Imm32 imm, RegisterID dest)
|
||||
{
|
||||
sub32(imm, dest);
|
||||
}
|
||||
|
||||
void subPtr(ImmPtr imm, RegisterID dest)
|
||||
{
|
||||
sub32(Imm32(imm), dest);
|
||||
}
|
||||
|
||||
void subPtr(ImmPtr imm, Address address)
|
||||
{
|
||||
sub32(Imm32(imm), address);
|
||||
}
|
||||
|
||||
void xorPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
xor32(src, dest);
|
||||
}
|
||||
|
||||
void xorPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
xor32(imm, srcDest);
|
||||
}
|
||||
|
||||
|
||||
void loadPtr(ImplicitAddress address, RegisterID dest)
|
||||
{
|
||||
load32(address, dest);
|
||||
}
|
||||
|
||||
void loadPtr(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
load32(address, dest);
|
||||
}
|
||||
|
||||
void loadPtr(void* address, RegisterID dest)
|
||||
{
|
||||
load32(address, dest);
|
||||
}
|
||||
|
||||
DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
|
||||
{
|
||||
return load32WithAddressOffsetPatch(address, dest);
|
||||
}
|
||||
|
||||
void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
|
||||
{
|
||||
set32(cond, left, right, dest);
|
||||
}
|
||||
|
||||
void storePtr(RegisterID src, ImplicitAddress address)
|
||||
{
|
||||
store32(src, address);
|
||||
}
|
||||
|
||||
void storePtr(RegisterID src, BaseIndex address)
|
||||
{
|
||||
store32(src, address);
|
||||
}
|
||||
|
||||
void storePtr(RegisterID src, void* address)
|
||||
{
|
||||
store32(src, address);
|
||||
}
|
||||
|
||||
void storePtr(ImmPtr imm, ImplicitAddress address)
|
||||
{
|
||||
store32(Imm32(imm), address);
|
||||
}
|
||||
|
||||
void storePtr(ImmPtr imm, BaseIndex address)
|
||||
{
|
||||
store32(Imm32(imm), address);
|
||||
}
|
||||
|
||||
void storePtr(ImmPtr imm, void* address)
|
||||
{
|
||||
store32(Imm32(imm), address);
|
||||
}
|
||||
|
||||
DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
|
||||
{
|
||||
return store32WithAddressOffsetPatch(src, address);
|
||||
}
|
||||
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, RegisterID right)
|
||||
{
|
||||
return branch32(cond, left, right);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, ImmPtr right)
|
||||
{
|
||||
return branch32(cond, left, Imm32(right));
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, Imm32 right)
|
||||
{
|
||||
return branch32(cond, left, right);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, Address right)
|
||||
{
|
||||
return branch32(cond, left, right);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, Address left, RegisterID right)
|
||||
{
|
||||
return branch32(cond, left, right);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
|
||||
{
|
||||
return branch32(cond, left, right);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, Address left, ImmPtr right)
|
||||
{
|
||||
return branch32(cond, left, Imm32(right));
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right)
|
||||
{
|
||||
return branch32(cond, left, Imm32(right));
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
|
||||
{
|
||||
return branchTest32(cond, reg, mask);
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
return branchTest32(cond, reg, mask);
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
return branchTest32(cond, address, mask);
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
return branchTest32(cond, address, mask);
|
||||
}
|
||||
|
||||
|
||||
Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest)
|
||||
{
|
||||
return branchAdd32(cond, src, dest);
|
||||
}
|
||||
|
||||
Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest)
|
||||
{
|
||||
return branchSub32(cond, imm, dest);
|
||||
}
|
||||
|
||||
using MacroAssemblerBase::branchTest8;
|
||||
Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask);
|
||||
}
|
||||
|
||||
void rshiftPtr(Imm32 imm, RegisterID dest)
|
||||
{
|
||||
rshift32(imm, dest);
|
||||
}
|
||||
|
||||
void lshiftPtr(Imm32 imm, RegisterID dest)
|
||||
{
|
||||
lshift32(imm, dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // MacroAssembler_h
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (C) 2009 University of Szeged
|
||||
* 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL
|
||||
|
||||
#include "MacroAssemblerARM.h"
|
||||
|
||||
#if WTF_PLATFORM_LINUX
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <elf.h>
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
|
||||
namespace JSC {
|
||||
|
||||
static bool isVFPPresent()
|
||||
{
|
||||
#if WTF_PLATFORM_LINUX
|
||||
int fd = open("/proc/self/auxv", O_RDONLY);
|
||||
if (fd > 0) {
|
||||
Elf32_auxv_t aux;
|
||||
while (read(fd, &aux, sizeof(Elf32_auxv_t))) {
|
||||
if (aux.a_type == AT_HWCAP) {
|
||||
close(fd);
|
||||
return aux.a_un.a_val & HWCAP_VFP;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent();
|
||||
|
||||
#if WTF_CPU_ARMV5_OR_LOWER
|
||||
/* On ARMv5 and below, natural alignment is required. */
|
||||
void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
ARMWord op2;
|
||||
|
||||
ASSERT(address.scale >= 0 && address.scale <= 3);
|
||||
op2 = m_assembler.lsl(address.index, static_cast<int>(address.scale));
|
||||
|
||||
if (address.offset >= 0 && address.offset + 0x2 <= 0xff) {
|
||||
m_assembler.add_r(ARMRegisters::S0, address.base, op2);
|
||||
m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset));
|
||||
m_assembler.ldrh_u(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset + 0x2));
|
||||
} else if (address.offset < 0 && address.offset >= -0xff) {
|
||||
m_assembler.add_r(ARMRegisters::S0, address.base, op2);
|
||||
m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset));
|
||||
m_assembler.ldrh_d(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset - 0x2));
|
||||
} else {
|
||||
m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset);
|
||||
m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, op2);
|
||||
m_assembler.ldrh_r(dest, address.base, ARMRegisters::S0);
|
||||
m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::OP2_IMM | 0x2);
|
||||
m_assembler.ldrh_r(ARMRegisters::S0, address.base, ARMRegisters::S0);
|
||||
}
|
||||
m_assembler.orr_r(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MacroAssemblerCodeRef_h
|
||||
#define MacroAssemblerCodeRef_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
// 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 WTF_CPU_ARM_THUMB2
|
||||
// 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.
|
||||
#define ASSERT_VALID_CODE_POINTER(ptr) \
|
||||
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_POINTER(ptr) \
|
||||
ASSERT(ptr)
|
||||
#define ASSERT_VALID_CODE_OFFSET(offset) // Anything goes!
|
||||
#endif
|
||||
|
||||
namespace JSC {
|
||||
|
||||
// FunctionPtr:
|
||||
//
|
||||
// FunctionPtr should be used to wrap pointers to C/C++ functions in JSC
|
||||
// (particularly, the stub functions).
|
||||
class FunctionPtr {
|
||||
public:
|
||||
FunctionPtr()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename FunctionType>
|
||||
explicit FunctionPtr(FunctionType* value)
|
||||
#if WTF_COMPILER_RVCT
|
||||
// RVTC compiler needs C-style cast as it fails with the following error
|
||||
// Error: #694: reinterpret_cast cannot cast away const or other type qualifiers
|
||||
: m_value((void*)(value))
|
||||
#else
|
||||
: m_value(reinterpret_cast<void*>(value))
|
||||
#endif
|
||||
{
|
||||
ASSERT_VALID_CODE_POINTER(m_value);
|
||||
}
|
||||
|
||||
void* value() const { return m_value; }
|
||||
void* executableAddress() const { return m_value; }
|
||||
|
||||
|
||||
private:
|
||||
void* m_value;
|
||||
};
|
||||
|
||||
// ReturnAddressPtr:
|
||||
//
|
||||
// ReturnAddressPtr should be used to wrap return addresses generated by processor
|
||||
// 'call' instructions exectued in JIT code. We use return addresses to look up
|
||||
// exception and optimization information, and to repatch the call instruction
|
||||
// that is the source of the return address.
|
||||
class ReturnAddressPtr {
|
||||
public:
|
||||
ReturnAddressPtr()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit ReturnAddressPtr(void* value)
|
||||
: m_value(value)
|
||||
{
|
||||
ASSERT_VALID_CODE_POINTER(m_value);
|
||||
}
|
||||
|
||||
explicit ReturnAddressPtr(FunctionPtr function)
|
||||
: m_value(function.value())
|
||||
{
|
||||
ASSERT_VALID_CODE_POINTER(m_value);
|
||||
}
|
||||
|
||||
void* value() const { return m_value; }
|
||||
|
||||
private:
|
||||
void* m_value;
|
||||
};
|
||||
|
||||
// MacroAssemblerCodePtr:
|
||||
//
|
||||
// MacroAssemblerCodePtr should be used to wrap pointers to JIT generated code.
|
||||
class MacroAssemblerCodePtr {
|
||||
public:
|
||||
MacroAssemblerCodePtr()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit MacroAssemblerCodePtr(void* value)
|
||||
#if WTF_CPU_ARM_THUMB2
|
||||
// Decorate the pointer as a thumb code pointer.
|
||||
: m_value(reinterpret_cast<char*>(value) + 1)
|
||||
#else
|
||||
: m_value(value)
|
||||
#endif
|
||||
{
|
||||
ASSERT_VALID_CODE_POINTER(m_value);
|
||||
}
|
||||
|
||||
explicit MacroAssemblerCodePtr(ReturnAddressPtr ra)
|
||||
: m_value(ra.value())
|
||||
{
|
||||
ASSERT_VALID_CODE_POINTER(m_value);
|
||||
}
|
||||
|
||||
void* executableAddress() const { return m_value; }
|
||||
#if WTF_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!()
|
||||
{
|
||||
return !m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
void* m_value;
|
||||
};
|
||||
|
||||
// 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 {
|
||||
ExecutablePool* m_executablePool;
|
||||
public:
|
||||
MacroAssemblerCodeRef()
|
||||
: m_executablePool(0)
|
||||
, m_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
MacroAssemblerCodeRef(void* code, ExecutablePool* executablePool, size_t size)
|
||||
: m_executablePool(executablePool)
|
||||
, m_code(code)
|
||||
, m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
~MacroAssemblerCodeRef()
|
||||
{
|
||||
if (m_executablePool)
|
||||
m_executablePool->release();
|
||||
}
|
||||
|
||||
MacroAssemblerCodeRef(const MacroAssemblerCodeRef &other)
|
||||
: m_executablePool(other.m_executablePool)
|
||||
, m_code(other.m_code)
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
if (m_executablePool)
|
||||
m_executablePool->addRef();
|
||||
}
|
||||
|
||||
void operator=(const MacroAssemblerCodeRef &other)
|
||||
{
|
||||
m_executablePool = other.m_executablePool;
|
||||
if (m_executablePool)
|
||||
m_executablePool->addRef();
|
||||
m_code = other.m_code;
|
||||
m_size = other.m_size;
|
||||
}
|
||||
|
||||
MacroAssemblerCodePtr m_code;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // MacroAssemblerCodeRef_h
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MacroAssemblerX86_h
|
||||
#define MacroAssemblerX86_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER && WTF_CPU_X86
|
||||
|
||||
#include "MacroAssemblerX86Common.h"
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class MacroAssemblerX86 : public MacroAssemblerX86Common {
|
||||
public:
|
||||
MacroAssemblerX86()
|
||||
: m_isSSE2Present(isSSE2Present())
|
||||
{
|
||||
}
|
||||
|
||||
static const Scale ScalePtr = TimesFour;
|
||||
static const unsigned int TotalRegisters = 8;
|
||||
|
||||
using MacroAssemblerX86Common::add32;
|
||||
using MacroAssemblerX86Common::and32;
|
||||
using MacroAssemblerX86Common::sub32;
|
||||
using MacroAssemblerX86Common::or32;
|
||||
using MacroAssemblerX86Common::load32;
|
||||
using MacroAssemblerX86Common::store32;
|
||||
using MacroAssemblerX86Common::branch32;
|
||||
using MacroAssemblerX86Common::call;
|
||||
using MacroAssemblerX86Common::loadDouble;
|
||||
using MacroAssemblerX86Common::convertInt32ToDouble;
|
||||
|
||||
void add32(Imm32 imm, RegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.leal_mr(imm.m_value, src, dest);
|
||||
}
|
||||
|
||||
void lea(Address address, RegisterID dest)
|
||||
{
|
||||
m_assembler.leal_mr(address.offset, address.base, dest);
|
||||
}
|
||||
|
||||
void lea(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
m_assembler.leal_mr(address.offset, address.base, address.index, address.scale, dest);
|
||||
}
|
||||
|
||||
void add32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
m_assembler.addl_im(imm.m_value, address.m_ptr);
|
||||
}
|
||||
|
||||
void addWithCarry32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
m_assembler.adcl_im(imm.m_value, address.m_ptr);
|
||||
}
|
||||
|
||||
void and32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
m_assembler.andl_im(imm.m_value, address.m_ptr);
|
||||
}
|
||||
|
||||
void or32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
m_assembler.orl_im(imm.m_value, address.m_ptr);
|
||||
}
|
||||
|
||||
void sub32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
m_assembler.subl_im(imm.m_value, address.m_ptr);
|
||||
}
|
||||
|
||||
void load32(void* address, RegisterID dest)
|
||||
{
|
||||
m_assembler.movl_mr(address, dest);
|
||||
}
|
||||
|
||||
void loadDouble(const void* address, FPRegisterID dest)
|
||||
{
|
||||
ASSERT(isSSE2Present());
|
||||
m_assembler.movsd_mr(address, dest);
|
||||
}
|
||||
|
||||
void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
|
||||
{
|
||||
m_assembler.cvtsi2sd_mr(src.m_ptr, dest);
|
||||
}
|
||||
|
||||
void store32(Imm32 imm, void* address)
|
||||
{
|
||||
m_assembler.movl_i32m(imm.m_value, address);
|
||||
}
|
||||
|
||||
void store32(RegisterID src, void* address)
|
||||
{
|
||||
m_assembler.movl_rm(src, address);
|
||||
}
|
||||
|
||||
Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
|
||||
{
|
||||
m_assembler.cmpl_rm(right, left.m_ptr);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
|
||||
{
|
||||
m_assembler.cmpl_im(right.m_value, left.m_ptr);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Call call()
|
||||
{
|
||||
return Call(m_assembler.call(), Call::Linkable);
|
||||
}
|
||||
|
||||
Call tailRecursiveCall()
|
||||
{
|
||||
return Call::fromTailJump(jump());
|
||||
}
|
||||
|
||||
Call makeTailRecursiveCall(Jump oldJump)
|
||||
{
|
||||
return Call::fromTailJump(oldJump);
|
||||
}
|
||||
|
||||
|
||||
DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
|
||||
{
|
||||
m_assembler.movl_i32r(initialValue.asIntptr(), dest);
|
||||
return DataLabelPtr(this);
|
||||
}
|
||||
|
||||
Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
|
||||
{
|
||||
m_assembler.cmpl_ir_force32(initialRightValue.asIntptr(), left);
|
||||
dataLabel = DataLabelPtr(this);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
|
||||
{
|
||||
m_assembler.cmpl_im_force32(initialRightValue.asIntptr(), left.offset, left.base);
|
||||
dataLabel = DataLabelPtr(this);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
|
||||
{
|
||||
m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
|
||||
return DataLabelPtr(this);
|
||||
}
|
||||
|
||||
Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
|
||||
{
|
||||
Label label(this);
|
||||
load32(address, dest);
|
||||
return label;
|
||||
}
|
||||
|
||||
bool supportsFloatingPoint() const { return m_isSSE2Present; }
|
||||
// See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
|
||||
bool supportsFloatingPointTruncate() const { return m_isSSE2Present; }
|
||||
bool supportsFloatingPointSqrt() const { return m_isSSE2Present; }
|
||||
|
||||
private:
|
||||
const bool m_isSSE2Present;
|
||||
|
||||
friend class LinkBuffer;
|
||||
friend class RepatchBuffer;
|
||||
|
||||
static void linkCall(void* code, Call call, FunctionPtr function)
|
||||
{
|
||||
X86Assembler::linkCall(code, call.m_jmp, function.value());
|
||||
}
|
||||
|
||||
static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
|
||||
{
|
||||
X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
|
||||
}
|
||||
|
||||
static void repatchCall(CodeLocationCall call, FunctionPtr destination)
|
||||
{
|
||||
X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // MacroAssemblerX86_h
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MacroAssemblerX86_64_h
|
||||
#define MacroAssemblerX86_64_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER && WTF_CPU_X86_64
|
||||
|
||||
#include "MacroAssemblerX86Common.h"
|
||||
|
||||
#define REPTACH_OFFSET_CALL_R11 3
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
|
||||
protected:
|
||||
static const X86Registers::RegisterID scratchRegister = X86Registers::r11;
|
||||
static const intptr_t MinInt32 = 0xFFFFFFFF80000000;
|
||||
static const intptr_t MaxInt32 = 0x000000007FFFFFFF;
|
||||
|
||||
public:
|
||||
static const Scale ScalePtr = TimesEight;
|
||||
static const unsigned int TotalRegisters = 16;
|
||||
|
||||
using MacroAssemblerX86Common::add32;
|
||||
using MacroAssemblerX86Common::and32;
|
||||
using MacroAssemblerX86Common::or32;
|
||||
using MacroAssemblerX86Common::sub32;
|
||||
using MacroAssemblerX86Common::load32;
|
||||
using MacroAssemblerX86Common::store32;
|
||||
using MacroAssemblerX86Common::call;
|
||||
using MacroAssemblerX86Common::loadDouble;
|
||||
using MacroAssemblerX86Common::convertInt32ToDouble;
|
||||
|
||||
void add32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
move(ImmPtr(address.m_ptr), scratchRegister);
|
||||
add32(imm, Address(scratchRegister));
|
||||
}
|
||||
|
||||
void and32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
move(ImmPtr(address.m_ptr), scratchRegister);
|
||||
and32(imm, Address(scratchRegister));
|
||||
}
|
||||
|
||||
void or32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
move(ImmPtr(address.m_ptr), scratchRegister);
|
||||
or32(imm, Address(scratchRegister));
|
||||
}
|
||||
|
||||
void sub32(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
move(ImmPtr(address.m_ptr), scratchRegister);
|
||||
sub32(imm, Address(scratchRegister));
|
||||
}
|
||||
|
||||
void load32(void* address, RegisterID dest)
|
||||
{
|
||||
if (dest == X86Registers::eax)
|
||||
m_assembler.movl_mEAX(address);
|
||||
else {
|
||||
move(X86Registers::eax, dest);
|
||||
m_assembler.movl_mEAX(address);
|
||||
swap(X86Registers::eax, dest);
|
||||
}
|
||||
}
|
||||
|
||||
void loadDouble(const void* address, FPRegisterID dest)
|
||||
{
|
||||
move(ImmPtr(address), scratchRegister);
|
||||
loadDouble(scratchRegister, dest);
|
||||
}
|
||||
|
||||
void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
|
||||
{
|
||||
move(Imm32(*static_cast<int32_t*>(src.m_ptr)), scratchRegister);
|
||||
m_assembler.cvtsi2sd_rr(scratchRegister, dest);
|
||||
}
|
||||
|
||||
void store32(Imm32 imm, void* address)
|
||||
{
|
||||
move(X86Registers::eax, scratchRegister);
|
||||
move(imm, X86Registers::eax);
|
||||
m_assembler.movl_EAXm(address);
|
||||
move(scratchRegister, X86Registers::eax);
|
||||
}
|
||||
|
||||
Call call()
|
||||
{
|
||||
DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
|
||||
Call result = Call(m_assembler.call(scratchRegister), Call::Linkable);
|
||||
ASSERT(differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11);
|
||||
return result;
|
||||
}
|
||||
|
||||
Call tailRecursiveCall()
|
||||
{
|
||||
DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
|
||||
Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
|
||||
ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
|
||||
return Call::fromTailJump(newJump);
|
||||
}
|
||||
|
||||
Call makeTailRecursiveCall(Jump oldJump)
|
||||
{
|
||||
oldJump.link(this);
|
||||
DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister);
|
||||
Jump newJump = Jump(m_assembler.jmp_r(scratchRegister));
|
||||
ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11);
|
||||
return Call::fromTailJump(newJump);
|
||||
}
|
||||
|
||||
|
||||
void addPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.addq_rr(src, dest);
|
||||
}
|
||||
|
||||
void lea(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
m_assembler.leaq_mr(address.offset, address.base, address.index, address.scale, dest);
|
||||
}
|
||||
|
||||
void lea(Address address, RegisterID dest)
|
||||
{
|
||||
m_assembler.leaq_mr(address.offset, address.base, dest);
|
||||
}
|
||||
|
||||
void addPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
m_assembler.addq_ir(imm.m_value, srcDest);
|
||||
}
|
||||
|
||||
void addPtr(ImmPtr imm, RegisterID dest)
|
||||
{
|
||||
move(imm, scratchRegister);
|
||||
m_assembler.addq_rr(scratchRegister, dest);
|
||||
}
|
||||
|
||||
void addPtr(Imm32 imm, RegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.leaq_mr(imm.m_value, src, dest);
|
||||
}
|
||||
|
||||
void addPtr(Imm32 imm, Address address)
|
||||
{
|
||||
m_assembler.addq_im(imm.m_value, address.offset, address.base);
|
||||
}
|
||||
|
||||
void addPtr(Imm32 imm, AbsoluteAddress address)
|
||||
{
|
||||
move(ImmPtr(address.m_ptr), scratchRegister);
|
||||
addPtr(imm, Address(scratchRegister));
|
||||
}
|
||||
|
||||
void andPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.andq_rr(src, dest);
|
||||
}
|
||||
|
||||
void andPtr(Address src, RegisterID dest)
|
||||
{
|
||||
m_assembler.andq_mr(src.offset, src.base, dest);
|
||||
}
|
||||
|
||||
void andPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
m_assembler.andq_ir(imm.m_value, srcDest);
|
||||
}
|
||||
|
||||
void andPtr(ImmPtr imm, RegisterID srcDest)
|
||||
{
|
||||
intptr_t value = intptr_t(imm.m_value);
|
||||
|
||||
// 32-bit immediates in 64-bit ALU ops are sign-extended.
|
||||
if (value >= MinInt32 && value <= MaxInt32) {
|
||||
andPtr(Imm32(int(value)), srcDest);
|
||||
} else {
|
||||
move(imm, scratchRegister);
|
||||
m_assembler.andq_rr(scratchRegister, srcDest);
|
||||
}
|
||||
}
|
||||
|
||||
void notPtr(RegisterID srcDest)
|
||||
{
|
||||
m_assembler.notq_r(srcDest);
|
||||
}
|
||||
|
||||
void orPtr(Address src, RegisterID dest)
|
||||
{
|
||||
m_assembler.orq_mr(src.offset, src.base, dest);
|
||||
}
|
||||
|
||||
void orPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.orq_rr(src, dest);
|
||||
}
|
||||
|
||||
void orPtr(ImmPtr imm, RegisterID dest)
|
||||
{
|
||||
move(imm, scratchRegister);
|
||||
m_assembler.orq_rr(scratchRegister, dest);
|
||||
}
|
||||
|
||||
void orPtr(Imm32 imm, RegisterID dest)
|
||||
{
|
||||
m_assembler.orq_ir(imm.m_value, dest);
|
||||
}
|
||||
|
||||
void subPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.subq_rr(src, dest);
|
||||
}
|
||||
|
||||
void subPtr(Imm32 imm, RegisterID dest)
|
||||
{
|
||||
m_assembler.subq_ir(imm.m_value, dest);
|
||||
}
|
||||
|
||||
void subPtr(ImmPtr imm, RegisterID dest)
|
||||
{
|
||||
move(imm, scratchRegister);
|
||||
m_assembler.subq_rr(scratchRegister, dest);
|
||||
}
|
||||
|
||||
void xorPtr(RegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.xorq_rr(src, dest);
|
||||
}
|
||||
|
||||
void xorPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
m_assembler.xorq_ir(imm.m_value, srcDest);
|
||||
}
|
||||
|
||||
void rshiftPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
m_assembler.sarq_i8r(imm.m_value, srcDest);
|
||||
}
|
||||
|
||||
void lshiftPtr(Imm32 imm, RegisterID srcDest)
|
||||
{
|
||||
m_assembler.shlq_i8r(imm.m_value, srcDest);
|
||||
}
|
||||
|
||||
void loadPtr(ImplicitAddress address, RegisterID dest)
|
||||
{
|
||||
m_assembler.movq_mr(address.offset, address.base, dest);
|
||||
}
|
||||
|
||||
void loadPtr(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
|
||||
}
|
||||
|
||||
void loadPtr(void* address, RegisterID dest)
|
||||
{
|
||||
if (dest == X86Registers::eax)
|
||||
m_assembler.movq_mEAX(address);
|
||||
else {
|
||||
move(X86Registers::eax, dest);
|
||||
m_assembler.movq_mEAX(address);
|
||||
swap(X86Registers::eax, dest);
|
||||
}
|
||||
}
|
||||
|
||||
DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
|
||||
{
|
||||
m_assembler.movq_mr_disp32(address.offset, address.base, dest);
|
||||
return DataLabel32(this);
|
||||
}
|
||||
|
||||
void storePtr(RegisterID src, ImplicitAddress address)
|
||||
{
|
||||
m_assembler.movq_rm(src, address.offset, address.base);
|
||||
}
|
||||
|
||||
void storePtr(ImmPtr imm, BaseIndex address)
|
||||
{
|
||||
intptr_t value = intptr_t(imm.m_value);
|
||||
|
||||
// 32-bit immediates in 64-bit stores will be zero-extended, so check
|
||||
// if the value can fit in such a store.
|
||||
if (value >= 0 && value < intptr_t(0x7FFFFFFF)) {
|
||||
m_assembler.movq_i32m(int32_t(value), address.offset, address.base, address.index,
|
||||
address.scale);
|
||||
} else {
|
||||
move(imm, scratchRegister);
|
||||
storePtr(scratchRegister, address);
|
||||
}
|
||||
}
|
||||
|
||||
void storePtr(RegisterID src, BaseIndex address)
|
||||
{
|
||||
m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale);
|
||||
}
|
||||
|
||||
void storePtr(RegisterID src, void* address)
|
||||
{
|
||||
if (src == X86Registers::eax)
|
||||
m_assembler.movq_EAXm(address);
|
||||
else {
|
||||
swap(X86Registers::eax, src);
|
||||
m_assembler.movq_EAXm(address);
|
||||
swap(X86Registers::eax, src);
|
||||
}
|
||||
}
|
||||
|
||||
void storePtr(ImmPtr imm, ImplicitAddress address)
|
||||
{
|
||||
intptr_t value = intptr_t(imm.m_value);
|
||||
|
||||
// 32-bit immediates in 64-bit stores will be zero-extended, so check
|
||||
// if the value can fit in such a store.
|
||||
if (value >= 0 && value < intptr_t(0x7FFFFFFF)) {
|
||||
m_assembler.movq_i32m(int32_t(value), address.offset, address.base);
|
||||
} else {
|
||||
move(imm, scratchRegister);
|
||||
storePtr(scratchRegister, address);
|
||||
}
|
||||
}
|
||||
|
||||
DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
|
||||
{
|
||||
m_assembler.movq_rm_disp32(src, address.offset, address.base);
|
||||
return DataLabel32(this);
|
||||
}
|
||||
|
||||
void movePtrToDouble(RegisterID src, FPRegisterID dest)
|
||||
{
|
||||
m_assembler.movq_rr(src, dest);
|
||||
}
|
||||
|
||||
void moveDoubleToPtr(FPRegisterID src, RegisterID dest)
|
||||
{
|
||||
m_assembler.movq_rr(src, dest);
|
||||
}
|
||||
|
||||
void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
|
||||
{
|
||||
if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
|
||||
m_assembler.testq_rr(left, left);
|
||||
else
|
||||
m_assembler.cmpq_ir(right.m_value, left);
|
||||
m_assembler.setCC_r(x86Condition(cond), dest);
|
||||
m_assembler.movzbl_rr(dest, dest);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, RegisterID right)
|
||||
{
|
||||
m_assembler.cmpq_rr(right, left);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, Imm32 right)
|
||||
{
|
||||
m_assembler.cmpq_ir(right.m_value, left);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, ImmPtr right)
|
||||
{
|
||||
move(right, scratchRegister);
|
||||
return branchPtr(cond, left, scratchRegister);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, RegisterID left, Address right)
|
||||
{
|
||||
m_assembler.cmpq_mr(right.offset, right.base, left);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
|
||||
{
|
||||
move(ImmPtr(left.m_ptr), scratchRegister);
|
||||
return branchPtr(cond, Address(scratchRegister), right);
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, Address left, RegisterID right)
|
||||
{
|
||||
m_assembler.cmpq_rm(right, left.offset, left.base);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchPtr(Condition cond, Address left, ImmPtr right)
|
||||
{
|
||||
move(right, scratchRegister);
|
||||
return branchPtr(cond, left, scratchRegister);
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
|
||||
{
|
||||
m_assembler.testq_rr(reg, mask);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
// if we are only interested in the low seven bits, this can be tested with a testb
|
||||
if (mask.m_value == -1)
|
||||
m_assembler.testq_rr(reg, reg);
|
||||
else if ((mask.m_value & ~0x7f) == 0)
|
||||
m_assembler.testb_i8r(mask.m_value, reg);
|
||||
else
|
||||
m_assembler.testq_i32r(mask.m_value, reg);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
if (mask.m_value == -1)
|
||||
m_assembler.cmpq_im(0, address.offset, address.base);
|
||||
else
|
||||
m_assembler.testq_i32m(mask.m_value, address.offset, address.base);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
if (mask.m_value == -1)
|
||||
m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale);
|
||||
else
|
||||
m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
|
||||
Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest)
|
||||
{
|
||||
ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
|
||||
addPtr(src, dest);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest)
|
||||
{
|
||||
ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero));
|
||||
subPtr(imm, dest);
|
||||
return Jump(m_assembler.jCC(x86Condition(cond)));
|
||||
}
|
||||
|
||||
DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
|
||||
{
|
||||
m_assembler.movq_i64r(initialValue.asIntptr(), dest);
|
||||
return DataLabelPtr(this);
|
||||
}
|
||||
|
||||
Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
|
||||
{
|
||||
dataLabel = moveWithPatch(initialRightValue, scratchRegister);
|
||||
return branchPtr(cond, left, scratchRegister);
|
||||
}
|
||||
|
||||
Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
|
||||
{
|
||||
dataLabel = moveWithPatch(initialRightValue, scratchRegister);
|
||||
return branchPtr(cond, left, scratchRegister);
|
||||
}
|
||||
|
||||
DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
|
||||
{
|
||||
DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
|
||||
storePtr(scratchRegister, address);
|
||||
return label;
|
||||
}
|
||||
|
||||
using MacroAssemblerX86Common::branchTest8;
|
||||
Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1))
|
||||
{
|
||||
ImmPtr addr(reinterpret_cast<void*>(address.offset));
|
||||
MacroAssemblerX86Common::move(addr, scratchRegister);
|
||||
return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask);
|
||||
}
|
||||
|
||||
Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
|
||||
{
|
||||
Label label(this);
|
||||
loadPtr(address, dest);
|
||||
return label;
|
||||
}
|
||||
|
||||
bool supportsFloatingPoint() const { return true; }
|
||||
// See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate()
|
||||
bool supportsFloatingPointTruncate() const { return true; }
|
||||
bool supportsFloatingPointSqrt() const { return true; }
|
||||
|
||||
private:
|
||||
friend class LinkBuffer;
|
||||
friend class RepatchBuffer;
|
||||
|
||||
static void linkCall(void* code, Call call, FunctionPtr function)
|
||||
{
|
||||
if (!call.isFlagSet(Call::Near))
|
||||
X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value());
|
||||
else
|
||||
X86Assembler::linkCall(code, call.m_jmp, function.value());
|
||||
}
|
||||
|
||||
static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
|
||||
{
|
||||
X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
|
||||
}
|
||||
|
||||
static void repatchCall(CodeLocationCall call, FunctionPtr destination)
|
||||
{
|
||||
X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // MacroAssemblerX86_64_h
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RepatchBuffer_h
|
||||
#define RepatchBuffer_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
#include <assembler/MacroAssembler.h>
|
||||
#include <moco/MocoStubs.h> //MOCO
|
||||
|
||||
namespace JSC {
|
||||
|
||||
// RepatchBuffer:
|
||||
//
|
||||
// This class is used to modify code after code generation has been completed,
|
||||
// and after the code has potentially already been executed. This mechanism is
|
||||
// used to apply optimizations to the code.
|
||||
//
|
||||
class RepatchBuffer {
|
||||
typedef MacroAssemblerCodePtr CodePtr;
|
||||
|
||||
public:
|
||||
RepatchBuffer(void *start, size_t size, bool mprot = true)
|
||||
: m_start(start), m_size(size), mprot(mprot)
|
||||
{
|
||||
ExecutableAllocator::makeWritable(m_start, m_size);
|
||||
}
|
||||
|
||||
RepatchBuffer(CodeBlock* codeBlock)
|
||||
{
|
||||
JITCode& code = codeBlock->getJITCode();
|
||||
m_start = code.start();
|
||||
m_size = code.size();
|
||||
mprot = true;
|
||||
|
||||
if (mprot)
|
||||
ExecutableAllocator::makeWritable(m_start, m_size);
|
||||
}
|
||||
|
||||
~RepatchBuffer()
|
||||
{
|
||||
if (mprot)
|
||||
ExecutableAllocator::makeExecutable(m_start, m_size);
|
||||
}
|
||||
|
||||
void relink(CodeLocationJump jump, CodeLocationLabel destination)
|
||||
{
|
||||
MacroAssembler::repatchJump(jump, destination);
|
||||
}
|
||||
|
||||
void relink(CodeLocationCall call, CodeLocationLabel destination)
|
||||
{
|
||||
MacroAssembler::repatchCall(call, destination);
|
||||
}
|
||||
|
||||
void relink(CodeLocationCall call, FunctionPtr destination)
|
||||
{
|
||||
MacroAssembler::repatchCall(call, destination);
|
||||
}
|
||||
|
||||
void relink(CodeLocationNearCall nearCall, CodePtr destination)
|
||||
{
|
||||
MacroAssembler::repatchNearCall(nearCall, CodeLocationLabel(destination));
|
||||
}
|
||||
|
||||
void relink(CodeLocationNearCall nearCall, CodeLocationLabel destination)
|
||||
{
|
||||
MacroAssembler::repatchNearCall(nearCall, destination);
|
||||
}
|
||||
|
||||
void repatch(CodeLocationDataLabel32 dataLabel32, int32_t value)
|
||||
{
|
||||
MacroAssembler::repatchInt32(dataLabel32, value);
|
||||
}
|
||||
|
||||
void repatch(CodeLocationDataLabelPtr dataLabelPtr, void* value)
|
||||
{
|
||||
MacroAssembler::repatchPointer(dataLabelPtr, value);
|
||||
}
|
||||
|
||||
void repatchLoadPtrToLEA(CodeLocationInstruction instruction)
|
||||
{
|
||||
MacroAssembler::repatchLoadPtrToLEA(instruction);
|
||||
}
|
||||
|
||||
void repatchLEAToLoadPtr(CodeLocationInstruction instruction)
|
||||
{
|
||||
MacroAssembler::repatchLEAToLoadPtr(instruction);
|
||||
}
|
||||
|
||||
void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label)
|
||||
{
|
||||
relink(CodeLocationCall(CodePtr(returnAddress)), label);
|
||||
}
|
||||
|
||||
void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction)
|
||||
{
|
||||
relinkCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction));
|
||||
}
|
||||
|
||||
void relinkCallerToFunction(ReturnAddressPtr returnAddress, FunctionPtr function)
|
||||
{
|
||||
relink(CodeLocationCall(CodePtr(returnAddress)), function);
|
||||
}
|
||||
|
||||
void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label)
|
||||
{
|
||||
relink(CodeLocationNearCall(CodePtr(returnAddress)), label);
|
||||
}
|
||||
|
||||
void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction)
|
||||
{
|
||||
relinkNearCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction));
|
||||
}
|
||||
|
||||
protected:
|
||||
void* m_start;
|
||||
size_t m_size;
|
||||
bool mprot;
|
||||
};
|
||||
|
||||
} // namespace JSC
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // RepatchBuffer_h
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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 "ExecutableAllocator.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
namespace JSC {
|
||||
|
||||
size_t ExecutableAllocator::pageSize = 0;
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE(ASSEMBLER)
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ExecutableAllocator_h
|
||||
#define ExecutableAllocator_h
|
||||
|
||||
#include <stddef.h> // for ptrdiff_t
|
||||
#include <limits>
|
||||
#include <wtf/Assertions.h>
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
#include "jslock.h"
|
||||
|
||||
#if WTF_PLATFORM_IPHONE
|
||||
#include <libkern/OSCacheControl.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_SYMBIAN
|
||||
#include <e32std.h>
|
||||
#endif
|
||||
|
||||
#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX
|
||||
#include <sys/cachectl.h>
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_WINCE
|
||||
// From pkfuncs.h (private header file from the Platform Builder)
|
||||
#define CACHE_SYNC_ALL 0x07F
|
||||
extern "C" __declspec(dllimport) void CacheRangeFlush(LPVOID pAddr, DWORD dwLength, DWORD dwFlags);
|
||||
#endif
|
||||
|
||||
#define JIT_ALLOCATOR_PAGE_SIZE (ExecutableAllocator::pageSize)
|
||||
#define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 4)
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
#define PROTECTION_FLAGS_RW (PROT_READ | PROT_WRITE)
|
||||
#define PROTECTION_FLAGS_RX (PROT_READ | PROT_EXEC)
|
||||
#define INITIAL_PROTECTION_FLAGS PROTECTION_FLAGS_RX
|
||||
#else
|
||||
#define INITIAL_PROTECTION_FLAGS (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
#endif
|
||||
|
||||
namespace JSC {
|
||||
|
||||
// Something included via windows.h defines a macro with this name,
|
||||
// which causes the function below to fail to compile.
|
||||
#ifdef _MSC_VER
|
||||
# undef max
|
||||
#endif
|
||||
|
||||
inline size_t roundUpAllocationSize(size_t request, size_t granularity)
|
||||
{
|
||||
if ((std::numeric_limits<size_t>::max() - granularity) <= request)
|
||||
CRASH(); // Allocation is too large
|
||||
|
||||
// Round up to next page boundary
|
||||
size_t size = request + (granularity - 1);
|
||||
size = size & ~(granularity - 1);
|
||||
ASSERT(size >= request);
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
namespace JSC {
|
||||
|
||||
// These are reference-counted. A new one (from the constructor or create)
|
||||
// starts with a count of 1.
|
||||
class ExecutablePool {
|
||||
private:
|
||||
struct Allocation {
|
||||
char* pages;
|
||||
size_t size;
|
||||
#if WTF_PLATFORM_SYMBIAN
|
||||
RChunk* chunk;
|
||||
#endif
|
||||
};
|
||||
typedef js::Vector<Allocation, 2 ,js::SystemAllocPolicy > AllocationList;
|
||||
|
||||
// Reference count for automatic reclamation.
|
||||
jsrefcount m_refCount;
|
||||
|
||||
public:
|
||||
// It should be impossible for us to roll over, because only small
|
||||
// pools have multiple holders, and they have one holder per chunk
|
||||
// of generated code, and they only hold 16KB or so of code.
|
||||
void addRef() { JS_ATOMIC_INCREMENT(&m_refCount); }
|
||||
void release() { if (JS_ATOMIC_DECREMENT(&m_refCount) == 0) delete this; }
|
||||
|
||||
static ExecutablePool* create(size_t n)
|
||||
{
|
||||
return new ExecutablePool(n);
|
||||
}
|
||||
|
||||
void* alloc(size_t n)
|
||||
{
|
||||
ASSERT(m_freePtr <= m_end);
|
||||
|
||||
// Round 'n' up to a multiple of word size; if all allocations are of
|
||||
// word sized quantities, then all subsequent allocations will be aligned.
|
||||
n = roundUpAllocationSize(n, sizeof(void*));
|
||||
|
||||
if (static_cast<ptrdiff_t>(n) < (m_end - m_freePtr)) {
|
||||
void* result = m_freePtr;
|
||||
m_freePtr += n;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Insufficient space to allocate in the existing pool
|
||||
// so we need allocate into a new pool
|
||||
return poolAllocate(n);
|
||||
}
|
||||
|
||||
~ExecutablePool()
|
||||
{
|
||||
Allocation* end = m_pools.end();
|
||||
for (Allocation* ptr = m_pools.begin(); ptr != end; ++ptr)
|
||||
ExecutablePool::systemRelease(*ptr);
|
||||
}
|
||||
|
||||
size_t available() const { return (m_pools.length() > 1) ? 0 : m_end - m_freePtr; }
|
||||
|
||||
private:
|
||||
static Allocation systemAlloc(size_t n);
|
||||
static void systemRelease(const Allocation& alloc);
|
||||
|
||||
explicit ExecutablePool(size_t n);
|
||||
|
||||
void* poolAllocate(size_t n);
|
||||
|
||||
char* m_freePtr;
|
||||
char* m_end;
|
||||
AllocationList m_pools;
|
||||
};
|
||||
|
||||
class ExecutableAllocator {
|
||||
enum ProtectionSeting { Writable, Executable };
|
||||
|
||||
public:
|
||||
static size_t pageSize;
|
||||
ExecutableAllocator()
|
||||
{
|
||||
if (!pageSize)
|
||||
intializePageSize();
|
||||
m_smallAllocationPool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
|
||||
}
|
||||
|
||||
~ExecutableAllocator()
|
||||
{
|
||||
m_smallAllocationPool->release();
|
||||
}
|
||||
|
||||
// poolForSize returns reference-counted objects. The caller owns a reference
|
||||
// to the object; i.e., poolForSize increments the count before returning the
|
||||
// object.
|
||||
|
||||
ExecutablePool* poolForSize(size_t n)
|
||||
{
|
||||
// Try to fit in the existing small allocator
|
||||
if (n < m_smallAllocationPool->available()) {
|
||||
m_smallAllocationPool->addRef();
|
||||
return m_smallAllocationPool;
|
||||
}
|
||||
|
||||
// If the request is large, we just provide a unshared allocator
|
||||
if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE)
|
||||
return ExecutablePool::create(n);
|
||||
|
||||
// Create a new allocator
|
||||
ExecutablePool* pool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
|
||||
// At this point, local |pool| is the owner.
|
||||
|
||||
// If the new allocator will result in more free space than in
|
||||
// the current small allocator, then we will use it instead
|
||||
if ((pool->available() - n) > m_smallAllocationPool->available()) {
|
||||
m_smallAllocationPool->release();
|
||||
m_smallAllocationPool = pool;
|
||||
pool->addRef();
|
||||
}
|
||||
|
||||
// Pass ownership to the caller.
|
||||
return pool;
|
||||
}
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
static void makeWritable(void* start, size_t size)
|
||||
{
|
||||
reprotectRegion(start, size, Writable);
|
||||
}
|
||||
|
||||
static void makeExecutable(void* start, size_t size)
|
||||
{
|
||||
reprotectRegion(start, size, Executable);
|
||||
}
|
||||
#else
|
||||
static void makeWritable(void*, size_t) {}
|
||||
static void makeExecutable(void*, size_t) {}
|
||||
#endif
|
||||
|
||||
|
||||
#if WTF_CPU_X86 || WTF_CPU_X86_64
|
||||
static void cacheFlush(void*, size_t)
|
||||
{
|
||||
}
|
||||
#elif WTF_CPU_MIPS
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
#if WTF_COMPILER_GCC && (GCC_VERSION >= 40300)
|
||||
#if WTF_MIPS_ISA_REV(2) && (GCC_VERSION < 40403)
|
||||
int lineSize;
|
||||
asm("rdhwr %0, $1" : "=r" (lineSize));
|
||||
//
|
||||
// Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
|
||||
// mips_expand_synci_loop that may execute synci one more time.
|
||||
// "start" points to the fisrt byte of the cache line.
|
||||
// "end" points to the last byte of the line before the last cache line.
|
||||
// Because size is always a multiple of 4, this is safe to set
|
||||
// "end" to the last byte.
|
||||
//
|
||||
intptr_t start = reinterpret_cast<intptr_t>(code) & (-lineSize);
|
||||
intptr_t end = ((reinterpret_cast<intptr_t>(code) + size - 1) & (-lineSize)) - 1;
|
||||
__builtin___clear_cache(reinterpret_cast<char*>(start), reinterpret_cast<char*>(end));
|
||||
#else
|
||||
intptr_t end = reinterpret_cast<intptr_t>(code) + size;
|
||||
__builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
|
||||
#endif
|
||||
#else
|
||||
_flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
|
||||
#endif
|
||||
}
|
||||
#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
sys_dcache_flush(code, size);
|
||||
sys_icache_invalidate(code, size);
|
||||
}
|
||||
#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
asm volatile (
|
||||
"push {r7}\n"
|
||||
"mov r0, %0\n"
|
||||
"mov r1, %1\n"
|
||||
"movw r7, #0x2\n"
|
||||
"movt r7, #0xf\n"
|
||||
"movs r2, #0x0\n"
|
||||
"svc 0x0\n"
|
||||
"pop {r7}\n"
|
||||
:
|
||||
: "r" (code), "r" (reinterpret_cast<char*>(code) + size)
|
||||
: "r0", "r1", "r2");
|
||||
}
|
||||
#elif WTF_PLATFORM_SYMBIAN
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
User::IMB_Range(code, static_cast<char*>(code) + size);
|
||||
}
|
||||
#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
|
||||
static __asm void cacheFlush(void* code, size_t size);
|
||||
#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
asm volatile (
|
||||
"push {r7}\n"
|
||||
"mov r0, %0\n"
|
||||
"mov r1, %1\n"
|
||||
"mov r7, #0xf0000\n"
|
||||
"add r7, r7, #0x2\n"
|
||||
"mov r2, #0x0\n"
|
||||
"svc 0x0\n"
|
||||
"pop {r7}\n"
|
||||
:
|
||||
: "r" (code), "r" (reinterpret_cast<char*>(code) + size)
|
||||
: "r0", "r1", "r2");
|
||||
}
|
||||
#elif WTF_PLATFORM_WINCE
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
CacheRangeFlush(code, size, CACHE_SYNC_ALL);
|
||||
}
|
||||
#else
|
||||
#error "The cacheFlush support is missing on this platform."
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
static void reprotectRegion(void*, size_t, ProtectionSeting);
|
||||
#endif
|
||||
|
||||
ExecutablePool* m_smallAllocationPool;
|
||||
static void intializePageSize();
|
||||
};
|
||||
|
||||
inline ExecutablePool::ExecutablePool(size_t n) : m_refCount(1)
|
||||
{
|
||||
size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
|
||||
Allocation mem = systemAlloc(allocSize);
|
||||
m_pools.append(mem);
|
||||
m_freePtr = mem.pages;
|
||||
if (!m_freePtr)
|
||||
CRASH(); // Failed to allocate
|
||||
m_end = m_freePtr + allocSize;
|
||||
}
|
||||
|
||||
inline void* ExecutablePool::poolAllocate(size_t n)
|
||||
{
|
||||
size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
|
||||
|
||||
Allocation result = systemAlloc(allocSize);
|
||||
if (!result.pages)
|
||||
CRASH(); // Failed to allocate
|
||||
|
||||
ASSERT(m_end >= m_freePtr);
|
||||
if ((allocSize - n) > static_cast<size_t>(m_end - m_freePtr)) {
|
||||
// Replace allocation pool
|
||||
m_freePtr = result.pages + n;
|
||||
m_end = result.pages + allocSize;
|
||||
}
|
||||
|
||||
m_pools.append(result);
|
||||
return result.pages;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // ENABLE(ASSEMBLER)
|
||||
|
||||
#endif // !defined(ExecutableAllocator)
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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 "ExecutableAllocator.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace JSC {
|
||||
|
||||
void ExecutableAllocator::intializePageSize()
|
||||
{
|
||||
ExecutableAllocator::pageSize = getpagesize();
|
||||
}
|
||||
|
||||
ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n)
|
||||
{
|
||||
void* allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, -1/*VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY*/, 0);
|
||||
if (allocation == MAP_FAILED)
|
||||
CRASH();
|
||||
ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc)
|
||||
{
|
||||
int result = munmap(alloc.pages, alloc.size);
|
||||
ASSERT_UNUSED(result, !result);
|
||||
}
|
||||
|
||||
#if WTF_ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSeting setting)
|
||||
{
|
||||
if (!pageSize)
|
||||
intializePageSize();
|
||||
|
||||
// Calculate the start of the page containing this region,
|
||||
// and account for this extra memory within size.
|
||||
intptr_t startPtr = reinterpret_cast<intptr_t>(start);
|
||||
intptr_t pageStartPtr = startPtr & ~(pageSize - 1);
|
||||
void* pageStart = reinterpret_cast<void*>(pageStartPtr);
|
||||
size += (startPtr - pageStartPtr);
|
||||
|
||||
// Round size up
|
||||
size += (pageSize - 1);
|
||||
size &= ~(pageSize - 1);
|
||||
|
||||
mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE(ASSEMBLER)
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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 "ExecutableAllocator.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
namespace JSC {
|
||||
|
||||
void ExecutableAllocator::intializePageSize()
|
||||
{
|
||||
SYSTEM_INFO system_info;
|
||||
GetSystemInfo(&system_info);
|
||||
ExecutableAllocator::pageSize = system_info.dwPageSize;
|
||||
}
|
||||
|
||||
ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n)
|
||||
{
|
||||
void* allocation = VirtualAlloc(0, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (!allocation)
|
||||
CRASH();
|
||||
ExecutablePool::Allocation alloc = {reinterpret_cast<char*>(allocation), n};
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc)
|
||||
{
|
||||
VirtualFree(alloc.pages, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE(ASSEMBLER)
|
|
@ -0,0 +1,71 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Julian Seward <jseward@acm.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _include_assembler_moco_stubs_h_
|
||||
#define _include_assembler_moco_stubs_h_
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class JITCode {
|
||||
public:
|
||||
JITCode(void* start, size_t size)
|
||||
: m_start(start), m_size(size)
|
||||
{
|
||||
}
|
||||
void* start() { return m_start; }
|
||||
size_t size() { return m_size; }
|
||||
private:
|
||||
void* m_start;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
class CodeBlock {
|
||||
public:
|
||||
CodeBlock(JITCode& jc)
|
||||
: m_jitcode(jc)
|
||||
{
|
||||
}
|
||||
JITCode& getJITCode() { return m_jitcode; }
|
||||
private:
|
||||
JITCode& m_jitcode;
|
||||
};
|
||||
|
||||
} // namespace JSC
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2007-2009 Torch Mobile, Inc.
|
||||
*
|
||||
* 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 COMPUTER, 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 COMPUTER, 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 "Assertions.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#if WTF_COMPILER_MSVC && !WTF_PLATFORM_WINCE
|
||||
#ifndef WINVER
|
||||
#define WINVER 0x0500
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_WINCE
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
WTF_ATTRIBUTE_PRINTF(1, 0)
|
||||
static void vprintf_stderr_common(const char* format, va_list args)
|
||||
{
|
||||
vfprintf(stderr, format, args);
|
||||
}
|
||||
|
||||
WTF_ATTRIBUTE_PRINTF(1, 2)
|
||||
static void printf_stderr_common(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf_stderr_common(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void printCallSite(const char* file, int line, const char* function)
|
||||
{
|
||||
#if WTF_PLATFORM_WIN && !WTF_PLATFORM_WINCE && defined _DEBUG
|
||||
_CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
|
||||
#else
|
||||
printf_stderr_common("(%s:%d %s)\n", file, line, function);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
|
||||
{
|
||||
if (assertion)
|
||||
printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
|
||||
else
|
||||
printf_stderr_common("SHOULD NEVER BE REACHED\n");
|
||||
printCallSite(file, line, function);
|
||||
}
|
||||
|
||||
void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
|
||||
{
|
||||
printf_stderr_common("ASSERTION FAILED: ");
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf_stderr_common(format, args);
|
||||
va_end(args);
|
||||
printf_stderr_common("\n%s\n", assertion);
|
||||
printCallSite(file, line, function);
|
||||
}
|
||||
|
||||
void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
|
||||
{
|
||||
printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
|
||||
printCallSite(file, line, function);
|
||||
}
|
||||
|
||||
void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
|
||||
{
|
||||
printf_stderr_common("FATAL ERROR: ");
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf_stderr_common(format, args);
|
||||
va_end(args);
|
||||
printf_stderr_common("\n");
|
||||
printCallSite(file, line, function);
|
||||
}
|
||||
|
||||
void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
|
||||
{
|
||||
printf_stderr_common("ERROR: ");
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf_stderr_common(format, args);
|
||||
va_end(args);
|
||||
printf_stderr_common("\n");
|
||||
printCallSite(file, line, function);
|
||||
}
|
||||
|
||||
void WTFLog(WTFLogChannel* channel, const char* format, ...)
|
||||
{
|
||||
if (channel->state != WTFLogChannelOn)
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf_stderr_common(format, args);
|
||||
va_end(args);
|
||||
if (format[strlen(format) - 1] != '\n')
|
||||
printf_stderr_common("\n");
|
||||
}
|
||||
|
||||
void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
|
||||
{
|
||||
if (channel->state != WTFLogChannelOn)
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf_stderr_common(format, args);
|
||||
va_end(args);
|
||||
if (format[strlen(format) - 1] != '\n')
|
||||
printf_stderr_common("\n");
|
||||
printCallSite(file, line, function);
|
||||
}
|
||||
|
||||
} // extern "C"
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (C) 2003, 2006, 2007 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 COMPUTER, 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 COMPUTER, INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef WTF_Assertions_h
|
||||
#define WTF_Assertions_h
|
||||
|
||||
/*
|
||||
no namespaces because this file has to be includable from C and Objective-C
|
||||
|
||||
Note, this file uses many GCC extensions, but it should be compatible with
|
||||
C, Objective C, C++, and Objective C++.
|
||||
|
||||
For non-debug builds, everything is disabled by default.
|
||||
Defining any of the symbols explicitly prevents this from having any effect.
|
||||
|
||||
MSVC7 note: variadic macro support was added in MSVC8, so for now we disable
|
||||
those macros in MSVC7. For more info, see the MSDN document on variadic
|
||||
macros here:
|
||||
|
||||
http://msdn2.microsoft.com/en-us/library/ms177415(VS.80).aspx
|
||||
*/
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
#if WTF_COMPILER_MSVC
|
||||
#include <stddef.h>
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_SYMBIAN
|
||||
#include <e32def.h>
|
||||
#include <e32debug.h>
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ASSERTIONS_DISABLED_DEFAULT 1
|
||||
#else
|
||||
#define ASSERTIONS_DISABLED_DEFAULT 0
|
||||
#endif
|
||||
|
||||
#ifndef ASSERT_DISABLED
|
||||
#define ASSERT_DISABLED ASSERTIONS_DISABLED_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifndef ASSERT_ARG_DISABLED
|
||||
#define ASSERT_ARG_DISABLED ASSERTIONS_DISABLED_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifndef FATAL_DISABLED
|
||||
#define FATAL_DISABLED ASSERTIONS_DISABLED_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifndef ERROR_DISABLED
|
||||
#define ERROR_DISABLED ASSERTIONS_DISABLED_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifndef LOG_DISABLED
|
||||
#define LOG_DISABLED ASSERTIONS_DISABLED_DEFAULT
|
||||
#endif
|
||||
|
||||
#if WTF_COMPILER_GCC
|
||||
#define WTF_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define WTF_PRETTY_FUNCTION __FUNCTION__
|
||||
#endif
|
||||
|
||||
/* WTF logging functions can process %@ in the format string to log a NSObject* but the printf format attribute
|
||||
emits a warning when %@ is used in the format string. Until <rdar://problem/5195437> is resolved we can't include
|
||||
the attribute when being used from Objective-C code in case it decides to use %@. */
|
||||
#if WTF_COMPILER_GCC && !defined(__OBJC__)
|
||||
#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments) __attribute__((__format__(printf, formatStringArgument, extraArguments)))
|
||||
#else
|
||||
#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments)
|
||||
#endif
|
||||
|
||||
/* These helper functions are always declared, but not necessarily always defined if the corresponding function is disabled. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum { WTFLogChannelOff, WTFLogChannelOn } WTFLogChannelState;
|
||||
|
||||
typedef struct {
|
||||
unsigned mask;
|
||||
const char *defaultName;
|
||||
WTFLogChannelState state;
|
||||
} WTFLogChannel;
|
||||
|
||||
void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion);
|
||||
void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
|
||||
void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion);
|
||||
void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
|
||||
void WTFReportError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
|
||||
void WTFLog(WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
|
||||
void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* CRASH -- gets us into the debugger or the crash reporter -- signals are ignored by the crash reporter so we must do better */
|
||||
|
||||
#ifndef CRASH
|
||||
#if WTF_PLATFORM_SYMBIAN
|
||||
#define CRASH() do { \
|
||||
__DEBUGGER(); \
|
||||
User::Panic(_L("Webkit CRASH"),0); \
|
||||
} while(false)
|
||||
#else
|
||||
#define CRASH() do { \
|
||||
*(int *)(uintptr_t)0xbbadbeef = 0; \
|
||||
((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
|
||||
} while(false)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ASSERT, ASSERT_WITH_MESSAGE, ASSERT_NOT_REACHED */
|
||||
|
||||
#if WTF_PLATFORM_WINCE && !WTF_PLATFORM_TORCHMOBILE
|
||||
/* FIXME: We include this here only to avoid a conflict with the ASSERT macro. */
|
||||
#include <windows.h>
|
||||
#undef min
|
||||
#undef max
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_WIN_OS || WTF_PLATFORM_SYMBIAN
|
||||
/* FIXME: Change to use something other than ASSERT to avoid this conflict with the underlying platform */
|
||||
#undef ASSERT
|
||||
#endif
|
||||
|
||||
#if ASSERT_DISABLED
|
||||
|
||||
#define ASSERT(assertion) ((void)0)
|
||||
#if WTF_COMPILER_MSVC7
|
||||
#define ASSERT_WITH_MESSAGE(assertion) ((void)0)
|
||||
#elif WTF_COMPILER_WINSCW
|
||||
#define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0)
|
||||
#else
|
||||
#define ASSERT_WITH_MESSAGE(assertion, ...) ((void)0)
|
||||
#endif /* COMPILER(MSVC7) */
|
||||
#define ASSERT_NOT_REACHED() ((void)0)
|
||||
#define ASSERT_UNUSED(variable, assertion) ((void)variable)
|
||||
|
||||
#else
|
||||
|
||||
#define ASSERT(assertion) do \
|
||||
if (!(assertion)) { \
|
||||
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
|
||||
CRASH(); \
|
||||
} \
|
||||
while (0)
|
||||
#if WTF_COMPILER_MSVC7
|
||||
#define ASSERT_WITH_MESSAGE(assertion) ((void)0)
|
||||
#elif WTF_COMPILER_WINSCW
|
||||
#define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0)
|
||||
#else
|
||||
#define ASSERT_WITH_MESSAGE(assertion, ...) do \
|
||||
if (!(assertion)) { \
|
||||
WTFReportAssertionFailureWithMessage(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion, __VA_ARGS__); \
|
||||
CRASH(); \
|
||||
} \
|
||||
while (0)
|
||||
#endif /* COMPILER(MSVC7) */
|
||||
#define ASSERT_NOT_REACHED() do { \
|
||||
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \
|
||||
CRASH(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_UNUSED(variable, assertion) ASSERT(assertion)
|
||||
|
||||
#endif
|
||||
|
||||
/* ASSERT_ARG */
|
||||
|
||||
#if ASSERT_ARG_DISABLED
|
||||
|
||||
#define ASSERT_ARG(argName, assertion) ((void)0)
|
||||
|
||||
#else
|
||||
|
||||
#define ASSERT_ARG(argName, assertion) do \
|
||||
if (!(assertion)) { \
|
||||
WTFReportArgumentAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #argName, #assertion); \
|
||||
CRASH(); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#endif
|
||||
|
||||
/* COMPILE_ASSERT */
|
||||
#ifndef COMPILE_ASSERT
|
||||
#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
/* FATAL */
|
||||
|
||||
#if FATAL_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW
|
||||
#define FATAL(...) ((void)0)
|
||||
#elif WTF_COMPILER_MSVC7
|
||||
#define FATAL() ((void)0)
|
||||
#else
|
||||
#define FATAL(...) do { \
|
||||
WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__); \
|
||||
CRASH(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* LOG_ERROR */
|
||||
|
||||
#if ERROR_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW
|
||||
#define LOG_ERROR(...) ((void)0)
|
||||
#elif WTF_COMPILER_MSVC7
|
||||
#define LOG_ERROR() ((void)0)
|
||||
#elif WTF_COMPILER_WINSCW
|
||||
#define LOG_ERROR(arg...) ((void)0)
|
||||
#else
|
||||
#define LOG_ERROR(...) WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* LOG */
|
||||
|
||||
#if LOG_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW
|
||||
#define LOG(channel, ...) ((void)0)
|
||||
#elif WTF_COMPILER_MSVC7
|
||||
#define LOG() ((void)0)
|
||||
#elif WTF_COMPILER_WINSCW
|
||||
#define LOG(arg...) ((void)0)
|
||||
#else
|
||||
#define LOG(channel, ...) WTFLog(&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__)
|
||||
#define JOIN_LOG_CHANNEL_WITH_PREFIX(prefix, channel) JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel)
|
||||
#define JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel) prefix ## channel
|
||||
#endif
|
||||
|
||||
/* LOG_VERBOSE */
|
||||
|
||||
#if LOG_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW
|
||||
#define LOG_VERBOSE(channel, ...) ((void)0)
|
||||
#elif WTF_COMPILER_MSVC7
|
||||
#define LOG_VERBOSE(channel) ((void)0)
|
||||
#elif WTF_COMPILER_WINSCW
|
||||
#define LOG_VERBOSE(channel, arg...) ((void)0)
|
||||
#else
|
||||
#define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif /* WTF_Assertions_h */
|
|
@ -0,0 +1,985 @@
|
|||
/*
|
||||
* Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2007-2009 Torch Mobile, Inc.
|
||||
*
|
||||
* 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 COMPUTER, 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 COMPUTER, INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef WTF_Platform_h
|
||||
#define WTF_Platform_h
|
||||
|
||||
/* Either XX(YY) --> WTF_XX_YY or XX(YY) --> XX_YY, depending on XX
|
||||
|
||||
PLATFORM(YY) --> WTF_PLATFORM_YY
|
||||
COMPILER(YY) --> WTF_COMPILER_YY
|
||||
CPU(YY) --> WTF_CPU_YY
|
||||
OS(YY) --> WTF_OS_YY
|
||||
USE(YY) --> WTF_USE_YY
|
||||
|
||||
HAVE(YY) --> HAVE_YY
|
||||
ENABLE(YY) --> ENABLE_YY
|
||||
*/
|
||||
|
||||
/* ==== PLATFORM handles OS, operating environment, graphics API, and
|
||||
CPU. This macro will be phased out in favor of platform adaptation
|
||||
macros, policy decision macros, and top-level port definitions. ==== */
|
||||
//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE) && WTF_PLATFORM_##WTF_FEATURE)
|
||||
|
||||
|
||||
/* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
|
||||
|
||||
/* COMPILER() - the compiler being used to build the project */
|
||||
//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE) && WTF_COMPILER_##WTF_FEATURE)
|
||||
/* CPU() - the target CPU architecture */
|
||||
//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE) && WTF_CPU_##WTF_FEATURE)
|
||||
/* HAVE() - specific system features (headers, functions or similar) that are present or not */
|
||||
//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE) && HAVE_##WTF_FEATURE)
|
||||
/* OS() - underlying operating system; only to be used for mandated low-level services like
|
||||
virtual memory, not to choose a GUI toolkit */
|
||||
//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE) && WTF_OS_##WTF_FEATURE)
|
||||
|
||||
|
||||
/* ==== Policy decision macros: these define policy choices for a particular port. ==== */
|
||||
|
||||
/* USE() - use a particular third-party library or optional OS service */
|
||||
//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE) && WTF_USE_##WTF_FEATURE)
|
||||
/* ENABLE() - turn on a specific feature of WebKit */
|
||||
//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE) && ENABLE_##WTF_FEATURE)
|
||||
|
||||
|
||||
|
||||
/* ==== COMPILER() - the compiler being used to build the project ==== */
|
||||
|
||||
/* COMPILER(MSVC) Microsoft Visual C++ */
|
||||
/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/
|
||||
#if defined(_MSC_VER)
|
||||
#define WTF_COMPILER_MSVC 1
|
||||
#if _MSC_VER < 1400
|
||||
#define WTF_COMPILER_MSVC7 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* COMPILER(RVCT) - ARM RealView Compilation Tools */
|
||||
#if defined(__CC_ARM) || defined(__ARMCC__)
|
||||
#define WTF_COMPILER_RVCT 1
|
||||
#endif
|
||||
|
||||
/* COMPILER(GCC) - GNU Compiler Collection */
|
||||
/* --gnu option of the RVCT compiler also defines __GNUC__ */
|
||||
#if defined(__GNUC__) && !WTF_COMPILER_RVCT
|
||||
#define WTF_COMPILER_GCC 1
|
||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
/* COMPILER(MINGW) - MinGW GCC */
|
||||
#if defined(MINGW) || defined(__MINGW32__)
|
||||
#define WTF_COMPILER_MINGW 1
|
||||
#endif
|
||||
|
||||
/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */
|
||||
#if defined(__WINSCW__)
|
||||
#define WTF_COMPILER_WINSCW 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ==== CPU() - the target CPU architecture ==== */
|
||||
|
||||
/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
|
||||
|
||||
|
||||
/* CPU(ALPHA) - DEC Alpha */
|
||||
#if defined(__alpha__)
|
||||
#define WTF_CPU_ALPHA 1
|
||||
#endif
|
||||
|
||||
/* CPU(IA64) - Itanium / IA-64 */
|
||||
#if defined(__ia64__)
|
||||
#define WTF_CPU_IA64 1
|
||||
#endif
|
||||
|
||||
/* CPU(PPC) - PowerPC 32-bit */
|
||||
#if defined(__ppc__) \
|
||||
|| defined(__PPC__) \
|
||||
|| defined(__powerpc__) \
|
||||
|| defined(__powerpc) \
|
||||
|| defined(__POWERPC__) \
|
||||
|| defined(_M_PPC) \
|
||||
|| defined(__PPC)
|
||||
#define WTF_CPU_PPC 1
|
||||
#define WTF_CPU_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
/* CPU(PPC64) - PowerPC 64-bit */
|
||||
#if defined(__ppc64__) \
|
||||
|| defined(__PPC64__)
|
||||
#define WTF_CPU_PPC64 1
|
||||
#define WTF_CPU_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
/* CPU(SH4) - SuperH SH-4 */
|
||||
#if defined(__SH4__)
|
||||
#define WTF_CPU_SH4 1
|
||||
#endif
|
||||
|
||||
/* CPU(SPARC32) - SPARC 32-bit */
|
||||
#if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8)
|
||||
#define WTF_CPU_SPARC32 1
|
||||
#define WTF_CPU_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
/* CPU(SPARC64) - SPARC 64-bit */
|
||||
#if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)
|
||||
#define WTF_CPU_SPARC64 1
|
||||
#define WTF_CPU_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */
|
||||
#if WTF_CPU_SPARC32 || WTF_CPU_SPARC64
|
||||
#define WTF_CPU_SPARC
|
||||
#endif
|
||||
|
||||
/* CPU(X86) - i386 / x86 32-bit */
|
||||
#if defined(__i386__) \
|
||||
|| defined(i386) \
|
||||
|| defined(_M_IX86) \
|
||||
|| defined(_X86_) \
|
||||
|| defined(__THW_INTEL)
|
||||
#define WTF_CPU_X86 1
|
||||
#endif
|
||||
|
||||
/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
|
||||
#if defined(__x86_64__) \
|
||||
|| defined(_M_X64)
|
||||
#define WTF_CPU_X86_64 1
|
||||
#endif
|
||||
|
||||
/* CPU(ARM) - ARM, any version*/
|
||||
#if defined(arm) \
|
||||
|| defined(__arm__)
|
||||
#define WTF_CPU_ARM 1
|
||||
|
||||
#if defined(__ARMEB__)
|
||||
#define WTF_CPU_BIG_ENDIAN 1
|
||||
|
||||
#elif !defined(__ARM_EABI__) \
|
||||
&& !defined(__EABI__) \
|
||||
&& !defined(__VFP_FP__) \
|
||||
&& !defined(ANDROID)
|
||||
#define WTF_CPU_MIDDLE_ENDIAN 1
|
||||
|
||||
#endif
|
||||
|
||||
#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N)
|
||||
|
||||
/* Set WTF_ARM_ARCH_VERSION */
|
||||
#if defined(__ARM_ARCH_4__) \
|
||||
|| defined(__ARM_ARCH_4T__) \
|
||||
|| defined(__MARM_ARMV4__) \
|
||||
|| defined(_ARMV4I_)
|
||||
#define WTF_ARM_ARCH_VERSION 4
|
||||
|
||||
#elif defined(__ARM_ARCH_5__) \
|
||||
|| defined(__ARM_ARCH_5T__) \
|
||||
|| defined(__ARM_ARCH_5E__) \
|
||||
|| defined(__ARM_ARCH_5TE__) \
|
||||
|| defined(__ARM_ARCH_5TEJ__) \
|
||||
|| defined(__MARM_ARMV5__)
|
||||
#define WTF_ARM_ARCH_VERSION 5
|
||||
|
||||
#elif defined(__ARM_ARCH_6__) \
|
||||
|| defined(__ARM_ARCH_6J__) \
|
||||
|| defined(__ARM_ARCH_6K__) \
|
||||
|| defined(__ARM_ARCH_6Z__) \
|
||||
|| defined(__ARM_ARCH_6ZK__) \
|
||||
|| defined(__ARM_ARCH_6T2__) \
|
||||
|| defined(__ARMV6__)
|
||||
#define WTF_ARM_ARCH_VERSION 6
|
||||
|
||||
#elif defined(__ARM_ARCH_7A__) \
|
||||
|| defined(__ARM_ARCH_7R__)
|
||||
#define WTF_ARM_ARCH_VERSION 7
|
||||
|
||||
/* RVCT sets _TARGET_ARCH_ARM */
|
||||
#elif defined(__TARGET_ARCH_ARM)
|
||||
#define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM
|
||||
|
||||
#else
|
||||
#define WTF_ARM_ARCH_VERSION 0
|
||||
|
||||
#endif
|
||||
|
||||
/* Set WTF_THUMB_ARCH_VERSION */
|
||||
#if defined(__ARM_ARCH_4T__)
|
||||
#define WTF_THUMB_ARCH_VERSION 1
|
||||
|
||||
#elif defined(__ARM_ARCH_5T__) \
|
||||
|| defined(__ARM_ARCH_5TE__) \
|
||||
|| defined(__ARM_ARCH_5TEJ__)
|
||||
#define WTF_THUMB_ARCH_VERSION 2
|
||||
|
||||
#elif defined(__ARM_ARCH_6J__) \
|
||||
|| defined(__ARM_ARCH_6K__) \
|
||||
|| defined(__ARM_ARCH_6Z__) \
|
||||
|| defined(__ARM_ARCH_6ZK__) \
|
||||
|| defined(__ARM_ARCH_6M__)
|
||||
#define WTF_THUMB_ARCH_VERSION 3
|
||||
|
||||
#elif defined(__ARM_ARCH_6T2__) \
|
||||
|| defined(__ARM_ARCH_7__) \
|
||||
|| defined(__ARM_ARCH_7A__) \
|
||||
|| defined(__ARM_ARCH_7R__) \
|
||||
|| defined(__ARM_ARCH_7M__)
|
||||
#define WTF_THUMB_ARCH_VERSION 4
|
||||
|
||||
/* RVCT sets __TARGET_ARCH_THUMB */
|
||||
#elif defined(__TARGET_ARCH_THUMB)
|
||||
#define WTF_THUMB_ARCH_VERSION __TARGET_ARCH_THUMB
|
||||
|
||||
#else
|
||||
#define WTF_THUMB_ARCH_VERSION 0
|
||||
#endif
|
||||
|
||||
|
||||
/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */
|
||||
/* On ARMv5 and below the natural alignment is required.
|
||||
And there are some other differences for v5 or earlier. */
|
||||
#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */
|
||||
#define WTF_CPU_ARMV5_OR_LOWER 1
|
||||
#endif
|
||||
|
||||
|
||||
/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
|
||||
/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */
|
||||
/* Only one of these will be defined. */
|
||||
#if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
|
||||
# if defined(thumb2) || defined(__thumb2__) \
|
||||
|| ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
|
||||
# define WTF_CPU_ARM_TRADITIONAL 0
|
||||
# define WTF_CPU_ARM_THUMB2 1
|
||||
# elif WTF_ARM_ARCH_AT_LEAST(4)
|
||||
# define WTF_CPU_ARM_TRADITIONAL 1
|
||||
# define WTF_CPU_ARM_THUMB2 0
|
||||
# else
|
||||
# error "Not supported ARM architecture"
|
||||
# endif
|
||||
#elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */
|
||||
# error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
|
||||
#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
|
||||
|
||||
#endif /* ARM */
|
||||
|
||||
|
||||
|
||||
/* Operating systems - low-level dependencies */
|
||||
|
||||
/* PLATFORM(DARWIN) */
|
||||
/* Operating system level dependencies for Mac OS X / Darwin that should */
|
||||
/* be used regardless of operating environment */
|
||||
#ifdef __APPLE__
|
||||
#define WTF_PLATFORM_DARWIN 1
|
||||
#include <AvailabilityMacros.h>
|
||||
#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
|
||||
#define BUILDING_ON_TIGER 1
|
||||
#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
|
||||
#define BUILDING_ON_LEOPARD 1
|
||||
#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
|
||||
#define BUILDING_ON_SNOW_LEOPARD 1
|
||||
#endif
|
||||
#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define TARGETING_TIGER 1
|
||||
#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
|
||||
#define TARGETING_LEOPARD 1
|
||||
#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
|
||||
#define TARGETING_SNOW_LEOPARD 1
|
||||
#endif
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
/* PLATFORM(WIN_OS) */
|
||||
/* Operating system level dependencies for Windows that should be used */
|
||||
/* regardless of operating environment */
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define WTF_PLATFORM_WIN_OS 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(WINCE) */
|
||||
/* Operating system level dependencies for Windows CE that should be used */
|
||||
/* regardless of operating environment */
|
||||
/* Note that for this platform PLATFORM(WIN_OS) is also defined. */
|
||||
#if defined(_WIN32_WCE)
|
||||
#define WTF_PLATFORM_WINCE 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(LINUX) */
|
||||
/* Operating system level dependencies for Linux-like systems that */
|
||||
/* should be used regardless of operating environment */
|
||||
#ifdef __linux__
|
||||
#define WTF_PLATFORM_LINUX 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(FREEBSD) */
|
||||
/* Operating system level dependencies for FreeBSD-like systems that */
|
||||
/* should be used regardless of operating environment */
|
||||
#ifdef __FreeBSD__
|
||||
#define WTF_PLATFORM_FREEBSD 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(OPENBSD) */
|
||||
/* Operating system level dependencies for OpenBSD systems that */
|
||||
/* should be used regardless of operating environment */
|
||||
#ifdef __OpenBSD__
|
||||
#define WTF_PLATFORM_OPENBSD 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(SOLARIS) */
|
||||
/* Operating system level dependencies for Solaris that should be used */
|
||||
/* regardless of operating environment */
|
||||
#if defined(sun) || defined(__sun)
|
||||
#define WTF_PLATFORM_SOLARIS 1
|
||||
#endif
|
||||
|
||||
#if defined (__SYMBIAN32__)
|
||||
/* we are cross-compiling, it is not really windows */
|
||||
#undef WTF_PLATFORM_WIN_OS
|
||||
#undef WTF_PLATFORM_WIN
|
||||
#define WTF_PLATFORM_SYMBIAN 1
|
||||
#endif
|
||||
|
||||
|
||||
/* PLATFORM(NETBSD) */
|
||||
/* Operating system level dependencies for NetBSD that should be used */
|
||||
/* regardless of operating environment */
|
||||
#if defined(__NetBSD__)
|
||||
#define WTF_PLATFORM_NETBSD 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(QNX) */
|
||||
/* Operating system level dependencies for QNX that should be used */
|
||||
/* regardless of operating environment */
|
||||
#if defined(__QNXNTO__)
|
||||
#define WTF_PLATFORM_QNX 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(UNIX) */
|
||||
/* Operating system level dependencies for Unix-like systems that */
|
||||
/* should be used regardless of operating environment */
|
||||
#if WTF_PLATFORM_DARWIN \
|
||||
|| WTF_PLATFORM_FREEBSD \
|
||||
|| WTF_PLATFORM_SYMBIAN \
|
||||
|| WTF_PLATFORM_NETBSD \
|
||||
|| defined(unix) \
|
||||
|| defined(__unix) \
|
||||
|| defined(__unix__) \
|
||||
|| defined(_AIX) \
|
||||
|| defined(__HAIKU__) \
|
||||
|| defined(__QNXNTO__) \
|
||||
|| defined(ANDROID)
|
||||
#define WTF_PLATFORM_UNIX 1
|
||||
#endif
|
||||
|
||||
/* Operating environments */
|
||||
|
||||
/* PLATFORM(CHROMIUM) */
|
||||
/* PLATFORM(QT) */
|
||||
/* PLATFORM(WX) */
|
||||
/* PLATFORM(GTK) */
|
||||
/* PLATFORM(HAIKU) */
|
||||
/* PLATFORM(MAC) */
|
||||
/* PLATFORM(WIN) */
|
||||
#if defined(BUILDING_CHROMIUM__)
|
||||
#define WTF_PLATFORM_CHROMIUM 1
|
||||
#elif defined(BUILDING_QT__)
|
||||
#define WTF_PLATFORM_QT 1
|
||||
#elif defined(BUILDING_WX__)
|
||||
#define WTF_PLATFORM_WX 1
|
||||
#elif defined(BUILDING_GTK__)
|
||||
#define WTF_PLATFORM_GTK 1
|
||||
#elif defined(BUILDING_HAIKU__)
|
||||
#define WTF_PLATFORM_HAIKU 1
|
||||
#elif WTF_PLATFORM_DARWIN
|
||||
#define WTF_PLATFORM_MAC 1
|
||||
#elif WTF_PLATFORM_WIN_OS
|
||||
#define WTF_PLATFORM_WIN 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(IPHONE) */
|
||||
#if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
|
||||
#define WTF_PLATFORM_IPHONE 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(IPHONE_SIMULATOR) */
|
||||
#if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
|
||||
#define WTF_PLATFORM_IPHONE 1
|
||||
#define WTF_PLATFORM_IPHONE_SIMULATOR 1
|
||||
#else
|
||||
#define WTF_PLATFORM_IPHONE_SIMULATOR 0
|
||||
#endif
|
||||
|
||||
#if !defined(WTF_PLATFORM_IPHONE)
|
||||
#define WTF_PLATFORM_IPHONE 0
|
||||
#endif
|
||||
|
||||
/* PLATFORM(ANDROID) */
|
||||
#if defined(ANDROID)
|
||||
#define WTF_PLATFORM_ANDROID 1
|
||||
#endif
|
||||
|
||||
/* Graphics engines */
|
||||
|
||||
/* PLATFORM(CG) and PLATFORM(CI) */
|
||||
#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE
|
||||
#define WTF_PLATFORM_CG 1
|
||||
#endif
|
||||
#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
|
||||
#define WTF_PLATFORM_CI 1
|
||||
#endif
|
||||
|
||||
/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */
|
||||
#if WTF_PLATFORM_CHROMIUM
|
||||
#if WTF_PLATFORM_DARWIN
|
||||
#define WTF_PLATFORM_CG 1
|
||||
#define WTF_PLATFORM_CI 1
|
||||
#define WTF_USE_ATSUI 1
|
||||
#define WTF_USE_CORE_TEXT 1
|
||||
#else
|
||||
#define WTF_PLATFORM_SKIA 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_GTK
|
||||
#define WTF_PLATFORM_CAIRO 1
|
||||
#endif
|
||||
|
||||
|
||||
/* PLATFORM(WINCE) && PLATFORM(QT)
|
||||
We can not determine the endianess at compile time. For
|
||||
Qt for Windows CE the endianess is specified in the
|
||||
device specific makespec
|
||||
*/
|
||||
#if WTF_PLATFORM_WINCE && WTF_PLATFORM_QT
|
||||
# include <QtGlobal>
|
||||
# undef WTF_PLATFORM_BIG_ENDIAN
|
||||
# undef WTF_PLATFORM_MIDDLE_ENDIAN
|
||||
# if Q_BYTE_ORDER == Q_BIG_EDIAN
|
||||
# define WTF_PLATFORM_BIG_ENDIAN 1
|
||||
# endif
|
||||
|
||||
# include <ce_time.h>
|
||||
#endif
|
||||
|
||||
#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
|
||||
#define ENABLE_JSC_MULTIPLE_THREADS 1
|
||||
#endif
|
||||
|
||||
/* On Windows, use QueryPerformanceCounter by default */
|
||||
#if WTF_PLATFORM_WIN_OS
|
||||
#define WTF_USE_QUERY_PERFORMANCE_COUNTER 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_WINCE && !WTF_PLATFORM_QT
|
||||
#undef ENABLE_JSC_MULTIPLE_THREADS
|
||||
#define ENABLE_JSC_MULTIPLE_THREADS 0
|
||||
#define USE_SYSTEM_MALLOC 0
|
||||
#define ENABLE_ICONDATABASE 0
|
||||
#define ENABLE_JAVASCRIPT_DEBUGGER 0
|
||||
#define ENABLE_FTPDIR 0
|
||||
#define ENABLE_PAN_SCROLLING 0
|
||||
#define ENABLE_WML 1
|
||||
#define HAVE_ACCESSIBILITY 0
|
||||
|
||||
#define NOMINMAX // Windows min and max conflict with standard macros
|
||||
#define NOSHLWAPI // shlwapi.h not available on WinCe
|
||||
|
||||
// MSDN documentation says these functions are provided with uspce.lib. But we cannot find this file.
|
||||
#define __usp10__ // disable "usp10.h"
|
||||
|
||||
#define _INC_ASSERT // disable "assert.h"
|
||||
#define assert(x)
|
||||
|
||||
// _countof is only included in CE6; for CE5 we need to define it ourself
|
||||
#ifndef _countof
|
||||
#define _countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#endif /* PLATFORM(WINCE) && !PLATFORM(QT) */
|
||||
|
||||
#if WTF_PLATFORM_QT
|
||||
#define WTF_USE_QT4_UNICODE 1
|
||||
#elif WTF_PLATFORM_WINCE
|
||||
#define WTF_USE_WINCE_UNICODE 1
|
||||
#elif WTF_PLATFORM_GTK
|
||||
/* The GTK+ Unicode backend is configurable */
|
||||
#else
|
||||
#define WTF_USE_ICU_UNICODE 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
|
||||
#define WTF_PLATFORM_CF 1
|
||||
#define WTF_USE_PTHREADS 1
|
||||
#define HAVE_PTHREAD_RWLOCK 1
|
||||
#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64
|
||||
#define WTF_USE_PLUGIN_HOST_PROCESS 1
|
||||
#endif
|
||||
#if !defined(ENABLE_MAC_JAVA_BRIDGE)
|
||||
#define ENABLE_MAC_JAVA_BRIDGE 1
|
||||
#endif
|
||||
#if !defined(ENABLE_DASHBOARD_SUPPORT)
|
||||
#define ENABLE_DASHBOARD_SUPPORT 1
|
||||
#endif
|
||||
#define HAVE_READLINE 1
|
||||
#define HAVE_RUNLOOP_TIMER 1
|
||||
#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */
|
||||
|
||||
#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN
|
||||
#define WTF_PLATFORM_CF 1
|
||||
#define WTF_USE_PTHREADS 1
|
||||
#define HAVE_PTHREAD_RWLOCK 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN
|
||||
#define WTF_PLATFORM_CF 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_IPHONE
|
||||
#define ENABLE_CONTEXT_MENUS 0
|
||||
#define ENABLE_DRAG_SUPPORT 0
|
||||
#define ENABLE_FTPDIR 1
|
||||
#define ENABLE_GEOLOCATION 1
|
||||
#define ENABLE_ICONDATABASE 0
|
||||
#define ENABLE_INSPECTOR 0
|
||||
#define ENABLE_MAC_JAVA_BRIDGE 0
|
||||
#define ENABLE_NETSCAPE_PLUGIN_API 0
|
||||
#define ENABLE_ORIENTATION_EVENTS 1
|
||||
#define ENABLE_REPAINT_THROTTLING 1
|
||||
#define HAVE_READLINE 1
|
||||
#define WTF_PLATFORM_CF 1
|
||||
#define WTF_USE_PTHREADS 1
|
||||
#define HAVE_PTHREAD_RWLOCK 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_ANDROID
|
||||
#define WTF_USE_PTHREADS 1
|
||||
#define WTF_PLATFORM_SGL 1
|
||||
#define USE_SYSTEM_MALLOC 1
|
||||
#define ENABLE_MAC_JAVA_BRIDGE 1
|
||||
#define LOG_DISABLED 1
|
||||
// Prevents Webkit from drawing the caret in textfields and textareas
|
||||
// This prevents unnecessary invals.
|
||||
#define ENABLE_TEXT_CARET 1
|
||||
#define ENABLE_JAVASCRIPT_DEBUGGER 0
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_WIN
|
||||
#define WTF_USE_WININET 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_WX
|
||||
#define ENABLE_ASSEMBLER 1
|
||||
#if WTF_PLATFORM_DARWIN
|
||||
#define WTF_PLATFORM_CF 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_GTK
|
||||
#if HAVE_PTHREAD_H
|
||||
#define WTF_USE_PTHREADS 1
|
||||
#define HAVE_PTHREAD_RWLOCK 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_HAIKU
|
||||
#define HAVE_POSIX_MEMALIGN 1
|
||||
#define WTF_USE_CURL 1
|
||||
#define WTF_USE_PTHREADS 1
|
||||
#define HAVE_PTHREAD_RWLOCK 1
|
||||
#define USE_SYSTEM_MALLOC 1
|
||||
#define ENABLE_NETSCAPE_PLUGIN_API 0
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_ACCESSIBILITY)
|
||||
#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
|
||||
#define HAVE_ACCESSIBILITY 1
|
||||
#endif
|
||||
#endif /* !defined(HAVE_ACCESSIBILITY) */
|
||||
|
||||
#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
|
||||
#define HAVE_SIGNAL_H 1
|
||||
#endif
|
||||
|
||||
#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \
|
||||
&& !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \
|
||||
&& !WTF_PLATFORM_ANDROID
|
||||
#define HAVE_TM_GMTOFF 1
|
||||
#define HAVE_TM_ZONE 1
|
||||
#define HAVE_TIMEGM 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_DARWIN
|
||||
|
||||
#define HAVE_ERRNO_H 1
|
||||
#define HAVE_LANGINFO_H 1
|
||||
#define HAVE_MMAP 1
|
||||
#define HAVE_MERGESORT 1
|
||||
#define HAVE_SBRK 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
#define HAVE_SYS_TIMEB_H 1
|
||||
|
||||
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT
|
||||
#define HAVE_MADV_FREE_REUSE 1
|
||||
#define HAVE_MADV_FREE 1
|
||||
#define HAVE_PTHREAD_SETNAME_NP 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_IPHONE
|
||||
#define HAVE_MADV_FREE 1
|
||||
#endif
|
||||
|
||||
#elif WTF_PLATFORM_WIN_OS
|
||||
|
||||
#if WTF_PLATFORM_WINCE
|
||||
#define HAVE_ERRNO_H 0
|
||||
#else
|
||||
#define HAVE_SYS_TIMEB_H 1
|
||||
#endif
|
||||
#define HAVE_VIRTUALALLOC 1
|
||||
|
||||
#elif WTF_PLATFORM_SYMBIAN
|
||||
|
||||
#define HAVE_ERRNO_H 1
|
||||
#define HAVE_MMAP 0
|
||||
#define HAVE_SBRK 1
|
||||
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
#if !WTF_COMPILER_RVCT
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#endif
|
||||
|
||||
#elif WTF_PLATFORM_QNX
|
||||
|
||||
#define HAVE_ERRNO_H 1
|
||||
#define HAVE_MMAP 1
|
||||
#define HAVE_SBRK 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
#elif WTF_PLATFORM_ANDROID
|
||||
|
||||
#define HAVE_ERRNO_H 1
|
||||
#define HAVE_LANGINFO_H 0
|
||||
#define HAVE_MMAP 1
|
||||
#define HAVE_SBRK 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
#else
|
||||
|
||||
/* FIXME: is this actually used or do other platforms generate their own config.h? */
|
||||
|
||||
#define HAVE_ERRNO_H 1
|
||||
/* As long as Haiku doesn't have a complete support of locale this will be disabled. */
|
||||
#if !WTF_PLATFORM_HAIKU
|
||||
#define HAVE_LANGINFO_H 1
|
||||
#endif
|
||||
#define HAVE_MMAP 1
|
||||
#define HAVE_SBRK 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
#endif
|
||||
|
||||
/* ENABLE macro defaults */
|
||||
|
||||
/* fastMalloc match validation allows for runtime verification that
|
||||
new is matched by delete, fastMalloc is matched by fastFree, etc. */
|
||||
#if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION)
|
||||
#define ENABLE_FAST_MALLOC_MATCH_VALIDATION 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_ICONDATABASE)
|
||||
#define ENABLE_ICONDATABASE 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_DATABASE)
|
||||
#define ENABLE_DATABASE 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_JAVASCRIPT_DEBUGGER)
|
||||
#define ENABLE_JAVASCRIPT_DEBUGGER 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_FTPDIR)
|
||||
#define ENABLE_FTPDIR 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_CONTEXT_MENUS)
|
||||
#define ENABLE_CONTEXT_MENUS 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_DRAG_SUPPORT)
|
||||
#define ENABLE_DRAG_SUPPORT 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_DASHBOARD_SUPPORT)
|
||||
#define ENABLE_DASHBOARD_SUPPORT 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_INSPECTOR)
|
||||
#define ENABLE_INSPECTOR 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_MAC_JAVA_BRIDGE)
|
||||
#define ENABLE_MAC_JAVA_BRIDGE 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_NETSCAPE_PLUGIN_API)
|
||||
#define ENABLE_NETSCAPE_PLUGIN_API 1
|
||||
#endif
|
||||
|
||||
#if !defined(WTF_USE_PLUGIN_HOST_PROCESS)
|
||||
#define WTF_USE_PLUGIN_HOST_PROCESS 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_ORIENTATION_EVENTS)
|
||||
#define ENABLE_ORIENTATION_EVENTS 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_OPCODE_STATS)
|
||||
#define ENABLE_OPCODE_STATS 0
|
||||
#endif
|
||||
|
||||
#define ENABLE_SAMPLING_COUNTERS 0
|
||||
#define ENABLE_SAMPLING_FLAGS 0
|
||||
#define ENABLE_OPCODE_SAMPLING 0
|
||||
#define ENABLE_CODEBLOCK_SAMPLING 0
|
||||
#if ENABLE_CODEBLOCK_SAMPLING && !ENABLE_OPCODE_SAMPLING
|
||||
#error "CODEBLOCK_SAMPLING requires OPCODE_SAMPLING"
|
||||
#endif
|
||||
#if ENABLE_OPCODE_SAMPLING || ENABLE_SAMPLING_FLAGS
|
||||
#define ENABLE_SAMPLING_THREAD 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_GEOLOCATION)
|
||||
#define ENABLE_GEOLOCATION 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_NOTIFICATIONS)
|
||||
#define ENABLE_NOTIFICATIONS 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_TEXT_CARET)
|
||||
#define ENABLE_TEXT_CARET 1
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL)
|
||||
#define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0
|
||||
#endif
|
||||
|
||||
#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
|
||||
#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA
|
||||
#define WTF_USE_JSVALUE64 1
|
||||
#elif WTF_CPU_ARM || WTF_CPU_PPC64
|
||||
#define WTF_USE_JSVALUE32 1
|
||||
#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW
|
||||
/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
|
||||
on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
|
||||
#define WTF_USE_JSVALUE32 1
|
||||
#else
|
||||
#define WTF_USE_JSVALUE32_64 1
|
||||
#endif
|
||||
#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */
|
||||
|
||||
#if !defined(ENABLE_REPAINT_THROTTLING)
|
||||
#define ENABLE_REPAINT_THROTTLING 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_JIT)
|
||||
|
||||
/* The JIT is tested & working on x86_64 Mac */
|
||||
#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC
|
||||
#define ENABLE_JIT 1
|
||||
/* The JIT is tested & working on x86 Mac */
|
||||
#elif WTF_CPU_X86 && WTF_PLATFORM_MAC
|
||||
#define ENABLE_JIT 1
|
||||
#define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
|
||||
#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
|
||||
#define ENABLE_JIT 1
|
||||
/* The JIT is tested & working on x86 Windows */
|
||||
#elif WTF_CPU_X86 && WTF_PLATFORM_WIN
|
||||
#define ENABLE_JIT 1
|
||||
#endif
|
||||
|
||||
#if PLATFORM(QT)
|
||||
#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN
|
||||
#define ENABLE_JIT 1
|
||||
#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN
|
||||
#define ENABLE_JIT 1
|
||||
#define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
|
||||
#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100
|
||||
#define ENABLE_JIT 1
|
||||
#define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
|
||||
#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC
|
||||
#define ENABLE_JIT 1
|
||||
#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
|
||||
#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100
|
||||
#define ENABLE_JIT 1
|
||||
#define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
|
||||
#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX
|
||||
#define ENABLE_JIT 1
|
||||
#endif
|
||||
#endif /* PLATFORM(QT) */
|
||||
|
||||
#endif /* !defined(ENABLE_JIT) */
|
||||
|
||||
#if ENABLE_JIT
|
||||
#ifndef ENABLE_JIT_OPTIMIZE_CALL
|
||||
#define ENABLE_JIT_OPTIMIZE_CALL 1
|
||||
#endif
|
||||
#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
|
||||
#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
|
||||
#endif
|
||||
#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
|
||||
#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
|
||||
#endif
|
||||
#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
|
||||
#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WTF_CPU_X86 && WTF_COMPILER_MSVC
|
||||
#define JSC_HOST_CALL __fastcall
|
||||
#elif WTF_CPU_X86 && WTF_COMPILER_GCC
|
||||
#define JSC_HOST_CALL __attribute__ ((fastcall))
|
||||
#else
|
||||
#define JSC_HOST_CALL
|
||||
#endif
|
||||
|
||||
#if WTF_COMPILER_GCC && !ENABLE_JIT
|
||||
#define HAVE_COMPUTED_GOTO 1
|
||||
#endif
|
||||
|
||||
#if ENABLE_JIT && defined(COVERAGE)
|
||||
#define WTF_USE_INTERPRETER 0
|
||||
#else
|
||||
#define WTF_USE_INTERPRETER 1
|
||||
#endif
|
||||
|
||||
/* Yet Another Regex Runtime. */
|
||||
#if !defined(ENABLE_YARR_JIT)
|
||||
|
||||
/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */
|
||||
#if (WTF_CPU_X86 && WTF_PLATFORM_MAC) \
|
||||
|| (WTF_CPU_X86_64 && WTF_PLATFORM_MAC) \
|
||||
|| (WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE) \
|
||||
|| (WTF_CPU_X86 && WTF_PLATFORM_WIN)
|
||||
#define ENABLE_YARR 1
|
||||
#define ENABLE_YARR_JIT 1
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_QT
|
||||
#if (WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100) \
|
||||
|| (WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC) \
|
||||
|| (WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100) \
|
||||
|| (WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX)
|
||||
#define ENABLE_YARR 1
|
||||
#define ENABLE_YARR_JIT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* !defined(ENABLE_YARR_JIT) */
|
||||
|
||||
/* Sanity Check */
|
||||
#if ENABLE_YARR_JIT && !ENABLE_YARR
|
||||
#error "YARR_JIT requires YARR"
|
||||
#endif
|
||||
|
||||
#if ENABLE_JIT || ENABLE_YARR_JIT
|
||||
#define ENABLE_ASSEMBLER 1
|
||||
#endif
|
||||
/* Setting this flag prevents the assembler from using RWX memory; this may improve
|
||||
security but currectly comes at a significant performance cost. */
|
||||
#if WTF_PLATFORM_IPHONE
|
||||
#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1
|
||||
#else
|
||||
#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0
|
||||
#endif
|
||||
|
||||
#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS
|
||||
#define ENABLE_PAN_SCROLLING 1
|
||||
#endif
|
||||
|
||||
/* Use the QXmlStreamReader implementation for XMLTokenizer */
|
||||
/* Use the QXmlQuery implementation for XSLTProcessor */
|
||||
#if WTF_PLATFORM_QT
|
||||
#define WTF_USE_QXMLSTREAM 1
|
||||
#define WTF_USE_QXMLQUERY 1
|
||||
#endif
|
||||
|
||||
#if !WTF_PLATFORM_QT
|
||||
#define WTF_USE_FONT_FAST_PATH 1
|
||||
#endif
|
||||
|
||||
/* Accelerated compositing */
|
||||
#if WTF_PLATFORM_MAC
|
||||
#if !defined(BUILDING_ON_TIGER)
|
||||
#define WTF_USE_ACCELERATED_COMPOSITING 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WTF_PLATFORM_IPHONE
|
||||
#define WTF_USE_ACCELERATED_COMPOSITING 1
|
||||
#endif
|
||||
|
||||
/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with
|
||||
with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and
|
||||
off in one place. */
|
||||
//#if WTF_PLATFORM_WIN
|
||||
//#include "QuartzCorePresent.h"
|
||||
//#if QUARTZCORE_PRESENT
|
||||
//#define WTF_USE_ACCELERATED_COMPOSITING 1
|
||||
//#define ENABLE_3D_RENDERING 1
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
#if WTF_COMPILER_GCC
|
||||
#define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
|
||||
#else
|
||||
#define WARN_UNUSED_RETURN
|
||||
#endif
|
||||
|
||||
#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
|
||||
#define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1
|
||||
#endif
|
||||
|
||||
/* Set up a define for a common error that is intended to cause a build error -- thus the space after Error. */
|
||||
#define WTF_PLATFORM_CFNETWORK Error USE_macro_should_be_used_with_CFNETWORK
|
||||
|
||||
#define ENABLE_JSC_ZOMBIES 0
|
||||
|
||||
#endif /* WTF_Platform_h */
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (C) 2008 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.
|
||||
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SegmentedVector_h
|
||||
#define SegmentedVector_h
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
namespace WTF {
|
||||
|
||||
// An iterator for SegmentedVector. It supports only the pre ++ operator
|
||||
template <typename T, size_t SegmentSize> class SegmentedVector;
|
||||
template <typename T, size_t SegmentSize> class SegmentedVectorIterator {
|
||||
private:
|
||||
friend class SegmentedVector<T, SegmentSize>;
|
||||
public:
|
||||
typedef SegmentedVectorIterator<T, SegmentSize> Iterator;
|
||||
|
||||
~SegmentedVectorIterator() { }
|
||||
|
||||
T& operator*() const { return m_vector.m_segments.at(m_segment)->at(m_index); }
|
||||
T* operator->() const { return &m_vector.m_segments.at(m_segment)->at(m_index); }
|
||||
|
||||
// Only prefix ++ operator supported
|
||||
Iterator& operator++()
|
||||
{
|
||||
ASSERT(m_index != SegmentSize);
|
||||
++m_index;
|
||||
//if (m_index >= m_vector.m_segments.at(m_segment)->size()) {
|
||||
if (m_index >= m_vector.m_segments[m_segment]->length()) {
|
||||
//if (m_segment + 1 < m_vector.m_segments.size()) {
|
||||
if (m_segment + 1 < m_vector.m_segments.length()) {
|
||||
//ASSERT(m_vector.m_segments.at(m_segment)->size() > 0);
|
||||
ASSERT(m_vector.m_segments[m_segment]->length() > 0);
|
||||
++m_segment;
|
||||
m_index = 0;
|
||||
} else {
|
||||
// Points to the "end" symbol
|
||||
m_segment = 0;
|
||||
m_index = SegmentSize;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& other) const
|
||||
{
|
||||
return (m_index == other.m_index && m_segment = other.m_segment && &m_vector == &other.m_vector);
|
||||
}
|
||||
|
||||
bool operator!=(const Iterator& other) const
|
||||
{
|
||||
return (m_index != other.m_index || m_segment != other.m_segment || &m_vector != &other.m_vector);
|
||||
}
|
||||
|
||||
SegmentedVectorIterator& operator=(const SegmentedVectorIterator<T, SegmentSize>& other)
|
||||
{
|
||||
m_vector = other.m_vector;
|
||||
m_segment = other.m_segment;
|
||||
m_index = other.m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
SegmentedVectorIterator(SegmentedVector<T, SegmentSize>& vector, size_t segment, size_t index)
|
||||
: m_vector(vector)
|
||||
, m_segment(segment)
|
||||
, m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
SegmentedVector<T, SegmentSize>& m_vector;
|
||||
size_t m_segment;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
// SegmentedVector is just like Vector, but it doesn't move the values
|
||||
// stored in its buffer when it grows. Therefore, it is safe to keep
|
||||
// pointers into a SegmentedVector.
|
||||
template <typename T, size_t SegmentSize> class SegmentedVector {
|
||||
friend class SegmentedVectorIterator<T, SegmentSize>;
|
||||
public:
|
||||
typedef SegmentedVectorIterator<T, SegmentSize> Iterator;
|
||||
|
||||
SegmentedVector()
|
||||
: m_size(0)
|
||||
{
|
||||
m_segments.append(&m_inlineSegment);
|
||||
}
|
||||
|
||||
~SegmentedVector()
|
||||
{
|
||||
deleteAllSegments();
|
||||
}
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
bool isEmpty() const { return !size(); }
|
||||
|
||||
T& at(size_t index)
|
||||
{
|
||||
if (index < SegmentSize)
|
||||
return m_inlineSegment[index];
|
||||
return segmentFor(index)->at(subscriptFor(index));
|
||||
}
|
||||
|
||||
T& operator[](size_t index)
|
||||
{
|
||||
return at(index);
|
||||
}
|
||||
|
||||
T& last()
|
||||
{
|
||||
return at(size() - 1);
|
||||
}
|
||||
|
||||
template <typename U> void append(const U& value)
|
||||
{
|
||||
++m_size;
|
||||
|
||||
if (m_size <= SegmentSize) {
|
||||
//m_inlineSegment.uncheckedAppend(value);
|
||||
m_inlineSegment.append(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!segmentExistsFor(m_size - 1))
|
||||
m_segments.append(new Segment);
|
||||
//segmentFor(m_size - 1)->uncheckedAppend(value);
|
||||
segmentFor(m_size - 1)->append(value);
|
||||
}
|
||||
|
||||
T& alloc()
|
||||
{
|
||||
append<T>(T());
|
||||
return last();
|
||||
}
|
||||
|
||||
void removeLast()
|
||||
{
|
||||
if (m_size <= SegmentSize)
|
||||
m_inlineSegment.removeLast();
|
||||
else
|
||||
segmentFor(m_size - 1)->removeLast();
|
||||
--m_size;
|
||||
}
|
||||
|
||||
void grow(size_t size)
|
||||
{
|
||||
ASSERT(size > m_size);
|
||||
ensureSegmentsFor(size);
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
deleteAllSegments();
|
||||
m_segments.resize(1);
|
||||
m_inlineSegment.clear();
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
Iterator begin()
|
||||
{
|
||||
return Iterator(*this, 0, m_size ? 0 : SegmentSize);
|
||||
}
|
||||
|
||||
Iterator end()
|
||||
{
|
||||
return Iterator(*this, 0, SegmentSize);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef js::Vector<T, SegmentSize ,js::SystemAllocPolicy > Segment;
|
||||
|
||||
void deleteAllSegments()
|
||||
{
|
||||
// Skip the first segment, because it's our inline segment, which was
|
||||
// not created by new.
|
||||
//for (size_t i = 1; i < m_segments.size(); i++)
|
||||
for (size_t i = 1; i < m_segments.length(); i++)
|
||||
delete m_segments[i];
|
||||
}
|
||||
|
||||
bool segmentExistsFor(size_t index)
|
||||
{
|
||||
//return index / SegmentSize < m_segments.size();
|
||||
return index / SegmentSize < m_segments.length();
|
||||
}
|
||||
|
||||
Segment* segmentFor(size_t index)
|
||||
{
|
||||
return m_segments[index / SegmentSize];
|
||||
}
|
||||
|
||||
size_t subscriptFor(size_t index)
|
||||
{
|
||||
return index % SegmentSize;
|
||||
}
|
||||
|
||||
void ensureSegmentsFor(size_t size)
|
||||
{
|
||||
size_t segmentCount = m_size / SegmentSize;
|
||||
if (m_size % SegmentSize)
|
||||
++segmentCount;
|
||||
//segmentCount = std::max<size_t>(segmentCount, 1); // We always have at least our inline segment.
|
||||
segmentCount = segmentCount > 1 ? segmentCount : 1; // We always have at least our inline segment.
|
||||
|
||||
size_t neededSegmentCount = size / SegmentSize;
|
||||
if (size % SegmentSize)
|
||||
++neededSegmentCount;
|
||||
|
||||
// Fill up to N - 1 segments.
|
||||
size_t end = neededSegmentCount - 1;
|
||||
for (size_t i = segmentCount - 1; i < end; ++i)
|
||||
ensureSegment(i, SegmentSize);
|
||||
|
||||
// Grow segment N to accomodate the remainder.
|
||||
ensureSegment(end, subscriptFor(size - 1) + 1);
|
||||
}
|
||||
|
||||
void ensureSegment(size_t segmentIndex, size_t size)
|
||||
{
|
||||
ASSERT(segmentIndex <= m_segments.size());
|
||||
if (segmentIndex == m_segments.size())
|
||||
m_segments.append(new Segment);
|
||||
m_segments[segmentIndex]->grow(size);
|
||||
}
|
||||
|
||||
size_t m_size;
|
||||
Segment m_inlineSegment;
|
||||
js::Vector<Segment*, 32 ,js::SystemAllocPolicy > m_segments;
|
||||
};
|
||||
|
||||
} // namespace WTF
|
||||
|
||||
using WTF::SegmentedVector;
|
||||
|
||||
#endif // SegmentedVector_h
|
|
@ -125,7 +125,7 @@ MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 42, 2, JSEXN_INTERNALERR, "bytecode {0} t
|
|||
MSG_DEF(JSMSG_UNKNOWN_FORMAT, 43, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}")
|
||||
MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 44, 0, JSEXN_SYNTAXERR, "too many constructor arguments")
|
||||
MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 45, 0, JSEXN_SYNTAXERR, "too many function arguments")
|
||||
MSG_DEF(JSMSG_BAD_QUANTIFIER, 46, 1, JSEXN_SYNTAXERR, "invalid quantifier {0}")
|
||||
MSG_DEF(JSMSG_BAD_QUANTIFIER, 46, 0, JSEXN_SYNTAXERR, "invalid quantifier")
|
||||
MSG_DEF(JSMSG_MIN_TOO_BIG, 47, 1, JSEXN_SYNTAXERR, "overlarge minimum {0}")
|
||||
MSG_DEF(JSMSG_MAX_TOO_BIG, 48, 1, JSEXN_SYNTAXERR, "overlarge maximum {0}")
|
||||
MSG_DEF(JSMSG_OUT_OF_ORDER, 49, 1, JSEXN_SYNTAXERR, "maximum {0} less than minimum")
|
||||
|
|
|
@ -93,6 +93,9 @@
|
|||
#include "jscntxtinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsregexpinlines.h"
|
||||
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
#include "jsxml.h"
|
||||
|
@ -575,6 +578,10 @@ JSRuntime::init(uint32 maxbytes)
|
|||
if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
|
||||
return false;
|
||||
|
||||
regExpAllocator = new JSC::ExecutableAllocator();
|
||||
if (!regExpAllocator)
|
||||
return false;
|
||||
|
||||
deflatedStringCache = new js::DeflatedStringCache();
|
||||
if (!deflatedStringCache || !deflatedStringCache->init())
|
||||
return false;
|
||||
|
@ -634,6 +641,7 @@ JSRuntime::~JSRuntime()
|
|||
js_FreeRuntimeScriptState(this);
|
||||
js_FinishAtomState(this);
|
||||
|
||||
delete regExpAllocator;
|
||||
/*
|
||||
* Finish the deflated string cache after the last GC and after
|
||||
* calling js_FinishAtomState, which finalizes strings.
|
||||
|
@ -5396,14 +5404,11 @@ JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
|
|||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
|
||||
{
|
||||
jschar *chars;
|
||||
JSObject *obj;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
chars = js_InflateString(cx, bytes, &length);
|
||||
jschar *chars = js_InflateString(cx, bytes, &length);
|
||||
if (!chars)
|
||||
return NULL;
|
||||
obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
|
||||
JSObject *obj = RegExp::createObject(cx, chars, length, flags);
|
||||
cx->free(chars);
|
||||
return obj;
|
||||
}
|
||||
|
@ -5412,22 +5417,17 @@ JS_PUBLIC_API(JSObject *)
|
|||
JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return js_NewRegExpObject(cx, NULL, chars, length, flags);
|
||||
return RegExp::createObject(cx, chars, length, flags);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
|
||||
{
|
||||
JSRegExpStatics *res;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, input);
|
||||
|
||||
/* No locking required, cx is thread-private and input must be live. */
|
||||
res = &cx->regExpStatics;
|
||||
res->clearRoots();
|
||||
res->input = input;
|
||||
res->multiline = multiline;
|
||||
cx->regExpStatics.reset(input, !!multiline);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -5441,7 +5441,7 @@ JS_PUBLIC_API(void)
|
|||
JS_ClearRegExpRoots(JSContext *cx)
|
||||
{
|
||||
/* No locking required, cx is thread-private and input must be live. */
|
||||
cx->regExpStatics.clearRoots();
|
||||
cx->regExpStatics.clear();
|
||||
}
|
||||
|
||||
/* TODO: compile, execute, get/set other statics... */
|
||||
|
|
|
@ -825,8 +825,9 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
|||
|
||||
JS_InitArenaPool(&cx->tempPool, "temp", TEMP_POOL_CHUNK_SIZE, sizeof(jsdouble),
|
||||
&cx->scriptStackQuota);
|
||||
JS_InitArenaPool(&cx->regExpPool, "regExp", TEMP_POOL_CHUNK_SIZE, sizeof(int),
|
||||
&cx->scriptStackQuota);
|
||||
|
||||
js_InitRegExpStatics(cx);
|
||||
JS_ASSERT(cx->resolveFlags == 0);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -1176,7 +1177,7 @@ FreeContext(JSContext *cx)
|
|||
#endif
|
||||
|
||||
/* Free the stuff hanging off of cx. */
|
||||
js_FreeRegExpStatics(cx);
|
||||
cx->regExpStatics.clear();
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
JS_FinishArenaPool(&cx->tempPool);
|
||||
|
||||
|
@ -2229,6 +2230,6 @@ FreeOldArenas(JSRuntime *rt, JSArenaPool *pool)
|
|||
void
|
||||
JSContext::purge()
|
||||
{
|
||||
FreeOldArenas(runtime, ®expPool);
|
||||
FreeOldArenas(runtime, ®ExpPool);
|
||||
}
|
||||
|
||||
|
|
185
js/src/jscntxt.h
185
js/src/jscntxt.h
|
@ -122,6 +122,10 @@ template<typename T> class Seq;
|
|||
|
||||
} /* namespace nanojit */
|
||||
|
||||
namespace JSC {
|
||||
class ExecutableAllocator;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Tracer constants. */
|
||||
|
@ -1542,6 +1546,8 @@ struct JSRuntime {
|
|||
|
||||
JSWrapObjectCallback wrapObjectCallback;
|
||||
|
||||
JSC::ExecutableAllocator *regExpAllocator;
|
||||
|
||||
JSRuntime();
|
||||
~JSRuntime();
|
||||
|
||||
|
@ -1636,23 +1642,131 @@ namespace js {
|
|||
class AutoGCRooter;
|
||||
}
|
||||
|
||||
struct JSRegExpStatics {
|
||||
JSContext *cx;
|
||||
JSString *input; /* input string to match (perl $_, GC root) */
|
||||
JSBool multiline; /* whether input contains newlines (perl $*) */
|
||||
JSSubString lastMatch; /* last string matched (perl $&) */
|
||||
JSSubString lastParen; /* last paren matched (perl $+) */
|
||||
JSSubString leftContext; /* input to left of last match (perl $`) */
|
||||
JSSubString rightContext; /* input to right of last match (perl $') */
|
||||
js::Vector<JSSubString> parens; /* last set of parens matched (perl $1, $2) */
|
||||
namespace js {
|
||||
|
||||
JSRegExpStatics(JSContext *cx) : cx(cx), parens(cx) {}
|
||||
class RegExp;
|
||||
|
||||
bool copy(const JSRegExpStatics& other);
|
||||
void clearRoots();
|
||||
void clear();
|
||||
class RegExpStatics
|
||||
{
|
||||
typedef Vector<int, 16> MatchPairs;
|
||||
JSContext * const cx;
|
||||
MatchPairs *matchPairs;
|
||||
JSString *input;
|
||||
uintN flags;
|
||||
bool ownsMatchPairs;
|
||||
|
||||
bool createDependent(size_t start, size_t end, jsval &out) const;
|
||||
/*
|
||||
* Check whether the index at |checkValidIndex| is valid (>= 0).
|
||||
* If so, construct a string for it and place it in |out|.
|
||||
* If not, place undefined in |out|.
|
||||
*/
|
||||
bool makeMatch(size_t checkValidIndex, size_t pairNum, jsval &out) const;
|
||||
static const uintN allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_STICKY | JSREG_MULTILINE;
|
||||
|
||||
size_t pairCount() const {
|
||||
if (!matchPairs)
|
||||
return 0;
|
||||
size_t matchItems = matchPairs->length();
|
||||
JS_ASSERT((matchItems % 2) == 0);
|
||||
return matchItems / 2;
|
||||
}
|
||||
|
||||
/* Fallible interface for RegExp. */
|
||||
MatchPairs *getOrCreateMatchPairs(JSString *newInput);
|
||||
|
||||
friend class RegExp;
|
||||
|
||||
public:
|
||||
explicit RegExpStatics(JSContext *cx)
|
||||
: cx(cx), matchPairs(), input(), flags(), ownsMatchPairs(true) { clear(); }
|
||||
~RegExpStatics();
|
||||
void save(RegExpStatics &container);
|
||||
void saveAndClear(RegExpStatics &container);
|
||||
void restore(RegExpStatics &container);
|
||||
|
||||
void reset(JSString *newInput, bool multiline) {
|
||||
clear();
|
||||
input = newInput;
|
||||
multiline = multiline;
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
void checkInvariants() {
|
||||
if (pairCount() > 0) {
|
||||
JS_ASSERT(input);
|
||||
JS_ASSERT(get(0, 0) <= get(0, 1));
|
||||
JS_ASSERT(get(0, 1) <= int(input->length()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Mutators. */
|
||||
|
||||
void setInput(JSString *newInput) { reset(newInput, multiline()); }
|
||||
|
||||
void setMultiline(bool enabled) {
|
||||
if (enabled)
|
||||
flags = flags | JSREG_MULTILINE;
|
||||
else
|
||||
flags = flags & ~JSREG_MULTILINE;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
input = 0;
|
||||
flags = 0;
|
||||
if (!ownsMatchPairs)
|
||||
matchPairs = 0;
|
||||
else if (matchPairs)
|
||||
matchPairs->clear();
|
||||
}
|
||||
|
||||
/* Accessors. */
|
||||
|
||||
JSString *getInput() const { return input; }
|
||||
uintN getFlags() const { return flags; }
|
||||
bool multiline() const { return flags & JSREG_MULTILINE; }
|
||||
bool matched() const { JS_ASSERT(pairCount() > 0); return get(0, 1) - get(0, 0) > 0; }
|
||||
size_t getParenCount() const { JS_ASSERT(pairCount() > 0); return pairCount() - 1; }
|
||||
|
||||
void mark(JSTracer *trc) const {
|
||||
if (input)
|
||||
JS_CALL_STRING_TRACER(trc, input, "res->input");
|
||||
}
|
||||
|
||||
size_t getParenLength(size_t parenNum) const {
|
||||
if (pairCount() <= parenNum + 1)
|
||||
return 0;
|
||||
return get(parenNum + 1, 1) - get(parenNum + 1, 0);
|
||||
}
|
||||
|
||||
int get(size_t pairNum, bool which) const {
|
||||
JS_ASSERT(pairNum < pairCount());
|
||||
return (*matchPairs)[2 * pairNum + which];
|
||||
}
|
||||
|
||||
/* jsval creators. */
|
||||
|
||||
bool createInput(jsval &out) const;
|
||||
bool createLastMatch(jsval &out) const { return makeMatch(0, 0, out); }
|
||||
bool createLastParen(jsval &out) const;
|
||||
bool createLeftContext(jsval &out) const;
|
||||
bool createRightContext(jsval &out) const;
|
||||
|
||||
bool createParen(size_t parenNum, jsval &out) const {
|
||||
return makeMatch((parenNum + 1) * 2, parenNum + 1, out);
|
||||
}
|
||||
|
||||
/* Substring creators. */
|
||||
|
||||
void getParen(size_t num, JSSubString &out) const;
|
||||
void getLastMatch(JSSubString &out) const;
|
||||
void getLastParen(JSSubString &out) const;
|
||||
void getLeftContext(JSSubString &out) const;
|
||||
void getRightContext(JSSubString &out) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct JSContext
|
||||
{
|
||||
explicit JSContext(JSRuntime *rt);
|
||||
|
@ -1743,6 +1857,9 @@ struct JSContext
|
|||
/* Temporary arena pool used while compiling and decompiling. */
|
||||
JSArenaPool tempPool;
|
||||
|
||||
/* Temporary arena pool used while evaluate regular expressions. */
|
||||
JSArenaPool regExpPool;
|
||||
|
||||
/* Top-level object and pointer to top stack frame's scope chain. */
|
||||
JSObject *globalObject;
|
||||
|
||||
|
@ -1750,7 +1867,7 @@ struct JSContext
|
|||
JSWeakRoots weakRoots;
|
||||
|
||||
/* Regular expression class statics. */
|
||||
JSRegExpStatics regExpStatics;
|
||||
js::RegExpStatics regExpStatics;
|
||||
|
||||
/* State for object and array toSource conversion. */
|
||||
JSSharpObjectMap sharpObjectMap;
|
||||
|
@ -1859,9 +1976,6 @@ struct JSContext
|
|||
/* Security callbacks that override any defined on the runtime. */
|
||||
JSSecurityCallbacks *securityCallbacks;
|
||||
|
||||
/* Pinned regexp pool used for regular expressions. */
|
||||
JSArenaPool regexpPool;
|
||||
|
||||
/* Stored here to avoid passing it around as a parameter. */
|
||||
uintN resolveFlags;
|
||||
|
||||
|
@ -2088,6 +2202,19 @@ private:
|
|||
JS_FRIEND_API(void) checkMallocGCPressure(void *p);
|
||||
};
|
||||
|
||||
inline
|
||||
js::RegExpStatics::~RegExpStatics()
|
||||
{
|
||||
if (ownsMatchPairs && matchPairs)
|
||||
cx->destroy<MatchPairs>(matchPairs);
|
||||
}
|
||||
|
||||
static inline void
|
||||
js_TraceRegExpStatics(JSTracer *trc, JSContext *acx)
|
||||
{
|
||||
acx->regExpStatics.mark(trc);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE JSObject *
|
||||
JSStackFrame::varobj(js::CallStack *cs) const
|
||||
{
|
||||
|
@ -2572,6 +2699,30 @@ class AutoKeepAtoms {
|
|||
~AutoKeepAtoms() { JS_UNKEEP_ATOMS(rt); }
|
||||
};
|
||||
|
||||
class AutoArenaAllocator {
|
||||
JSArenaPool *pool;
|
||||
void *mark;
|
||||
public:
|
||||
explicit AutoArenaAllocator(JSArenaPool *pool) : pool(pool) { mark = JS_ARENA_MARK(pool); }
|
||||
~AutoArenaAllocator() { JS_ARENA_RELEASE(pool, mark); }
|
||||
|
||||
template <typename T>
|
||||
T *alloc(size_t elems) {
|
||||
void *ptr;
|
||||
JS_ARENA_ALLOCATE(ptr, pool, elems * sizeof(T));
|
||||
return static_cast<T *>(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
class AutoReleasePtr {
|
||||
JSContext *cx;
|
||||
void *ptr;
|
||||
AutoReleasePtr operator=(const AutoReleasePtr &other);
|
||||
public:
|
||||
explicit AutoReleasePtr(JSContext *cx, void *ptr) : cx(cx), ptr(ptr) {}
|
||||
~AutoReleasePtr() { cx->free(ptr); }
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
class JSAutoResolveFlags
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
#include "jsstaticcheck.h"
|
||||
#include "jslibmath.h"
|
||||
#include "jsvector.h"
|
||||
#include "jsregexpinlines.h"
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
#include "jsxml.h"
|
||||
|
@ -88,6 +89,11 @@
|
|||
#include "jsdhash.h"
|
||||
#endif
|
||||
|
||||
// Grr, windows.h or something under it #defines CONST...
|
||||
#ifdef CONST
|
||||
#undef CONST
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
|
||||
/*
|
||||
|
@ -8273,16 +8279,13 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
|||
|
||||
case TOK_REGEXP:
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
pn = NullaryNode::create(tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
|
||||
obj = js_NewRegExpObject(context, &tokenStream,
|
||||
tokenStream.getTokenbuf().begin(),
|
||||
tokenStream.getTokenbuf().length(),
|
||||
tokenStream.currentToken().t_reflags);
|
||||
JSObject *obj = RegExp::createObject(context, tokenStream.getTokenbuf().begin(),
|
||||
tokenStream.getTokenbuf().length(),
|
||||
tokenStream.currentToken().t_reflags);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
if (!tc->compileAndGo()) {
|
||||
|
|
|
@ -96,6 +96,7 @@ extern "C++" {
|
|||
namespace js {
|
||||
struct Parser;
|
||||
struct Compiler;
|
||||
class RegExp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,7 +128,6 @@ typedef struct JSAtomMap JSAtomMap;
|
|||
typedef struct JSAtomState JSAtomState;
|
||||
typedef struct JSCodeSpec JSCodeSpec;
|
||||
typedef struct JSPrinter JSPrinter;
|
||||
typedef struct JSRegExp JSRegExp;
|
||||
typedef struct JSRegExpStatics JSRegExpStatics;
|
||||
typedef struct JSScope JSScope;
|
||||
typedef struct JSScopeOps JSScopeOps;
|
||||
|
|
5905
js/src/jsregexp.cpp
5905
js/src/jsregexp.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -50,87 +50,23 @@
|
|||
#include "jsdhash.h"
|
||||
#endif
|
||||
|
||||
/* Forward declarations. */
|
||||
namespace js {
|
||||
class RegExp;
|
||||
class RegExpStatics;
|
||||
class AutoValueRooter;
|
||||
}
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
namespace js { class AutoValueRooter; }
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
|
||||
js::AutoValueRooter *tvr);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
|
||||
js::AutoValueRooter *tvr);
|
||||
|
||||
/*
|
||||
* This struct holds a bitmap representation of a class from a regexp.
|
||||
* There's a list of these referenced by the classList field in the JSRegExp
|
||||
* struct below. The initial state has startIndex set to the offset in the
|
||||
* original regexp source of the beginning of the class contents. The first
|
||||
* use of the class converts the source representation into a bitmap.
|
||||
*
|
||||
*/
|
||||
typedef struct RECharSet {
|
||||
JSPackedBool converted;
|
||||
JSPackedBool sense;
|
||||
uint16 length;
|
||||
union {
|
||||
uint8 *bits;
|
||||
struct {
|
||||
size_t startIndex;
|
||||
size_t length;
|
||||
} src;
|
||||
} u;
|
||||
} RECharSet;
|
||||
|
||||
typedef struct RENode RENode;
|
||||
|
||||
struct JSRegExp {
|
||||
jsrefcount nrefs; /* reference count */
|
||||
uint16 flags; /* flags, see jsapi.h's JSREG_* defines */
|
||||
size_t parenCount; /* number of parenthesized submatches */
|
||||
size_t classCount; /* count [...] bitmaps */
|
||||
RECharSet *classList; /* list of [...] bitmaps */
|
||||
JSString *source; /* locked source string, sans // */
|
||||
jsbytecode program[1]; /* regular expression bytecode */
|
||||
};
|
||||
|
||||
extern JSRegExp *
|
||||
js_NewRegExp(JSContext *cx, js::TokenStream *ts,
|
||||
JSString *str, uintN flags, JSBool flat);
|
||||
|
||||
extern JSRegExp *
|
||||
js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt, JSBool flat);
|
||||
|
||||
#define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs)
|
||||
#define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re)
|
||||
|
||||
extern void
|
||||
js_DestroyRegExp(JSContext *cx, JSRegExp *re);
|
||||
|
||||
/*
|
||||
* Execute re on input str at *indexp, returning null in *rval on mismatch.
|
||||
* On match, return true if test is true, otherwise return an array object.
|
||||
* Update *indexp and cx->regExpStatics always on match.
|
||||
*/
|
||||
extern JSBool
|
||||
js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
|
||||
JSBool test, jsval *rval);
|
||||
|
||||
extern void
|
||||
js_InitRegExpStatics(JSContext *cx);
|
||||
|
||||
extern void
|
||||
js_TraceRegExpStatics(JSTracer *trc, JSContext *acx);
|
||||
|
||||
extern void
|
||||
js_FreeRegExpStatics(JSContext *cx);
|
||||
|
||||
#define VALUE_IS_REGEXP(cx, v) \
|
||||
(!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isRegExp())
|
||||
|
||||
extern JSClass js_RegExpClass;
|
||||
|
||||
static inline bool
|
||||
VALUE_IS_REGEXP(JSContext *cx, jsval v)
|
||||
{
|
||||
return !JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isRegExp();
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isRegExp() const
|
||||
{
|
||||
|
@ -149,23 +85,23 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj);
|
|||
extern JSBool
|
||||
js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *) JS_FASTCALL
|
||||
js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto);
|
||||
|
||||
/*
|
||||
* Create, serialize/deserialize, or clone a RegExp object.
|
||||
* Move data from |cx|'s regexp statics to |statics| and root the input string in |tvr| if it's
|
||||
* available.
|
||||
*/
|
||||
extern JSObject *
|
||||
js_NewRegExpObject(JSContext *cx, js::TokenStream *ts,
|
||||
const jschar *chars, size_t length, uintN flags);
|
||||
extern JS_FRIEND_API(void)
|
||||
js_SaveAndClearRegExpStatics(JSContext *cx, js::RegExpStatics *statics, js::AutoValueRooter *tvr);
|
||||
|
||||
/* Move the data from |statics| into |cx|. */
|
||||
extern JS_FRIEND_API(void)
|
||||
js_RestoreRegExpStatics(JSContext *cx, js::RegExpStatics *statics, js::AutoValueRooter *tvr);
|
||||
|
||||
extern JSBool
|
||||
js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp);
|
||||
|
||||
extern JS_FRIEND_API(JSObject *) JS_FASTCALL
|
||||
js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto);
|
||||
|
||||
/* Return whether the given character array contains RegExp meta-characters. */
|
||||
extern bool
|
||||
js_ContainsRegExpMetaChars(const jschar *chars, size_t length);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsregexp_h___ */
|
||||
|
|
|
@ -0,0 +1,419 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* June 12, 2009.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Leary <cdleary@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsregexpinlines_h___
|
||||
#define jsregexpinlines_h___
|
||||
|
||||
#include "jsregexp.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "yarr/yarr/RegexJIT.h"
|
||||
#include "nanojit/avmplus.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Defined in the inlines header to avoid Yarr dependency includes in main header. */
|
||||
class RegExp
|
||||
{
|
||||
jsrefcount refCount;
|
||||
JSString *source;
|
||||
JSC::Yarr::RegexCodeBlock compiled;
|
||||
unsigned parenCount;
|
||||
uint32 flags;
|
||||
|
||||
RegExp(JSString *source, uint32 flags)
|
||||
: refCount(1), source(source), compiled(), parenCount(), flags(flags) {}
|
||||
bool compileHelper(JSContext *cx, const UString &pattern);
|
||||
bool compile(JSContext *cx);
|
||||
static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
|
||||
void handlePCREError(JSContext *cx, int error);
|
||||
void handleYarrError(JSContext *cx, int error);
|
||||
|
||||
public:
|
||||
~RegExp() {}
|
||||
static bool hasMetaChars(const jschar *chars, size_t length);
|
||||
/*
|
||||
* Parse regexp flags. Report an error and return false if an invalid
|
||||
* sequence of flags is encountered (repeat/invalid flag).
|
||||
*/
|
||||
static bool parseFlags(JSContext *cx, JSString *flagStr, uint32 &flagsOut);
|
||||
|
||||
/* Factories. */
|
||||
|
||||
static RegExp *create(JSContext *cx, JSString *source, uint32 flags);
|
||||
static RegExp *createFlagged(JSContext *cx, JSString *source, JSString *flags);
|
||||
/*
|
||||
* Create an object with new regular expression internals.
|
||||
* @note The context's regexp statics flags are OR'd into the provided flags,
|
||||
* so this function is really meant for object creation during code
|
||||
* execution, as opposed to during something like XDR.
|
||||
*/
|
||||
static JSObject *createObject(JSContext *cx, const jschar *chars, size_t length, uint32 flags);
|
||||
static RegExp *extractFrom(JSObject *obj);
|
||||
static RegExp *clone(JSContext *cx, const RegExp &other);
|
||||
|
||||
/* Mutators. */
|
||||
void incref(JSContext *cx) { JS_ATOMIC_INCREMENT(&refCount); }
|
||||
void decref(JSContext *cx);
|
||||
|
||||
/* Accessors. */
|
||||
JSString *getSource() const { return source; }
|
||||
size_t getParenCount() const { return parenCount; }
|
||||
bool ignoreCase() const { return flags & JSREG_FOLD; }
|
||||
bool global() const { return flags & JSREG_GLOB; }
|
||||
bool multiline() const { return flags & JSREG_MULTILINE; }
|
||||
bool sticky() const { return flags & JSREG_STICKY; }
|
||||
const uint32 &getFlags() const { JS_ASSERT((flags & allFlags) == flags); return flags; }
|
||||
uint32 flagCount() const;
|
||||
|
||||
/*
|
||||
* Execute regexp on |input| at |*lastIndex|.
|
||||
*
|
||||
* On match: Update |*lastIndex| and RegExp class statics.
|
||||
* Return true if test is true. Place an array in |*rval| if test is false.
|
||||
* On mismatch: Make |*rval| null.
|
||||
*/
|
||||
bool execute(JSContext *cx, JSString *input, size_t *lastIndex, bool test, jsval *rval);
|
||||
};
|
||||
|
||||
/* RegExp inlines. */
|
||||
|
||||
inline RegExp *
|
||||
RegExp::create(JSContext *cx, JSString *source, uint32 flags)
|
||||
{
|
||||
RegExp *self;
|
||||
void *mem = cx->malloc(sizeof(*self));
|
||||
if (!mem)
|
||||
return NULL;
|
||||
self = new (mem) RegExp(source, flags);
|
||||
if (!self->compile(cx)) {
|
||||
cx->destroy<RegExp>(self);
|
||||
return NULL;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
RegExp::createObject(JSContext *cx, const jschar *chars, size_t length, uint32 flags)
|
||||
{
|
||||
JS_ASSERT((flags & allFlags) == flags);
|
||||
JSString *str = js_NewStringCopyN(cx, chars, length);
|
||||
if (!str)
|
||||
return NULL;
|
||||
AutoValueRooter tvr(cx, str);
|
||||
uint32 staticsFlags = cx->regExpStatics.getFlags();
|
||||
JS_ASSERT((staticsFlags & allFlags) == staticsFlags);
|
||||
RegExp *re = RegExp::create(cx, str, flags | staticsFlags);
|
||||
if (!re)
|
||||
return NULL;
|
||||
JSObject *obj = NewObject(cx, &js_RegExpClass, NULL, NULL);
|
||||
if (!obj) {
|
||||
re->decref(cx);
|
||||
return NULL;
|
||||
}
|
||||
obj->setPrivate(re);
|
||||
obj->zeroRegExpLastIndex();
|
||||
return obj;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExp::compileHelper(JSContext *cx, const UString &pattern)
|
||||
{
|
||||
bool fellBack = false;
|
||||
int error = 0;
|
||||
jitCompileRegex(*cx->runtime->regExpAllocator, compiled, pattern, parenCount, error, fellBack, ignoreCase(), multiline());
|
||||
if (!error)
|
||||
return true;
|
||||
if (fellBack)
|
||||
handlePCREError(cx, error);
|
||||
else
|
||||
handleYarrError(cx, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExp::compile(JSContext *cx)
|
||||
{
|
||||
if (!sticky())
|
||||
return compileHelper(cx, *source);
|
||||
/*
|
||||
* The sticky case we implement hackily by prepending a caret onto the front
|
||||
* and relying on |::execute| to pseudo-slice the string when it sees a sticky regexp.
|
||||
*/
|
||||
JSString *fakeySource = js_ConcatStringsZ(cx, "^", source);
|
||||
AutoValueRooter rooter(cx, fakeySource);
|
||||
return compileHelper(cx, *fakeySource);
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExp::hasMetaChars(const jschar *chars, size_t length)
|
||||
{
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
jschar c = chars[i];
|
||||
switch (c) {
|
||||
/* Taken from the PatternCharacter production in 15.10.1. */
|
||||
case '^': case '$': case '\\': case '.': case '*': case '+':
|
||||
case '?': case '(': case ')': case '[': case ']': case '{':
|
||||
case '}': case '|':
|
||||
return true;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline uint32
|
||||
RegExp::flagCount() const
|
||||
{
|
||||
uint32 nflags = 0;
|
||||
for (uint32 tmpFlags = flags; tmpFlags != 0; tmpFlags &= tmpFlags - 1)
|
||||
nflags++;
|
||||
return nflags;
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExp::decref(JSContext *cx)
|
||||
{
|
||||
if (JS_ATOMIC_DECREMENT(&refCount) == 0)
|
||||
cx->destroy<RegExp>(this);
|
||||
}
|
||||
|
||||
inline RegExp *
|
||||
RegExp::extractFrom(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT_IF(obj, obj->isRegExp());
|
||||
return static_cast<RegExp *>(obj->getPrivate());
|
||||
}
|
||||
|
||||
inline RegExp *
|
||||
RegExp::clone(JSContext *cx, const RegExp &other)
|
||||
{
|
||||
return create(cx, other.source, other.flags);
|
||||
}
|
||||
|
||||
/* RegExpStatics inlines. */
|
||||
|
||||
inline RegExpStatics::MatchPairs *
|
||||
RegExpStatics::getOrCreateMatchPairs(JSString *newInput)
|
||||
{
|
||||
input = newInput;
|
||||
if (ownsMatchPairs) {
|
||||
if (matchPairs)
|
||||
matchPairs->clear();
|
||||
else
|
||||
matchPairs = cx->create<MatchPairs>(cx);
|
||||
} else {
|
||||
matchPairs = cx->create<MatchPairs>(cx);
|
||||
ownsMatchPairs = false;
|
||||
}
|
||||
checkInvariants();
|
||||
return matchPairs;
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::restore(RegExpStatics &container)
|
||||
{
|
||||
checkInvariants();
|
||||
input = container.input;
|
||||
flags = container.flags;
|
||||
JS_ASSERT((flags & allFlags) == flags);
|
||||
matchPairs = container.matchPairs;
|
||||
ownsMatchPairs = container.ownsMatchPairs;
|
||||
container.ownsMatchPairs = false;
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::save(RegExpStatics &container)
|
||||
{
|
||||
checkInvariants();
|
||||
JS_ASSERT(this != &container);
|
||||
container.input = input;
|
||||
container.flags = flags;
|
||||
JS_ASSERT((flags & allFlags) == flags);
|
||||
container.matchPairs = matchPairs;
|
||||
JS_ASSERT_IF(matchPairs, matchPairs->length() == container.matchPairs->length());
|
||||
container.ownsMatchPairs = ownsMatchPairs;
|
||||
ownsMatchPairs = false;
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::saveAndClear(RegExpStatics &container)
|
||||
{
|
||||
save(container);
|
||||
clear();
|
||||
checkInvariants();
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpStatics::createDependent(size_t start, size_t end, jsval &out) const
|
||||
{
|
||||
JS_ASSERT(start <= end);
|
||||
JS_ASSERT(end <= input->length());
|
||||
JSString *str = js_NewDependentString(cx, input, start, end - start);
|
||||
if (!str)
|
||||
return false;
|
||||
out = STRING_TO_JSVAL(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpStatics::createInput(jsval &out) const
|
||||
{
|
||||
out = input ? STRING_TO_JSVAL(input) : JS_GetEmptyStringValue(cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpStatics::makeMatch(size_t checkValidIndex, size_t pairNum, jsval &out) const
|
||||
{
|
||||
if (checkValidIndex / 2 >= pairCount() || (*matchPairs)[checkValidIndex] < 0) {
|
||||
out = JS_GetEmptyStringValue(cx);
|
||||
return true;
|
||||
}
|
||||
return createDependent(get(pairNum, 0), get(pairNum, 1), out);
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpStatics::createLastParen(jsval &out) const
|
||||
{
|
||||
if (pairCount() <= 1) {
|
||||
out = JS_GetEmptyStringValue(cx);
|
||||
return true;
|
||||
}
|
||||
size_t num = pairCount() - 1;
|
||||
int start = get(num, 0);
|
||||
int end = get(num, 1);
|
||||
if (start == -1) {
|
||||
JS_ASSERT(end == -1);
|
||||
out = JS_GetEmptyStringValue(cx);
|
||||
return true;
|
||||
}
|
||||
JS_ASSERT(start >= 0 && end >= 0);
|
||||
return createDependent(start, end, out);
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpStatics::createLeftContext(jsval &out) const
|
||||
{
|
||||
if (!pairCount()) {
|
||||
out = JS_GetEmptyStringValue(cx);
|
||||
return true;
|
||||
}
|
||||
if ((*matchPairs)[0] < 0) {
|
||||
out = JSVAL_VOID;
|
||||
return true;
|
||||
}
|
||||
return createDependent(0, (*matchPairs)[0], out);
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegExpStatics::createRightContext(jsval &out) const
|
||||
{
|
||||
if (!pairCount()) {
|
||||
out = JS_GetEmptyStringValue(cx);
|
||||
return true;
|
||||
}
|
||||
if ((*matchPairs)[1] < 0) {
|
||||
out = JSVAL_VOID;
|
||||
return true;
|
||||
}
|
||||
return createDependent((*matchPairs)[1], input->length(), out);
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::getParen(size_t num, JSSubString &out) const
|
||||
{
|
||||
out.chars = input->chars() + get(num + 1, 0);
|
||||
out.length = getParenLength(num);
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::getLastMatch(JSSubString &out) const
|
||||
{
|
||||
if (!pairCount()) {
|
||||
out = js_EmptySubString;
|
||||
return;
|
||||
}
|
||||
JS_ASSERT(input);
|
||||
out.chars = input->chars() + get(0, 0);
|
||||
JS_ASSERT(get(0, 1) >= get(0, 0));
|
||||
out.length = get(0, 1) - get(0, 0);
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::getLastParen(JSSubString &out) const
|
||||
{
|
||||
if (!pairCount()) {
|
||||
out = js_EmptySubString;
|
||||
return;
|
||||
}
|
||||
size_t num = pairCount() - 1;
|
||||
out.chars = input->chars() + get(num, 0);
|
||||
JS_ASSERT(get(num, 1) >= get(num, 0));
|
||||
out.length = get(num, 1) - get(num, 0);
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::getLeftContext(JSSubString &out) const
|
||||
{
|
||||
if (!pairCount()) {
|
||||
out = js_EmptySubString;
|
||||
return;
|
||||
}
|
||||
out.chars = input->chars();
|
||||
out.length = get(0, 0);
|
||||
}
|
||||
|
||||
inline void
|
||||
RegExpStatics::getRightContext(JSSubString &out) const
|
||||
{
|
||||
if (!pairCount()) {
|
||||
out = js_EmptySubString;
|
||||
return;
|
||||
}
|
||||
out.chars = input->chars() + get(0, 1);
|
||||
JS_ASSERT(get(0, 1) <= int(input->length()));
|
||||
out.length = input->length() - get(0, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* jsregexpinlines_h___ */
|
|
@ -997,6 +997,22 @@ js_TraceId(JSTracer *trc, jsid id);
|
|||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
namespace js {
|
||||
|
||||
class AutoObjectLocker {
|
||||
JSContext * const cx;
|
||||
JSObject * const obj;
|
||||
public:
|
||||
AutoObjectLocker(JSContext *cx, JSObject *obj)
|
||||
: cx(cx), obj(obj) {
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
}
|
||||
|
||||
~AutoObjectLocker() { JS_UNLOCK_OBJ(cx, obj); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
|
|
274
js/src/jsstr.cpp
274
js/src/jsstr.cpp
|
@ -80,6 +80,7 @@
|
|||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsregexpinlines.h"
|
||||
#include "jsstrinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -208,6 +209,20 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
|
|||
return str;
|
||||
}
|
||||
|
||||
JSString * JS_FASTCALL
|
||||
js_ConcatStringsZ(JSContext *cx, const char *left, JSString *right)
|
||||
{
|
||||
const size_t leftLength = strlen(left);
|
||||
const size_t newLength = leftLength + right->length();
|
||||
const size_t newSize = (newLength + 1) * sizeof(jschar);
|
||||
jschar *chars = static_cast<jschar *>(cx->malloc(newSize));
|
||||
for (size_t i = 0; i < leftLength; ++i)
|
||||
chars[i] = left[i];
|
||||
js_strncpy(chars + leftLength, right->chars(), right->length());
|
||||
JSString *str = js_NewString(cx, chars, newLength);
|
||||
return str;
|
||||
}
|
||||
|
||||
const jschar *
|
||||
js_UndependString(JSContext *cx, JSString *str)
|
||||
{
|
||||
|
@ -1431,14 +1446,14 @@ class RegExpGuard
|
|||
|
||||
JSContext *mCx;
|
||||
JSObject *mReobj;
|
||||
JSRegExp *mRe;
|
||||
js::RegExp *mRe;
|
||||
|
||||
public:
|
||||
RegExpGuard(JSContext *cx) : mCx(cx), mRe(NULL) {}
|
||||
|
||||
~RegExpGuard() {
|
||||
if (mRe)
|
||||
DROP_REGEXP(mCx, mRe);
|
||||
mRe->decref(mCx);
|
||||
}
|
||||
|
||||
JSContext* cx() const { return mCx; }
|
||||
|
@ -1450,8 +1465,8 @@ class RegExpGuard
|
|||
jsval patval = vp[2];
|
||||
if (argc != 0 && VALUE_IS_REGEXP(mCx, patval)) {
|
||||
mReobj = JSVAL_TO_OBJECT(patval);
|
||||
mRe = (JSRegExp *) mReobj->getPrivate();
|
||||
HOLD_REGEXP(mCx, mRe);
|
||||
mRe = static_cast<js::RegExp *>(mReobj->getPrivate());
|
||||
mRe->incref(mCx);
|
||||
} else {
|
||||
patstr = ArgToRootedString(mCx, argc, vp, 0);
|
||||
if (!patstr)
|
||||
|
@ -1478,7 +1493,7 @@ class RegExpGuard
|
|||
patstr->getCharsAndLength(pat, patlen);
|
||||
if (optarg < argc ||
|
||||
(!flat &&
|
||||
(patlen > sMaxFlatPatLen || js_ContainsRegExpMetaChars(pat, patlen)))) {
|
||||
(patlen > sMaxFlatPatLen || RegExp::hasMetaChars(pat, patlen)))) {
|
||||
return false;
|
||||
}
|
||||
textstr->getCharsAndLength(text, textlen);
|
||||
|
@ -1509,7 +1524,7 @@ class RegExpGuard
|
|||
} else {
|
||||
opt = NULL;
|
||||
}
|
||||
mRe = js_NewRegExpOpt(mCx, patstr, opt, flat);
|
||||
mRe = RegExp::createFlagged(mCx, patstr, opt);
|
||||
if (!mRe)
|
||||
return false;
|
||||
mReobj = NULL;
|
||||
|
@ -1518,7 +1533,7 @@ class RegExpGuard
|
|||
|
||||
/* Data available on successful return from |normalizeRegExp|. */
|
||||
JSObject *reobj() const { return mReobj; } /* nullable */
|
||||
JSRegExp *re() const { return mRe; } /* non-null */
|
||||
js::RegExp *re() const { return mRe; } /* non-null */
|
||||
};
|
||||
|
||||
/* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */
|
||||
|
@ -1549,19 +1564,20 @@ static bool
|
|||
DoMatch(JSContext *cx, jsval *vp, JSString *str, const RegExpGuard &g,
|
||||
DoMatchCallback callback, void *data, MatchControlFlags flags)
|
||||
{
|
||||
if (g.re()->flags & JSREG_GLOB) {
|
||||
RegExp &re = *g.re();
|
||||
if (re.global()) {
|
||||
/* global matching ('g') */
|
||||
bool testGlobal = flags & TEST_GLOBAL_BIT;
|
||||
if (g.reobj())
|
||||
g.reobj()->zeroRegExpLastIndex();
|
||||
for (size_t count = 0, i = 0, length = str->length(); i <= length; ++count) {
|
||||
if (!js_ExecuteRegExp(cx, g.re(), str, &i, testGlobal, vp))
|
||||
if (!re.execute(cx, str, &i, testGlobal, vp))
|
||||
return false;
|
||||
if (!Matched(testGlobal, *vp))
|
||||
break;
|
||||
if (!callback(cx, count, data))
|
||||
return false;
|
||||
if (cx->regExpStatics.lastMatch.length == 0)
|
||||
if (!cx->regExpStatics.matched())
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
|
@ -1569,48 +1585,14 @@ DoMatch(JSContext *cx, jsval *vp, JSString *str, const RegExpGuard &g,
|
|||
bool testSingle = !!(flags & TEST_SINGLE_BIT),
|
||||
callbackOnSingle = !!(flags & CALLBACK_ON_SINGLE_BIT);
|
||||
size_t i = 0;
|
||||
if (!js_ExecuteRegExp(cx, g.re(), str, &i, testSingle, vp))
|
||||
if (!re.execute(cx, str, &i, testSingle, vp))
|
||||
return false;
|
||||
if (callbackOnSingle && Matched(testSingle, *vp) &&
|
||||
!callback(cx, 0, data)) {
|
||||
if (callbackOnSingle && Matched(testSingle, *vp) && !callback(cx, 0, data))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* DoMatch will only callback on global matches, hence this function builds
|
||||
* only the "array of matches" returned by match on global regexps.
|
||||
*/
|
||||
static bool
|
||||
MatchCallback(JSContext *cx, size_t count, void *p)
|
||||
{
|
||||
JS_ASSERT(count <= JSVAL_INT_MAX); /* by max string length */
|
||||
|
||||
jsval &arrayval = *static_cast<jsval *>(p);
|
||||
JSObject *arrayobj = JSVAL_TO_OBJECT(arrayval);
|
||||
if (!arrayobj) {
|
||||
arrayobj = js_NewArrayObject(cx, 0, NULL);
|
||||
if (!arrayobj)
|
||||
return false;
|
||||
arrayval = OBJECT_TO_JSVAL(arrayobj);
|
||||
}
|
||||
|
||||
JSString *str = cx->regExpStatics.input;
|
||||
JSSubString &match = cx->regExpStatics.lastMatch;
|
||||
ptrdiff_t off = match.chars - str->chars();
|
||||
JS_ASSERT(off >= 0 && size_t(off) <= str->length());
|
||||
JSString *matchstr = js_NewDependentString(cx, str, off, match.length);
|
||||
if (!matchstr)
|
||||
return false;
|
||||
|
||||
jsval v = STRING_TO_JSVAL(matchstr);
|
||||
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
|
||||
return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v);
|
||||
}
|
||||
|
||||
static bool
|
||||
BuildFlatMatchArray(JSContext *cx, JSString *textstr, const RegExpGuard &g,
|
||||
jsval *vp)
|
||||
|
@ -1633,6 +1615,32 @@ BuildFlatMatchArray(JSContext *cx, JSString *textstr, const RegExpGuard &g,
|
|||
STRING_TO_JSVAL(textstr));
|
||||
}
|
||||
|
||||
/*
|
||||
* DoMatch will only callback on global matches, hence this function builds
|
||||
* only the "array of matches" returned by match on global regexps.
|
||||
*/
|
||||
static bool
|
||||
MatchCallback(JSContext *cx, size_t count, void *p)
|
||||
{
|
||||
JS_ASSERT(count <= JSVAL_INT_MAX); /* by max string length */
|
||||
|
||||
jsval &arrayval = *static_cast<jsval *>(p);
|
||||
JSObject *arrayobj = JSVAL_TO_OBJECT(arrayval);
|
||||
if (!arrayobj) {
|
||||
arrayobj = js_NewArrayObject(cx, 0, NULL);
|
||||
if (!arrayobj)
|
||||
return false;
|
||||
arrayval = OBJECT_TO_JSVAL(arrayobj);
|
||||
}
|
||||
|
||||
jsval v;
|
||||
if (!cx->regExpStatics.createLastMatch(v))
|
||||
return false;
|
||||
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
|
||||
return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
str_match(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
|
@ -1651,8 +1659,8 @@ str_match(JSContext *cx, uintN argc, jsval *vp)
|
|||
if (!DoMatch(cx, vp, str, g, MatchCallback, array.addr(), MATCH_ARGS))
|
||||
return false;
|
||||
|
||||
/* When not global, DoMatch will leave |RegEx.exec()| in *vp. */
|
||||
if (g.re()->flags & JSREG_GLOB)
|
||||
/* When not global, DoMatch will leave |RegExp.exec()| in *vp. */
|
||||
if (g.re()->global())
|
||||
*vp = array.value();
|
||||
return true;
|
||||
}
|
||||
|
@ -1674,11 +1682,11 @@ str_search(JSContext *cx, uintN argc, jsval *vp)
|
|||
return false;
|
||||
|
||||
size_t i = 0;
|
||||
if (!js_ExecuteRegExp(cx, g.re(), str, &i, true, vp))
|
||||
if (!g.re()->execute(cx, str, &i, true, vp))
|
||||
return false;
|
||||
|
||||
if (*vp == JSVAL_TRUE)
|
||||
*vp = INT_TO_JSVAL(cx->regExpStatics.leftContext.length);
|
||||
*vp = INT_TO_JSVAL(cx->regExpStatics.get(0, 0));
|
||||
else
|
||||
*vp = INT_TO_JSVAL(-1);
|
||||
return true;
|
||||
|
@ -1708,44 +1716,44 @@ struct ReplaceData
|
|||
JSCharBuffer cb; /* buffer built during DoMatch */
|
||||
};
|
||||
|
||||
static JSSubString *
|
||||
static bool
|
||||
InterpretDollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData &rdata,
|
||||
size_t *skip)
|
||||
JSSubString &out, size_t *skip)
|
||||
{
|
||||
JSRegExpStatics *res;
|
||||
jschar dc, *cp;
|
||||
uintN num, tmp;
|
||||
|
||||
JS_ASSERT(*dp == '$');
|
||||
|
||||
/* If there is only a dollar, bail now */
|
||||
if (dp + 1 >= ep)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
/* Interpret all Perl match-induced dollar variables. */
|
||||
res = &cx->regExpStatics;
|
||||
dc = dp[1];
|
||||
RegExpStatics &statics = cx->regExpStatics;
|
||||
jschar dc = dp[1];
|
||||
if (JS7_ISDEC(dc)) {
|
||||
/* ECMA-262 Edition 3: 1-9 or 01-99 */
|
||||
num = JS7_UNDEC(dc);
|
||||
if (num > res->parens.length())
|
||||
return NULL;
|
||||
uintN num = JS7_UNDEC(dc);
|
||||
if (num > statics.getParenCount())
|
||||
return false;
|
||||
|
||||
cp = dp + 2;
|
||||
jschar *cp = dp + 2;
|
||||
if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
|
||||
tmp = 10 * num + JS7_UNDEC(dc);
|
||||
if (tmp <= res->parens.length()) {
|
||||
uintN tmp = 10 * num + JS7_UNDEC(dc);
|
||||
if (tmp <= statics.getParenCount()) {
|
||||
cp++;
|
||||
num = tmp;
|
||||
}
|
||||
}
|
||||
if (num == 0)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
/* Adjust num from 1 $n-origin to 0 array-index-origin. */
|
||||
num--;
|
||||
*skip = cp - dp;
|
||||
return (num < res->parens.length()) ? &res->parens[num] : &js_EmptySubString;
|
||||
if (num < statics.getParenCount())
|
||||
statics.getParen(num, out);
|
||||
else
|
||||
out = js_EmptySubString;
|
||||
return true;
|
||||
}
|
||||
|
||||
*skip = 2;
|
||||
|
@ -1753,23 +1761,28 @@ InterpretDollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData &rdata,
|
|||
case '$':
|
||||
rdata.dollarStr.chars = dp;
|
||||
rdata.dollarStr.length = 1;
|
||||
return &rdata.dollarStr;
|
||||
out = rdata.dollarStr;
|
||||
return true;
|
||||
case '&':
|
||||
return &res->lastMatch;
|
||||
statics.getLastMatch(out);
|
||||
return true;
|
||||
case '+':
|
||||
return &res->lastParen;
|
||||
statics.getLastParen(out);
|
||||
return true;
|
||||
case '`':
|
||||
return &res->leftContext;
|
||||
statics.getLeftContext(out);
|
||||
return true;
|
||||
case '\'':
|
||||
return &res->rightContext;
|
||||
statics.getRightContext(out);
|
||||
return true;
|
||||
}
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
PushRegExpSubstr(JSContext *cx, const JSSubString &sub, jsval *&sp)
|
||||
{
|
||||
JSString *whole = cx->regExpStatics.input;
|
||||
JSString *whole = cx->regExpStatics.getInput();
|
||||
size_t off = sub.chars - whole->chars();
|
||||
JSString *str = js_NewDependentString(cx, whole, off, sub.length);
|
||||
if (!str)
|
||||
|
@ -1779,29 +1792,26 @@ PushRegExpSubstr(JSContext *cx, const JSSubString &sub, jsval *&sp)
|
|||
}
|
||||
|
||||
class PreserveRegExpStatics {
|
||||
JSContext *cx;
|
||||
JSRegExpStatics save;
|
||||
JSContext * const cx;
|
||||
RegExpStatics container;
|
||||
|
||||
public:
|
||||
PreserveRegExpStatics(JSContext *cx) : cx(cx), save(cx) {
|
||||
save.copy(cx->regExpStatics);
|
||||
PreserveRegExpStatics(JSContext *cx)
|
||||
: cx(cx), container(cx) {
|
||||
cx->regExpStatics.save(container);
|
||||
container.checkInvariants();
|
||||
}
|
||||
|
||||
~PreserveRegExpStatics() {
|
||||
cx->regExpStatics.copy(save);
|
||||
container.checkInvariants();
|
||||
cx->regExpStatics.checkInvariants();
|
||||
cx->regExpStatics.restore(container);
|
||||
}
|
||||
};
|
||||
|
||||
static bool
|
||||
FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||
{
|
||||
JSString *repstr;
|
||||
size_t replen, skip;
|
||||
jschar *dp, *ep;
|
||||
JSSubString *sub;
|
||||
JSObject *lambda;
|
||||
|
||||
lambda = rdata.lambda;
|
||||
JSObject *lambda = rdata.lambda;
|
||||
if (lambda) {
|
||||
LeaveTrace(cx);
|
||||
|
||||
|
@ -1813,7 +1823,8 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
|||
* For $&, etc., we must create string jsvals from cx->regExpStatics.
|
||||
* We grab up stack space to keep the newborn strings GC-rooted.
|
||||
*/
|
||||
uintN p = rdata.g.re()->parenCount;
|
||||
RegExpStatics &statics = cx->regExpStatics;
|
||||
uintN p = statics.getParenCount();
|
||||
uintN argc = 1 + p + 2;
|
||||
|
||||
if (!rdata.argsPushed() && !cx->stack().pushInvokeArgs(cx, argc, rdata.args))
|
||||
|
@ -1827,21 +1838,16 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
|||
*sp++ = OBJECT_TO_JSVAL(lambda->getParent());
|
||||
|
||||
/* Push $&, $1, $2, ... */
|
||||
if (!PushRegExpSubstr(cx, cx->regExpStatics.lastMatch, sp))
|
||||
if (!statics.createLastMatch(*sp++))
|
||||
return false;
|
||||
|
||||
uintN i = 0;
|
||||
for (uintN n = cx->regExpStatics.parens.length(); i < n; i++) {
|
||||
if (!PushRegExpSubstr(cx, cx->regExpStatics.parens[i], sp))
|
||||
for (size_t i = 0; i < statics.getParenCount(); ++i) {
|
||||
if (!statics.createParen(i, *sp++))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Make sure to push undefined for any unmatched parens. */
|
||||
for (; i < p; i++)
|
||||
*sp++ = JSVAL_VOID;
|
||||
|
||||
/* Push match index and input string. */
|
||||
*sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length);
|
||||
*sp++ = INT_TO_JSVAL((jsint)statics.get(0, 0));
|
||||
*sp++ = STRING_TO_JSVAL(rdata.str);
|
||||
|
||||
if (!js_Invoke(cx, rdata.args, 0))
|
||||
|
@ -1852,7 +1858,7 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
|||
* created by this js_ValueToString that would otherwise be GC-
|
||||
* able, until we use rdata.repstr in DoReplace.
|
||||
*/
|
||||
repstr = js_ValueToString(cx, *rdata.args.getvp());
|
||||
JSString *repstr = js_ValueToString(cx, *rdata.args.getvp());
|
||||
if (!repstr)
|
||||
return false;
|
||||
|
||||
|
@ -1862,17 +1868,17 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
|||
return true;
|
||||
}
|
||||
|
||||
repstr = rdata.repstr;
|
||||
replen = repstr->length();
|
||||
for (dp = rdata.dollar, ep = rdata.dollarEnd; dp;
|
||||
dp = js_strchr_limit(dp, '$', ep)) {
|
||||
sub = InterpretDollar(cx, dp, ep, rdata, &skip);
|
||||
if (sub) {
|
||||
replen += sub->length - skip;
|
||||
JSString *repstr = rdata.repstr;
|
||||
size_t replen = repstr->length();
|
||||
for (jschar *dp = rdata.dollar, *ep = rdata.dollarEnd; dp; dp = js_strchr_limit(dp, '$', ep)) {
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(cx, dp, ep, rdata, sub, &skip)) {
|
||||
replen += sub.length - skip;
|
||||
dp += skip;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
dp++;
|
||||
}
|
||||
}
|
||||
*sizep = replen;
|
||||
return true;
|
||||
|
@ -1881,23 +1887,19 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
|||
static void
|
||||
DoReplace(JSContext *cx, ReplaceData &rdata, jschar *chars)
|
||||
{
|
||||
JSString *repstr;
|
||||
jschar *bp, *cp, *dp, *ep;
|
||||
size_t len, skip;
|
||||
JSSubString *sub;
|
||||
|
||||
repstr = rdata.repstr;
|
||||
jschar *bp, *cp;
|
||||
JSString *repstr = rdata.repstr;
|
||||
bp = cp = repstr->chars();
|
||||
for (dp = rdata.dollar, ep = rdata.dollarEnd; dp;
|
||||
dp = js_strchr_limit(dp, '$', ep)) {
|
||||
len = dp - cp;
|
||||
for (jschar *dp = rdata.dollar, *ep = rdata.dollarEnd; dp; dp = js_strchr_limit(dp, '$', ep)) {
|
||||
size_t len = dp - cp;
|
||||
js_strncpy(chars, cp, len);
|
||||
chars += len;
|
||||
cp = dp;
|
||||
sub = InterpretDollar(cx, dp, ep, rdata, &skip);
|
||||
if (sub) {
|
||||
len = sub->length;
|
||||
js_strncpy(chars, sub->chars, len);
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(cx, dp, ep, rdata, sub, &skip)) {
|
||||
len = sub.length;
|
||||
js_strncpy(chars, sub.chars, len);
|
||||
chars += len;
|
||||
cp += skip;
|
||||
dp += skip;
|
||||
|
@ -1912,14 +1914,14 @@ static bool
|
|||
ReplaceCallback(JSContext *cx, size_t count, void *p)
|
||||
{
|
||||
ReplaceData &rdata = *static_cast<ReplaceData *>(p);
|
||||
RegExpStatics &statics = cx->regExpStatics;
|
||||
|
||||
rdata.calledBack = true;
|
||||
JSString *str = rdata.str;
|
||||
size_t leftoff = rdata.leftIndex;
|
||||
const jschar *left = str->chars() + leftoff;
|
||||
size_t leftlen = cx->regExpStatics.lastMatch.chars - left;
|
||||
rdata.leftIndex = cx->regExpStatics.lastMatch.chars - str->chars();
|
||||
rdata.leftIndex += cx->regExpStatics.lastMatch.length;
|
||||
size_t leftlen = statics.get(0, 0) - leftoff;
|
||||
rdata.leftIndex = statics.get(0, 1);
|
||||
|
||||
size_t replen = 0; /* silence 'unused' warning */
|
||||
if (!FindReplaceLength(cx, rdata, &replen))
|
||||
|
@ -2012,8 +2014,9 @@ str_replace(JSContext *cx, uintN argc, jsval *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
JSSubString *sub = &cx->regExpStatics.rightContext;
|
||||
if (!rdata.cb.append(sub->chars, sub->length))
|
||||
JSSubString sub;
|
||||
cx->regExpStatics.getRightContext(sub);
|
||||
if (!rdata.cb.append(sub.chars, sub.length))
|
||||
return false;
|
||||
|
||||
JSString *retstr = js_NewStringFromCharBuffer(cx, rdata.cb);
|
||||
|
@ -2034,8 +2037,7 @@ str_replace(JSContext *cx, uintN argc, jsval *vp)
|
|||
* separator occurrence if found, or str->length if no separator is found.
|
||||
*/
|
||||
static jsint
|
||||
find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
|
||||
JSSubString *sep)
|
||||
find_split(JSContext *cx, JSString *str, js::RegExp *re, jsint *ip, JSSubString *sep)
|
||||
{
|
||||
jsint i;
|
||||
size_t length;
|
||||
|
@ -2071,7 +2073,7 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
|
|||
again:
|
||||
/* JS1.2 deviated from Perl by never matching at end of string. */
|
||||
index = (size_t)i;
|
||||
if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval))
|
||||
if (!re->execute(cx, str, &index, true, &rval))
|
||||
return -2;
|
||||
if (rval != JSVAL_TRUE) {
|
||||
/* Mismatch: ensure our caller advances i past end of string. */
|
||||
|
@ -2079,7 +2081,8 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
|
|||
return length;
|
||||
}
|
||||
i = (jsint)index;
|
||||
*sep = cx->regExpStatics.lastMatch;
|
||||
JS_ASSERT(sep);
|
||||
cx->regExpStatics.getLastMatch(*sep);
|
||||
if (sep->length == 0) {
|
||||
/*
|
||||
* Empty string match: never split on an empty match at the start
|
||||
|
@ -2142,10 +2145,10 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
JSRegExp *re;
|
||||
RegExp *re;
|
||||
JSSubString *sep, tmp;
|
||||
if (VALUE_IS_REGEXP(cx, vp[2])) {
|
||||
re = (JSRegExp *) JSVAL_TO_OBJECT(vp[2])->getPrivate();
|
||||
re = static_cast<RegExp *>(JSVAL_TO_OBJECT(vp[2])->getPrivate());
|
||||
sep = &tmp;
|
||||
|
||||
/* Set a magic value so we can detect a successful re match. */
|
||||
|
@ -2199,12 +2202,13 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
|
|||
* substring that was delimited.
|
||||
*/
|
||||
if (re && sep->chars) {
|
||||
JSRegExpStatics *res = &cx->regExpStatics;
|
||||
for (uintN num = 0; num < res->parens.length(); num++) {
|
||||
RegExpStatics &statics = cx->regExpStatics;
|
||||
for (uintN num = 0; num < statics.getParenCount(); num++) {
|
||||
if (limited && len >= limit)
|
||||
break;
|
||||
JSSubString *parsub = &res->parens[num];
|
||||
sub = js_NewStringCopyN(cx, parsub->chars, parsub->length);
|
||||
JSSubString parsub;
|
||||
statics.getParen(num, parsub);
|
||||
sub = js_NewStringCopyN(cx, parsub.chars, parsub.length);
|
||||
if (!sub || !splits.append(sub))
|
||||
return false;
|
||||
len++;
|
||||
|
|
|
@ -307,6 +307,9 @@ js_GetStringChars(JSContext *cx, JSString *str);
|
|||
extern JSString * JS_FASTCALL
|
||||
js_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
|
||||
|
||||
extern JSString * JS_FASTCALL
|
||||
js_ConcatStringsZ(JSContext *cx, const char *left, JSString *right);
|
||||
|
||||
extern const jschar *
|
||||
js_UndependString(JSContext *cx, JSString *str);
|
||||
|
||||
|
|
|
@ -405,6 +405,25 @@ PodArrayZero(T (&t)[N])
|
|||
memset(t, 0, N * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename InputIterT, typename ValueT>
|
||||
InputIterT
|
||||
find(InputIterT begin, InputIterT end, const ValueT &target)
|
||||
{
|
||||
for (; begin != end; ++begin) {
|
||||
if (*begin == target)
|
||||
return begin;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename InputIterT, typename CallableT>
|
||||
void
|
||||
for_each(InputIterT begin, InputIterT end, CallableT f)
|
||||
{
|
||||
for (; begin != end; ++begin)
|
||||
f(*begin);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jstl_h_ */
|
||||
|
|
|
@ -377,6 +377,7 @@ class Vector : AllocPolicy
|
|||
bool appendN(const T &t, size_t n);
|
||||
template <class U> bool append(const U *begin, const U *end);
|
||||
template <class U> bool append(const U *begin, size_t length);
|
||||
template <class U, size_t O, class BP> bool append(const Vector<U,O,BP> &other);
|
||||
|
||||
void popBack();
|
||||
|
||||
|
@ -396,6 +397,18 @@ class Vector : AllocPolicy
|
|||
* passed array.
|
||||
*/
|
||||
void replaceRawBuffer(T *p, size_t length);
|
||||
|
||||
/*
|
||||
* Places |val| at position |p|, shifting existing elements
|
||||
* from |p| onward one position higher.
|
||||
*/
|
||||
bool insert(T *p, const T &val);
|
||||
|
||||
/*
|
||||
* Removes the element |t|, which must fall in the bounds [begin, end),
|
||||
* shifting existing elements from |t + 1| onward one position lower.
|
||||
*/
|
||||
void erase(T *t);
|
||||
};
|
||||
|
||||
/* Helper functions */
|
||||
|
@ -658,6 +671,36 @@ Vector<T,N,AP>::appendN(const T &t, size_t needed)
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
inline bool
|
||||
Vector<T,N,AP>::insert(T *p, const T &val)
|
||||
{
|
||||
size_t pos = p - begin();
|
||||
JS_ASSERT(pos <= length());
|
||||
size_t oldLength = length();
|
||||
if (pos == oldLength)
|
||||
return append(val);
|
||||
if (!append(back())) /* Dup the last element. */
|
||||
return false;
|
||||
for (size_t i = oldLength; i > pos; --i)
|
||||
(*this)[i] = (*this)[i - 1];
|
||||
(*this)[pos] = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
inline void
|
||||
Vector<T,N,AP>::erase(T *it)
|
||||
{
|
||||
JS_ASSERT(begin() <= it && it < end());
|
||||
while (it + 1 != end()) {
|
||||
*it = *(it + 1);
|
||||
++it;
|
||||
}
|
||||
popBack();
|
||||
}
|
||||
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
template <class U>
|
||||
inline bool
|
||||
|
@ -688,6 +731,14 @@ Vector<T,N,AP>::append(const U *insBegin, const U *insEnd)
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
template <class U, size_t O, class BP>
|
||||
inline bool
|
||||
Vector<T,N,AP>::append(const Vector<U,O,BP> &other)
|
||||
{
|
||||
return append(other.begin(), other.end());
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
template <class U>
|
||||
inline bool
|
||||
|
|
|
@ -157,7 +157,7 @@ class AutoCompartment
|
|||
private:
|
||||
LazilyConstructed<ExecuteFrameGuard> frame;
|
||||
JSFrameRegs regs;
|
||||
JSRegExpStatics statics;
|
||||
RegExpStatics statics;
|
||||
AutoValueRooter input;
|
||||
|
||||
public:
|
||||
|
|
|
@ -40,7 +40,7 @@ var gTestfile = 'regress-332472.js';
|
|||
var BUGNUMBER = 332472;
|
||||
var summary = 'new RegExp() ignores string boundaries when throwing exceptions';
|
||||
var actual = '';
|
||||
var expect = 'SyntaxError: invalid quantifier ?asdf';
|
||||
var expect = 'SyntaxError: invalid quantifier';
|
||||
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
|
|
@ -43,7 +43,7 @@ script regress-325269.js
|
|||
script regress-327608.js
|
||||
script regress-328443.js
|
||||
script regress-328556.js
|
||||
script regress-330569.js
|
||||
skip script regress-330569.js # Yarr doesn't bail on complex regexps.
|
||||
script regress-333541.js
|
||||
skip script regress-335700.js # bug xxx - reftest hang, BigO
|
||||
skip-if(!xulRuntime.shell) script regress-336409-1.js # no results reported.
|
||||
|
@ -71,7 +71,7 @@ skip script regress-350531.js # slow
|
|||
script regress-351102-01.js
|
||||
script regress-351102-02.js
|
||||
script regress-351102-06.js
|
||||
script regress-351448.js
|
||||
skip script regress-351448.js # Yarr doesn't have the same complexity errors at execution time.
|
||||
script regress-351463-01.js
|
||||
script regress-351973.js
|
||||
script regress-352261.js
|
||||
|
|
|
@ -24,3 +24,4 @@ script regress-566914.js
|
|||
script regress-567152.js
|
||||
script regress-569306.js
|
||||
script regress-571014.js
|
||||
script regress-yarr-regexp.js
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
function toSource(o) { return o === null ? "null" : o.toSource(); }
|
||||
|
||||
var gcgcz = /((?:.)+)((?:.)*)/; /* Greedy capture, greedy capture zero. */
|
||||
reportCompare(["a", "a", ""].toSource(), gcgcz.exec("a").toSource());
|
||||
reportCompare(["ab", "ab", ""].toSource(), gcgcz.exec("ab").toSource());
|
||||
reportCompare(["abc", "abc", ""].toSource(), gcgcz.exec("abc").toSource());
|
||||
|
||||
reportCompare(["a", ""].toSource(), toSource(/((?:)*?)a/.exec("a")));
|
||||
reportCompare(["a", ""].toSource(), toSource(/((?:.)*?)a/.exec("a")));
|
||||
reportCompare(["a", ""].toSource(), toSource(/a((?:.)*)/.exec("a")));
|
||||
|
||||
reportCompare(["B", "B"].toSource(), toSource(/([A-Z])/.exec("fooBar")));
|
|
@ -612,7 +612,7 @@ public:
|
|||
|
||||
private:
|
||||
JSContext *cx;
|
||||
JSRegExpStatics statics;
|
||||
js::RegExpStatics statics;
|
||||
js::AutoValueRooter tvr;
|
||||
uint32 options;
|
||||
JSStackFrame *fp;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
INCLUDES := -I. -Iyarr -Iwtf -I../assembler/assembler -I../assembler
|
||||
|
||||
all:
|
||||
$(CXX) -g3 -c $(INCLUDES) yarr/*.cpp
|
||||
$(CXX) -g3 $(INCLUDES) TestMain.cpp *.o
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* June 12, 2009.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Leary <cdleary@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jswtfbridge_h__
|
||||
#define jswtfbridge_h__
|
||||
|
||||
/*
|
||||
* The JS/WTF Bridge to Bona-fide Quality.
|
||||
*/
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
#include "jsstr.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jstl.h"
|
||||
|
||||
typedef jschar UChar;
|
||||
typedef JSString UString;
|
||||
|
||||
template <typename T>
|
||||
class ValueDeleter
|
||||
{
|
||||
public:
|
||||
void operator()(T &t) { delete t; }
|
||||
};
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
static inline void
|
||||
deleteAllValues(js::Vector<T,N,AP> &vector)
|
||||
{
|
||||
js::for_each(vector.begin(), vector.end(), ValueDeleter<T>());
|
||||
}
|
||||
|
||||
class Unicode {
|
||||
public:
|
||||
static UChar toUpper(UChar c) { return JS_TOUPPER(c); }
|
||||
static UChar toLower(UChar c) { return JS_TOLOWER(c); }
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
Originally written by: Philip Hazel
|
||||
Email local part: ph10
|
||||
Email domain: cam.ac.uk
|
||||
|
||||
University of Cambridge Computing Service,
|
||||
Cambridge, England. Phone: +44 1223 334714.
|
||||
|
||||
Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
|
||||
|
||||
Adapted for JavaScriptCore and WebKit by Apple Inc.
|
||||
|
||||
Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
|
|
@ -0,0 +1,35 @@
|
|||
PCRE is a library of functions to support regular expressions whose syntax
|
||||
and semantics are as close as possible to those of the Perl 5 language.
|
||||
|
||||
This is JavaScriptCore's variant of the PCRE library. While this library
|
||||
started out as a copy of PCRE, many of the features of PCRE have been
|
||||
removed.
|
||||
|
||||
Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the name of Apple
|
||||
Inc. nor the names of their contributors may be used to endorse or
|
||||
promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
|
@ -0,0 +1,96 @@
|
|||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* This file is automatically written by the dftables auxiliary
|
||||
program. If you edit it by hand, you might like to edit the Makefile to
|
||||
prevent its ever being regenerated.
|
||||
|
||||
This file contains the default tables for characters with codes less than
|
||||
128 (ASCII characters). These tables are used when no external tables are
|
||||
passed to PCRE. */
|
||||
|
||||
const unsigned char jsc_pcre_default_tables[480] = {
|
||||
|
||||
/* This table is a lower casing table. */
|
||||
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
|
||||
/* This table is a case flipping table. */
|
||||
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
|
||||
/* This table contains bit maps for various character classes.
|
||||
Each map is 32 bytes long and the bits run from the least
|
||||
significant end of each byte. The classes are: space, digit, word. */
|
||||
|
||||
0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
|
||||
0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
/* This table identifies various classes of character by individual bits:
|
||||
0x01 white space character
|
||||
0x08 hexadecimal digit
|
||||
0x10 alphanumeric or '_'
|
||||
*/
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0- 7 */
|
||||
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 8- 15 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16- 23 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24- 31 */
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* - ' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ( - / */
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 0 - 7 */
|
||||
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 - ? */
|
||||
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, /* @ - G */
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* H - O */
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* P - W */
|
||||
0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, /* X - _ */
|
||||
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, /* ` - g */
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* h - o */
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* p - w */
|
||||
0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /* x -127 */
|
||||
|
||||
|
||||
/* End of chartables.c */
|
|
@ -0,0 +1,273 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# This is JavaScriptCore's variant of the PCRE library. While this library
|
||||
# started out as a copy of PCRE, many of the features of PCRE have been
|
||||
# removed. This library now supports only the regular expression features
|
||||
# required by the JavaScript language specification, and has only the functions
|
||||
# needed by JavaScriptCore and the rest of WebKit.
|
||||
#
|
||||
# Originally written by Philip Hazel
|
||||
# Copyright (c) 1997-2006 University of Cambridge
|
||||
# Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * 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.
|
||||
#
|
||||
# * Neither the name of the University of Cambridge nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# This is a freestanding support program to generate a file containing
|
||||
# character tables. The tables are built according to the default C
|
||||
# locale.
|
||||
|
||||
use strict;
|
||||
|
||||
use File::Basename;
|
||||
use File::Spec;
|
||||
use File::Temp qw(tempfile);
|
||||
use Getopt::Long;
|
||||
|
||||
sub readHeaderValues();
|
||||
|
||||
my %pcre_internal;
|
||||
|
||||
if (scalar(@ARGV) < 1) {
|
||||
print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $outputFile;
|
||||
my $preprocessor;
|
||||
GetOptions('preprocessor=s' => \$preprocessor);
|
||||
if (not $preprocessor) {
|
||||
$preprocessor = "cpp";
|
||||
}
|
||||
|
||||
$outputFile = $ARGV[0];
|
||||
die('Must specify output file.') unless defined($outputFile);
|
||||
|
||||
readHeaderValues();
|
||||
|
||||
open(OUT, ">", $outputFile) or die "$!";
|
||||
binmode(OUT);
|
||||
|
||||
printf(OUT
|
||||
"/*************************************************\n" .
|
||||
"* Perl-Compatible Regular Expressions *\n" .
|
||||
"*************************************************/\n\n" .
|
||||
"/* This file is automatically written by the dftables auxiliary \n" .
|
||||
"program. If you edit it by hand, you might like to edit the Makefile to \n" .
|
||||
"prevent its ever being regenerated.\n\n");
|
||||
printf(OUT
|
||||
"This file contains the default tables for characters with codes less than\n" .
|
||||
"128 (ASCII characters). These tables are used when no external tables are\n" .
|
||||
"passed to PCRE. */\n\n" .
|
||||
"const unsigned char jsc_pcre_default_tables[%d] = {\n\n" .
|
||||
"/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length});
|
||||
|
||||
if ($pcre_internal{lcc_offset} != 0) {
|
||||
die "lcc_offset != 0";
|
||||
}
|
||||
|
||||
printf(OUT " ");
|
||||
for (my $i = 0; $i < 128; $i++) {
|
||||
if (($i & 7) == 0 && $i != 0) {
|
||||
printf(OUT "\n ");
|
||||
}
|
||||
printf(OUT "0x%02X", ord(lc(chr($i))));
|
||||
if ($i != 127) {
|
||||
printf(OUT ", ");
|
||||
}
|
||||
}
|
||||
printf(OUT ",\n\n");
|
||||
|
||||
printf(OUT "/* This table is a case flipping table. */\n\n");
|
||||
|
||||
if ($pcre_internal{fcc_offset} != 128) {
|
||||
die "fcc_offset != 128";
|
||||
}
|
||||
|
||||
printf(OUT " ");
|
||||
for (my $i = 0; $i < 128; $i++) {
|
||||
if (($i & 7) == 0 && $i != 0) {
|
||||
printf(OUT "\n ");
|
||||
}
|
||||
my $c = chr($i);
|
||||
printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c)));
|
||||
if ($i != 127) {
|
||||
printf(OUT ", ");
|
||||
}
|
||||
}
|
||||
printf(OUT ",\n\n");
|
||||
|
||||
printf(OUT
|
||||
"/* This table contains bit maps for various character classes.\n" .
|
||||
"Each map is 32 bytes long and the bits run from the least\n" .
|
||||
"significant end of each byte. The classes are: space, digit, word. */\n\n");
|
||||
|
||||
if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) {
|
||||
die "cbits_offset != fcc_offset + 128";
|
||||
}
|
||||
|
||||
my @cbit_table = (0) x $pcre_internal{cbit_length};
|
||||
for (my $i = ord('0'); $i <= ord('9'); $i++) {
|
||||
$cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7);
|
||||
}
|
||||
$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7);
|
||||
for (my $i = 0; $i < 128; $i++) {
|
||||
my $c = chr($i);
|
||||
if ($c =~ /[[:alnum:]]/) {
|
||||
$cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7);
|
||||
}
|
||||
if ($c =~ /[[:space:]]/) {
|
||||
$cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7);
|
||||
}
|
||||
}
|
||||
|
||||
printf(OUT " ");
|
||||
for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) {
|
||||
if (($i & 7) == 0 && $i != 0) {
|
||||
if (($i & 31) == 0) {
|
||||
printf(OUT "\n");
|
||||
}
|
||||
printf(OUT "\n ");
|
||||
}
|
||||
printf(OUT "0x%02X", $cbit_table[$i]);
|
||||
if ($i != $pcre_internal{cbit_length} - 1) {
|
||||
printf(OUT ", ");
|
||||
}
|
||||
}
|
||||
printf(OUT ",\n\n");
|
||||
|
||||
printf(OUT
|
||||
"/* This table identifies various classes of character by individual bits:\n" .
|
||||
" 0x%02x white space character\n" .
|
||||
" 0x%02x hexadecimal digit\n" .
|
||||
" 0x%02x alphanumeric or '_'\n*/\n\n",
|
||||
$pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word});
|
||||
|
||||
if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) {
|
||||
die "ctypes_offset != cbits_offset + cbit_length";
|
||||
}
|
||||
|
||||
printf(OUT " ");
|
||||
for (my $i = 0; $i < 128; $i++) {
|
||||
my $x = 0;
|
||||
my $c = chr($i);
|
||||
if ($c =~ /[[:space:]]/) {
|
||||
$x += $pcre_internal{ctype_space};
|
||||
}
|
||||
if ($c =~ /[[:xdigit:]]/) {
|
||||
$x += $pcre_internal{ctype_xdigit};
|
||||
}
|
||||
if ($c =~ /[[:alnum:]_]/) {
|
||||
$x += $pcre_internal{ctype_word};
|
||||
}
|
||||
printf(OUT "0x%02X", $x);
|
||||
if ($i != 127) {
|
||||
printf(OUT ", ");
|
||||
} else {
|
||||
printf(OUT "};");
|
||||
}
|
||||
if (($i & 7) == 7) {
|
||||
printf(OUT " /* ");
|
||||
my $d = chr($i - 7);
|
||||
if ($d =~ /[[:print:]]/) {
|
||||
printf(OUT " %c -", $i - 7);
|
||||
} else {
|
||||
printf(OUT "%3d-", $i - 7);
|
||||
}
|
||||
if ($c =~ m/[[:print:]]/) {
|
||||
printf(OUT " %c ", $i);
|
||||
} else {
|
||||
printf(OUT "%3d", $i);
|
||||
}
|
||||
printf(OUT " */\n");
|
||||
if ($i != 127) {
|
||||
printf(OUT " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) {
|
||||
die "tables_length != ctypes_offset + 128";
|
||||
}
|
||||
|
||||
printf(OUT "\n\n/* End of chartables.c */\n");
|
||||
|
||||
close(OUT);
|
||||
|
||||
exit 0;
|
||||
|
||||
sub readHeaderValues()
|
||||
{
|
||||
my @variables = qw(
|
||||
cbit_digit
|
||||
cbit_length
|
||||
cbit_space
|
||||
cbit_word
|
||||
cbits_offset
|
||||
ctype_space
|
||||
ctype_word
|
||||
ctype_xdigit
|
||||
ctypes_offset
|
||||
fcc_offset
|
||||
lcc_offset
|
||||
tables_length
|
||||
);
|
||||
|
||||
local $/ = undef;
|
||||
|
||||
my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h");
|
||||
|
||||
my ($fh, $tempFile) = tempfile(
|
||||
basename($0) . "-XXXXXXXX",
|
||||
DIR => File::Spec->tmpdir(),
|
||||
SUFFIX => ".in",
|
||||
UNLINK => 0,
|
||||
);
|
||||
|
||||
print $fh "#define DFTABLES\n\n";
|
||||
|
||||
open(HEADER, "<", $headerPath) or die "$!";
|
||||
print $fh <HEADER>;
|
||||
close(HEADER);
|
||||
|
||||
print $fh "\n\n";
|
||||
|
||||
for my $v (@variables) {
|
||||
print $fh "\$pcre_internal{\"$v\"} = $v;\n";
|
||||
}
|
||||
|
||||
close($fh);
|
||||
|
||||
open(CPP, "$preprocessor \"$tempFile\" |") or die "$!";
|
||||
my $content = <CPP>;
|
||||
close(CPP);
|
||||
|
||||
eval $content;
|
||||
die "$@" if $@;
|
||||
unlink $tempFile;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* This is the public header file for JavaScriptCore's variant of the PCRE
|
||||
library. While this library started out as a copy of PCRE, many of the
|
||||
features of PCRE have been removed. This library now supports only the
|
||||
regular expression features required by the JavaScript language
|
||||
specification, and has only the functions needed by JavaScriptCore and the
|
||||
rest of WebKit.
|
||||
|
||||
Copyright (c) 1997-2005 University of Cambridge
|
||||
Copyright (C) 2002, 2004, 2006, 2007 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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE.
|
||||
|
||||
#ifndef JSRegExp_h
|
||||
#define JSRegExp_h
|
||||
|
||||
#include "yarr/jswtfbridge.h"
|
||||
|
||||
struct JSRegExp;
|
||||
struct JSContext;
|
||||
|
||||
enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase };
|
||||
enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline };
|
||||
|
||||
/* jsRegExpExecute error codes */
|
||||
const int JSRegExpErrorNoMatch = -1;
|
||||
const int JSRegExpErrorHitLimit = -2;
|
||||
const int JSRegExpErrorNoMemory = -3;
|
||||
const int JSRegExpErrorInternal = -4;
|
||||
|
||||
JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
|
||||
JSRegExpIgnoreCaseOption, JSRegExpMultilineOption,
|
||||
unsigned* numSubpatterns, int *error);
|
||||
|
||||
int jsRegExpExecute(JSContext *, const JSRegExp*,
|
||||
const UChar* subject, int subjectLength, int startOffset,
|
||||
int* offsetsVector, int offsetsVectorLength);
|
||||
|
||||
void jsRegExpFree(JSRegExp*);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
# Perl Compatible Regular Expressions - Qt4 build info
|
||||
VPATH += $$PWD
|
||||
INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp
|
||||
DEPENDPATH += $$PWD
|
||||
|
||||
SOURCES += \
|
||||
pcre_compile.cpp \
|
||||
pcre_exec.cpp \
|
||||
pcre_tables.cpp \
|
||||
pcre_ucp_searchfuncs.cpp \
|
||||
pcre_xclass.cpp
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,434 @@
|
|||
/* This is JavaScriptCore's variant of the PCRE library. While this library
|
||||
started out as a copy of PCRE, many of the features of PCRE have been
|
||||
removed. This library now supports only the regular expression features
|
||||
required by the JavaScript language specification, and has only the functions
|
||||
needed by JavaScriptCore and the rest of WebKit.
|
||||
|
||||
Originally written by Philip Hazel
|
||||
Copyright (c) 1997-2006 University of Cambridge
|
||||
Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* This header contains definitions that are shared between the different
|
||||
modules, but which are not relevant to the exported API. This includes some
|
||||
functions whose names all begin with "_pcre_". */
|
||||
|
||||
#ifndef PCRE_INTERNAL_H
|
||||
#define PCRE_INTERNAL_H
|
||||
|
||||
/* Bit definitions for entries in the pcre_ctypes table. */
|
||||
|
||||
#define ctype_space 0x01
|
||||
#define ctype_xdigit 0x08
|
||||
#define ctype_word 0x10 /* alphameric or '_' */
|
||||
|
||||
/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
|
||||
of bits for a class map. Some classes are built by combining these tables. */
|
||||
|
||||
#define cbit_space 0 /* \s */
|
||||
#define cbit_digit 32 /* \d */
|
||||
#define cbit_word 64 /* \w */
|
||||
#define cbit_length 96 /* Length of the cbits table */
|
||||
|
||||
/* Offsets of the various tables from the base tables pointer, and
|
||||
total length. */
|
||||
|
||||
#define lcc_offset 0
|
||||
#define fcc_offset 128
|
||||
#define cbits_offset 256
|
||||
#define ctypes_offset (cbits_offset + cbit_length)
|
||||
#define tables_length (ctypes_offset + 128)
|
||||
|
||||
#ifndef DFTABLES
|
||||
|
||||
#include "pcre.h"
|
||||
|
||||
/* The value of LINK_SIZE determines the number of bytes used to store links as
|
||||
offsets within the compiled regex. The default is 2, which allows for compiled
|
||||
patterns up to 64K long. */
|
||||
|
||||
#define LINK_SIZE 3
|
||||
|
||||
/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
|
||||
inline, and there are *still* stupid compilers about that don't like indented
|
||||
pre-processor statements, or at least there were when I first wrote this. After
|
||||
all, it had only been about 10 years then... */
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPRINTF(p) /*printf p; fflush(stdout);*/
|
||||
#else
|
||||
#define DPRINTF(p) /*nothing*/
|
||||
#endif
|
||||
|
||||
/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored
|
||||
in big-endian order) by default. These are used, for example, to link from the
|
||||
start of a subpattern to its alternatives and its end. The use of 2 bytes per
|
||||
offset limits the size of the compiled regex to around 64K, which is big enough
|
||||
for almost everybody. However, I received a request for an even bigger limit.
|
||||
For this reason, and also to make the code easier to maintain, the storing and
|
||||
loading of offsets from the byte string is now handled by the functions that are
|
||||
defined here. */
|
||||
|
||||
/* PCRE uses some other 2-byte quantities that do not change when the size of
|
||||
offsets changes. There are used for repeat counts and for other things such as
|
||||
capturing parenthesis numbers in back references. */
|
||||
|
||||
static inline void put2ByteValue(unsigned char* opcodePtr, int value)
|
||||
{
|
||||
JS_ASSERT(value >= 0 && value <= 0xFFFF);
|
||||
opcodePtr[0] = value >> 8;
|
||||
opcodePtr[1] = value;
|
||||
}
|
||||
|
||||
static inline void put3ByteValue(unsigned char* opcodePtr, int value)
|
||||
{
|
||||
JS_ASSERT(value >= 0 && value <= 0xFFFFFF);
|
||||
opcodePtr[0] = value >> 16;
|
||||
opcodePtr[1] = value >> 8;
|
||||
opcodePtr[2] = value;
|
||||
}
|
||||
|
||||
static inline int get2ByteValue(const unsigned char* opcodePtr)
|
||||
{
|
||||
return (opcodePtr[0] << 8) | opcodePtr[1];
|
||||
}
|
||||
|
||||
static inline int get3ByteValue(const unsigned char* opcodePtr)
|
||||
{
|
||||
return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2];
|
||||
}
|
||||
|
||||
static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value)
|
||||
{
|
||||
put2ByteValue(opcodePtr, value);
|
||||
opcodePtr += 2;
|
||||
}
|
||||
|
||||
static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value)
|
||||
{
|
||||
put3ByteValue(opcodePtr, value);
|
||||
opcodePtr += 3;
|
||||
}
|
||||
|
||||
static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value)
|
||||
{
|
||||
#if LINK_SIZE == 3
|
||||
put3ByteValue(opcodePtr, value);
|
||||
#elif LINK_SIZE == 2
|
||||
put2ByteValue(opcodePtr, value);
|
||||
#else
|
||||
# error LINK_SIZE not supported.
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int getLinkValueAllowZero(const unsigned char* opcodePtr)
|
||||
{
|
||||
#if LINK_SIZE == 3
|
||||
return get3ByteValue(opcodePtr);
|
||||
#elif LINK_SIZE == 2
|
||||
return get2ByteValue(opcodePtr);
|
||||
#else
|
||||
# error LINK_SIZE not supported.
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC.
|
||||
JS_STATIC_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE)));
|
||||
|
||||
static inline void putLinkValue(unsigned char* opcodePtr, int value)
|
||||
{
|
||||
JS_ASSERT(value);
|
||||
putLinkValueAllowZero(opcodePtr, value);
|
||||
}
|
||||
|
||||
static inline int getLinkValue(const unsigned char* opcodePtr)
|
||||
{
|
||||
int value = getLinkValueAllowZero(opcodePtr);
|
||||
JS_ASSERT(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value)
|
||||
{
|
||||
putLinkValue(opcodePtr, value);
|
||||
opcodePtr += LINK_SIZE;
|
||||
}
|
||||
|
||||
static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value)
|
||||
{
|
||||
putLinkValueAllowZero(opcodePtr, value);
|
||||
opcodePtr += LINK_SIZE;
|
||||
}
|
||||
|
||||
// FIXME: These are really more of a "compiled regexp state" than "regexp options"
|
||||
enum RegExpOptions {
|
||||
UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */
|
||||
UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */
|
||||
UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */
|
||||
IsAnchoredOption = 0x02000000, /* can't use partial with this regex */
|
||||
IgnoreCaseOption = 0x00000001,
|
||||
MatchAcrossMultipleLinesOption = 0x00000002
|
||||
};
|
||||
|
||||
/* Flags added to firstByte or reqByte; a "non-literal" item is either a
|
||||
variable-length repeat, or a anything other than literal characters. */
|
||||
|
||||
#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */
|
||||
#define REQ_VARY 0x0200 /* reqByte followed non-literal item */
|
||||
|
||||
/* Miscellaneous definitions */
|
||||
|
||||
/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
|
||||
contain UTF-8 characters with values greater than 255. */
|
||||
|
||||
#define XCL_NOT 0x01 /* Flag: this is a negative class */
|
||||
#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */
|
||||
|
||||
#define XCL_END 0 /* Marks end of individual items */
|
||||
#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */
|
||||
#define XCL_RANGE 2 /* A range (two multibyte chars) follows */
|
||||
|
||||
/* These are escaped items that aren't just an encoding of a particular data
|
||||
value such as \n. They must have non-zero values, as check_escape() returns
|
||||
their negation. Also, they must appear in the same order as in the opcode
|
||||
definitions below, up to ESC_w. The final one must be
|
||||
ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two
|
||||
tests in the code for an escape > ESC_b and <= ESC_w to
|
||||
detect the types that may be repeated. These are the types that consume
|
||||
characters. If any new escapes are put in between that don't consume a
|
||||
character, that code will have to change. */
|
||||
|
||||
enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF };
|
||||
|
||||
/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
|
||||
that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
|
||||
OP_EOD must correspond in order to the list of escapes immediately above.
|
||||
Note that whenever this list is updated, the two macro definitions that follow
|
||||
must also be updated to match. */
|
||||
|
||||
#define FOR_EACH_OPCODE(macro) \
|
||||
macro(END) \
|
||||
\
|
||||
, macro(NOT_WORD_BOUNDARY) \
|
||||
, macro(WORD_BOUNDARY) \
|
||||
, macro(NOT_DIGIT) \
|
||||
, macro(DIGIT) \
|
||||
, macro(NOT_WHITESPACE) \
|
||||
, macro(WHITESPACE) \
|
||||
, macro(NOT_WORDCHAR) \
|
||||
, macro(WORDCHAR) \
|
||||
\
|
||||
, macro(NOT_NEWLINE) \
|
||||
\
|
||||
, macro(CIRC) \
|
||||
, macro(DOLL) \
|
||||
, macro(BOL) \
|
||||
, macro(EOL) \
|
||||
, macro(CHAR) \
|
||||
, macro(CHAR_IGNORING_CASE) \
|
||||
, macro(ASCII_CHAR) \
|
||||
, macro(ASCII_LETTER_IGNORING_CASE) \
|
||||
, macro(NOT) \
|
||||
\
|
||||
, macro(STAR) \
|
||||
, macro(MINSTAR) \
|
||||
, macro(PLUS) \
|
||||
, macro(MINPLUS) \
|
||||
, macro(QUERY) \
|
||||
, macro(MINQUERY) \
|
||||
, macro(UPTO) \
|
||||
, macro(MINUPTO) \
|
||||
, macro(EXACT) \
|
||||
\
|
||||
, macro(NOTSTAR) \
|
||||
, macro(NOTMINSTAR) \
|
||||
, macro(NOTPLUS) \
|
||||
, macro(NOTMINPLUS) \
|
||||
, macro(NOTQUERY) \
|
||||
, macro(NOTMINQUERY) \
|
||||
, macro(NOTUPTO) \
|
||||
, macro(NOTMINUPTO) \
|
||||
, macro(NOTEXACT) \
|
||||
\
|
||||
, macro(TYPESTAR) \
|
||||
, macro(TYPEMINSTAR) \
|
||||
, macro(TYPEPLUS) \
|
||||
, macro(TYPEMINPLUS) \
|
||||
, macro(TYPEQUERY) \
|
||||
, macro(TYPEMINQUERY) \
|
||||
, macro(TYPEUPTO) \
|
||||
, macro(TYPEMINUPTO) \
|
||||
, macro(TYPEEXACT) \
|
||||
\
|
||||
, macro(CRSTAR) \
|
||||
, macro(CRMINSTAR) \
|
||||
, macro(CRPLUS) \
|
||||
, macro(CRMINPLUS) \
|
||||
, macro(CRQUERY) \
|
||||
, macro(CRMINQUERY) \
|
||||
, macro(CRRANGE) \
|
||||
, macro(CRMINRANGE) \
|
||||
\
|
||||
, macro(CLASS) \
|
||||
, macro(NCLASS) \
|
||||
, macro(XCLASS) \
|
||||
\
|
||||
, macro(REF) \
|
||||
\
|
||||
, macro(ALT) \
|
||||
, macro(KET) \
|
||||
, macro(KETRMAX) \
|
||||
, macro(KETRMIN) \
|
||||
\
|
||||
, macro(ASSERT) \
|
||||
, macro(ASSERT_NOT) \
|
||||
\
|
||||
, macro(BRAZERO) \
|
||||
, macro(BRAMINZERO) \
|
||||
, macro(BRANUMBER) \
|
||||
, macro(BRA)
|
||||
|
||||
#define OPCODE_ENUM_VALUE(opcode) OP_##opcode
|
||||
enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) };
|
||||
|
||||
/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and
|
||||
study.c that all opcodes are less than 128 in value. This makes handling UTF-8
|
||||
character sequences easier. */
|
||||
|
||||
/* The highest extraction number before we have to start using additional
|
||||
bytes. (Originally PCRE didn't have support for extraction counts higher than
|
||||
this number.) The value is limited by the number of opcodes left after OP_BRA,
|
||||
i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
|
||||
opcodes. */
|
||||
|
||||
/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above
|
||||
are in conflict! */
|
||||
|
||||
#define EXTRACT_BASIC_MAX 100
|
||||
|
||||
/* The code vector runs on as long as necessary after the end. */
|
||||
|
||||
struct JSRegExp {
|
||||
unsigned options;
|
||||
|
||||
unsigned short topBracket;
|
||||
unsigned short topBackref;
|
||||
|
||||
unsigned short firstByte;
|
||||
unsigned short reqByte;
|
||||
};
|
||||
|
||||
/* Internal shared data tables. These are tables that are used by more than one
|
||||
of the exported public functions. They have to be "external" in the C sense,
|
||||
but are not part of the PCRE public API. The data for these tables is in the
|
||||
pcre_tables.c module. */
|
||||
|
||||
#define jsc_pcre_utf8_table1_size 6
|
||||
|
||||
extern const int jsc_pcre_utf8_table1[6];
|
||||
extern const int jsc_pcre_utf8_table2[6];
|
||||
extern const int jsc_pcre_utf8_table3[6];
|
||||
extern const unsigned char jsc_pcre_utf8_table4[0x40];
|
||||
|
||||
extern const unsigned char jsc_pcre_default_tables[tables_length];
|
||||
|
||||
static inline unsigned char toLowerCase(unsigned char c)
|
||||
{
|
||||
static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset;
|
||||
return lowerCaseChars[c];
|
||||
}
|
||||
|
||||
static inline unsigned char flipCase(unsigned char c)
|
||||
{
|
||||
static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset;
|
||||
return flippedCaseChars[c];
|
||||
}
|
||||
|
||||
static inline unsigned char classBitmapForChar(unsigned char c)
|
||||
{
|
||||
static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset;
|
||||
return charClassBitmaps[c];
|
||||
}
|
||||
|
||||
static inline unsigned char charTypeForChar(unsigned char c)
|
||||
{
|
||||
const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset;
|
||||
return charTypeMap[c];
|
||||
}
|
||||
|
||||
static inline bool isWordChar(UChar c)
|
||||
{
|
||||
return c < 128 && (charTypeForChar(c) & ctype_word);
|
||||
}
|
||||
|
||||
static inline bool isSpaceChar(UChar c)
|
||||
{
|
||||
return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0;
|
||||
}
|
||||
|
||||
static inline bool isNewline(UChar nl)
|
||||
{
|
||||
return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029);
|
||||
}
|
||||
|
||||
static inline bool isBracketStartOpcode(unsigned char opcode)
|
||||
{
|
||||
if (opcode >= OP_BRA)
|
||||
return true;
|
||||
switch (opcode) {
|
||||
case OP_ASSERT:
|
||||
case OP_ASSERT_NOT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr)
|
||||
{
|
||||
JS_ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT);
|
||||
do
|
||||
opcodePtr += getLinkValue(opcodePtr + 1);
|
||||
while (*opcodePtr == OP_ALT);
|
||||
}
|
||||
|
||||
/* Internal shared functions. These are functions that are used in more
|
||||
that one of the source files. They have to have external linkage, but
|
||||
but are not part of the public API and so not exported from the library. */
|
||||
|
||||
extern int jsc_pcre_ucp_othercase(unsigned);
|
||||
extern bool jsc_pcre_xclass(int, const unsigned char*);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* End of pcre_internal.h */
|
|
@ -0,0 +1,71 @@
|
|||
/* This is JavaScriptCore's variant of the PCRE library. While this library
|
||||
started out as a copy of PCRE, many of the features of PCRE have been
|
||||
removed. This library now supports only the regular expression features
|
||||
required by the JavaScript language specification, and has only the functions
|
||||
needed by JavaScriptCore and the rest of WebKit.
|
||||
|
||||
Originally written by Philip Hazel
|
||||
Copyright (c) 1997-2006 University of Cambridge
|
||||
Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* This module contains some fixed tables that are used by more than one of the
|
||||
PCRE code modules. */
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
/*************************************************
|
||||
* Tables for UTF-8 support *
|
||||
*************************************************/
|
||||
|
||||
/* These are the breakpoints for different numbers of bytes in a UTF-8
|
||||
character. */
|
||||
|
||||
const int jsc_pcre_utf8_table1[6] =
|
||||
{ 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
|
||||
|
||||
/* These are the indicator bits and the mask for the data bits to set in the
|
||||
first byte of a character, indexed by the number of additional bytes. */
|
||||
|
||||
const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
|
||||
const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
|
||||
|
||||
/* Table of the number of extra characters, indexed by the first character
|
||||
masked with 0x3f. The highest number for a valid UTF-8 character is in fact
|
||||
0x3d. */
|
||||
|
||||
const unsigned char jsc_pcre_utf8_table4[0x40] = {
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
|
||||
|
||||
#include "chartables.c"
|
|
@ -0,0 +1,98 @@
|
|||
/* This is JavaScriptCore's variant of the PCRE library. While this library
|
||||
started out as a copy of PCRE, many of the features of PCRE have been
|
||||
removed. This library now supports only the regular expression features
|
||||
required by the JavaScript language specification, and has only the functions
|
||||
needed by JavaScriptCore and the rest of WebKit.
|
||||
|
||||
Originally written by Philip Hazel
|
||||
Copyright (c) 1997-2006 University of Cambridge
|
||||
Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/* This module contains code for searching the table of Unicode character
|
||||
properties. */
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
#include "ucpinternal.h" /* Internal table details */
|
||||
#include "ucptable.cpp" /* The table itself */
|
||||
|
||||
/*************************************************
|
||||
* Search table and return other case *
|
||||
*************************************************/
|
||||
|
||||
/* If the given character is a letter, and there is another case for the
|
||||
letter, return the other case. Otherwise, return -1.
|
||||
|
||||
Arguments:
|
||||
c the character value
|
||||
|
||||
Returns: the other case or -1 if none
|
||||
*/
|
||||
|
||||
int jsc_pcre_ucp_othercase(unsigned c)
|
||||
{
|
||||
int bot = 0;
|
||||
int top = sizeof(ucp_table) / sizeof(cnode);
|
||||
int mid;
|
||||
|
||||
/* The table is searched using a binary chop. You might think that using
|
||||
intermediate variables to hold some of the common expressions would speed
|
||||
things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it
|
||||
makes things a lot slower. */
|
||||
|
||||
for (;;) {
|
||||
if (top <= bot)
|
||||
return -1;
|
||||
mid = (bot + top) >> 1;
|
||||
if (c == (ucp_table[mid].f0 & f0_charmask))
|
||||
break;
|
||||
if (c < (ucp_table[mid].f0 & f0_charmask))
|
||||
top = mid;
|
||||
else {
|
||||
if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask)))
|
||||
break;
|
||||
bot = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Found an entry in the table. Return -1 for a range entry. Otherwise return
|
||||
the other case if there is one, else -1. */
|
||||
|
||||
if (ucp_table[mid].f0 & f0_rangeflag)
|
||||
return -1;
|
||||
|
||||
int offset = ucp_table[mid].f1 & f1_casemask;
|
||||
if (offset & f1_caseneg)
|
||||
offset |= f1_caseneg;
|
||||
return !offset ? -1 : c + offset;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* This is JavaScriptCore's variant of the PCRE library. While this library
|
||||
started out as a copy of PCRE, many of the features of PCRE have been
|
||||
removed. This library now supports only the regular expression features
|
||||
required by the JavaScript language specification, and has only the functions
|
||||
needed by JavaScriptCore and the rest of WebKit.
|
||||
|
||||
Originally written by Philip Hazel
|
||||
Copyright (c) 1997-2006 University of Cambridge
|
||||
Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* This module contains an internal function that is used to match an extended
|
||||
class (one that contains characters whose values are > 255). */
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
/*************************************************
|
||||
* Match character against an XCLASS *
|
||||
*************************************************/
|
||||
|
||||
/* This function is called to match a character against an extended class that
|
||||
might contain values > 255.
|
||||
|
||||
Arguments:
|
||||
c the character
|
||||
data points to the flag byte of the XCLASS data
|
||||
|
||||
Returns: true if character matches, else false
|
||||
*/
|
||||
|
||||
/* Get the next UTF-8 character, advancing the pointer. This is called when we
|
||||
know we are in UTF-8 mode. */
|
||||
|
||||
static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr)
|
||||
{
|
||||
c = *subjectPtr++;
|
||||
if ((c & 0xc0) == 0xc0) {
|
||||
int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */
|
||||
int gcss = 6 * gcaa;
|
||||
c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss;
|
||||
while (gcaa-- > 0) {
|
||||
gcss -= 6;
|
||||
c |= (*subjectPtr++ & 0x3f) << gcss;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool jsc_pcre_xclass(int c, const unsigned char* data)
|
||||
{
|
||||
bool negated = (*data & XCL_NOT);
|
||||
|
||||
/* Character values < 256 are matched against a bitmap, if one is present. If
|
||||
not, we still carry on, because there may be ranges that start below 256 in the
|
||||
additional data. */
|
||||
|
||||
if (c < 256) {
|
||||
if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0)
|
||||
return !negated; /* char found */
|
||||
}
|
||||
|
||||
/* First skip the bit map if present. Then match against the list of Unicode
|
||||
properties or large chars or ranges that end with a large char. We won't ever
|
||||
encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */
|
||||
|
||||
if ((*data++ & XCL_MAP) != 0)
|
||||
data += 32;
|
||||
|
||||
int t;
|
||||
while ((t = *data++) != XCL_END) {
|
||||
if (t == XCL_SINGLE) {
|
||||
int x;
|
||||
getUTF8CharAndAdvancePointer(x, data);
|
||||
if (c == x)
|
||||
return !negated;
|
||||
}
|
||||
else if (t == XCL_RANGE) {
|
||||
int x, y;
|
||||
getUTF8CharAndAdvancePointer(x, data);
|
||||
getUTF8CharAndAdvancePointer(y, data);
|
||||
if (c >= x && c <= y)
|
||||
return !negated;
|
||||
}
|
||||
}
|
||||
|
||||
return negated; /* char did not match */
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/* This is JavaScriptCore's variant of the PCRE library. While this library
|
||||
started out as a copy of PCRE, many of the features of PCRE have been
|
||||
removed. This library now supports only the regular expression features
|
||||
required by the JavaScript language specification, and has only the functions
|
||||
needed by JavaScriptCore and the rest of WebKit.
|
||||
|
||||
Originally written by Philip Hazel
|
||||
Copyright (c) 1997-2006 University of Cambridge
|
||||
Copyright (C) 2002, 2004, 2006, 2007 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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
* Unicode Property Table handler *
|
||||
*************************************************/
|
||||
|
||||
/* Internal header file defining the layout of the bits in each pair of 32-bit
|
||||
words that form a data item in the table. */
|
||||
|
||||
typedef struct cnode {
|
||||
unsigned f0;
|
||||
unsigned f1;
|
||||
} cnode;
|
||||
|
||||
/* Things for the f0 field */
|
||||
|
||||
#define f0_scriptmask 0xff000000 /* Mask for script field */
|
||||
#define f0_scriptshift 24 /* Shift for script value */
|
||||
#define f0_rangeflag 0x00f00000 /* Flag for a range item */
|
||||
#define f0_charmask 0x001fffff /* Mask for code point value */
|
||||
|
||||
/* Things for the f1 field */
|
||||
|
||||
#define f1_typemask 0xfc000000 /* Mask for char type field */
|
||||
#define f1_typeshift 26 /* Shift for the type field */
|
||||
#define f1_rangemask 0x0000ffff /* Mask for a range offset */
|
||||
#define f1_casemask 0x0000ffff /* Mask for a case offset */
|
||||
#define f1_caseneg 0xffff8000 /* Bits for negation */
|
||||
|
||||
/* The data consists of a vector of structures of type cnode. The two unsigned
|
||||
32-bit integers are used as follows:
|
||||
|
||||
(f0) (1) The most significant byte holds the script number. The numbers are
|
||||
defined by the enum in ucp.h.
|
||||
|
||||
(2) The 0x00800000 bit is set if this entry defines a range of characters.
|
||||
It is not set if this entry defines a single character
|
||||
|
||||
(3) The 0x00600000 bits are spare.
|
||||
|
||||
(4) The 0x001fffff bits contain the code point. No Unicode code point will
|
||||
ever be greater than 0x0010ffff, so this should be OK for ever.
|
||||
|
||||
(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are
|
||||
defined by an enum in ucp.h.
|
||||
|
||||
(2) The 0x03ff0000 bits are spare.
|
||||
|
||||
(3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of
|
||||
range if this entry defines a range, OR the *signed* offset to the
|
||||
character's "other case" partner if this entry defines a single
|
||||
character. There is no partner if the value is zero.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) |
|
||||
-------------------------------------------------------------------------------
|
||||
| | | | |
|
||||
| | |-> spare | |-> spare
|
||||
| | |
|
||||
| |-> spare |-> spare
|
||||
|
|
||||
|-> range flag
|
||||
|
||||
The upper/lower casing information is set only for characters that come in
|
||||
pairs. The non-one-to-one mappings in the Unicode data are ignored.
|
||||
|
||||
When searching the data, proceed as follows:
|
||||
|
||||
(1) Set up for a binary chop search.
|
||||
|
||||
(2) If the top is not greater than the bottom, the character is not in the
|
||||
table. Its type must therefore be "Cn" ("Undefined").
|
||||
|
||||
(3) Find the middle vector element.
|
||||
|
||||
(4) Extract the code point and compare. If equal, we are done.
|
||||
|
||||
(5) If the test character is smaller, set the top to the current point, and
|
||||
goto (2).
|
||||
|
||||
(6) If the current entry defines a range, compute the last character by adding
|
||||
the offset, and see if the test character is within the range. If it is,
|
||||
we are done.
|
||||
|
||||
(7) Otherwise, set the bottom to one element past the current point and goto
|
||||
(2).
|
||||
*/
|
||||
|
||||
/* End of ucpinternal.h */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (C) 2007, 2008, 2009 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.
|
||||
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef WTF_ASCIICType_h
|
||||
#define WTF_ASCIICType_h
|
||||
|
||||
#include "yarr/jswtfbridge.h"
|
||||
|
||||
// The behavior of many of the functions in the <ctype.h> header is dependent
|
||||
// on the current locale. But in the WebKit project, all uses of those functions
|
||||
// are in code processing something that's not locale-specific. These equivalents
|
||||
// for some of the <ctype.h> functions are named more explicitly, not dependent
|
||||
// on the C library locale, and we should also optimize them as needed.
|
||||
|
||||
// All functions return false or leave the character unchanged if passed a character
|
||||
// that is outside the range 0-7F. So they can be used on Unicode strings or
|
||||
// characters if the intent is to do processing only if the character is ASCII.
|
||||
|
||||
namespace WTF {
|
||||
|
||||
inline bool isASCII(char c) { return !(c & ~0x7F); }
|
||||
inline bool isASCII(unsigned short c) { return !(c & ~0x7F); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCII(wchar_t c) { return !(c & ~0x7F); }
|
||||
#endif
|
||||
inline bool isASCII(int c) { return !(c & ~0x7F); }
|
||||
|
||||
inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
|
||||
inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
|
||||
#endif
|
||||
inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
|
||||
|
||||
inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
|
||||
inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
|
||||
#endif
|
||||
inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
|
||||
|
||||
inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); }
|
||||
inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); }
|
||||
#endif
|
||||
inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); }
|
||||
|
||||
inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
|
||||
inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
|
||||
#endif
|
||||
inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
|
||||
|
||||
inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); }
|
||||
inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); }
|
||||
#endif
|
||||
inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); }
|
||||
|
||||
inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; }
|
||||
inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; }
|
||||
#endif
|
||||
inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; }
|
||||
|
||||
inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; }
|
||||
inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; }
|
||||
#endif
|
||||
inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; }
|
||||
|
||||
/*
|
||||
Statistics from a run of Apple's page load test for callers of isASCIISpace:
|
||||
|
||||
character count
|
||||
--------- -----
|
||||
non-spaces 689383
|
||||
20 space 294720
|
||||
0A \n 89059
|
||||
09 \t 28320
|
||||
0D \r 0
|
||||
0C \f 0
|
||||
0B \v 0
|
||||
*/
|
||||
inline bool isASCIISpace(char c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
|
||||
inline bool isASCIISpace(unsigned short c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
|
||||
#endif
|
||||
inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
|
||||
|
||||
inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
|
||||
inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
|
||||
#endif
|
||||
inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
|
||||
|
||||
inline char toASCIIUpper(char c) { return static_cast<char>(c & ~((c >= 'a' && c <= 'z') << 5)); }
|
||||
inline unsigned short toASCIIUpper(unsigned short c) { return static_cast<unsigned short>(c & ~((c >= 'a' && c <= 'z') << 5)); }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline wchar_t toASCIIUpper(wchar_t c) { return static_cast<wchar_t>(c & ~((c >= 'a' && c <= 'z') << 5)); }
|
||||
#endif
|
||||
inline int toASCIIUpper(int c) { return static_cast<int>(c & ~((c >= 'a' && c <= 'z') << 5)); }
|
||||
|
||||
inline int toASCIIHexValue(char c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
|
||||
inline int toASCIIHexValue(unsigned short c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline int toASCIIHexValue(wchar_t c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
|
||||
#endif
|
||||
inline int toASCIIHexValue(int c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
|
||||
|
||||
inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; }
|
||||
inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; }
|
||||
#if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; }
|
||||
#endif
|
||||
inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; }
|
||||
|
||||
}
|
||||
|
||||
using WTF::isASCII;
|
||||
using WTF::isASCIIAlpha;
|
||||
using WTF::isASCIIAlphanumeric;
|
||||
using WTF::isASCIIDigit;
|
||||
using WTF::isASCIIHexDigit;
|
||||
using WTF::isASCIILower;
|
||||
using WTF::isASCIIOctalDigit;
|
||||
using WTF::isASCIIPrintable;
|
||||
using WTF::isASCIISpace;
|
||||
using WTF::isASCIIUpper;
|
||||
using WTF::toASCIIHexValue;
|
||||
using WTF::toASCIILower;
|
||||
using WTF::toASCIIUpper;
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,629 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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 "jsinttypes.h"
|
||||
#include "RegexCompiler.h"
|
||||
|
||||
#include "RegexPattern.h"
|
||||
|
||||
using namespace WTF;
|
||||
|
||||
namespace JSC { namespace Yarr {
|
||||
|
||||
#include "RegExpJitTables.h"
|
||||
|
||||
class CharacterClassConstructor {
|
||||
public:
|
||||
CharacterClassConstructor(bool isCaseInsensitive = false)
|
||||
: m_isCaseInsensitive(isCaseInsensitive)
|
||||
{
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_matches.clear();
|
||||
m_ranges.clear();
|
||||
m_matchesUnicode.clear();
|
||||
m_rangesUnicode.clear();
|
||||
}
|
||||
|
||||
void append(const CharacterClass* other)
|
||||
{
|
||||
for (size_t i = 0; i < other->m_matches.length(); ++i)
|
||||
addSorted(m_matches, other->m_matches[i]);
|
||||
for (size_t i = 0; i < other->m_ranges.length(); ++i)
|
||||
addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end);
|
||||
for (size_t i = 0; i < other->m_matchesUnicode.length(); ++i)
|
||||
addSorted(m_matchesUnicode, other->m_matchesUnicode[i]);
|
||||
for (size_t i = 0; i < other->m_rangesUnicode.length(); ++i)
|
||||
addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end);
|
||||
}
|
||||
|
||||
void putChar(UChar ch)
|
||||
{
|
||||
if (ch <= 0x7f) {
|
||||
if (m_isCaseInsensitive && isASCIIAlpha(ch)) {
|
||||
addSorted(m_matches, toASCIIUpper(ch));
|
||||
addSorted(m_matches, toASCIILower(ch));
|
||||
} else
|
||||
addSorted(m_matches, ch);
|
||||
} else {
|
||||
UChar upper, lower;
|
||||
if (m_isCaseInsensitive && ((upper = Unicode::toUpper(ch)) != (lower = Unicode::toLower(ch)))) {
|
||||
addSorted(m_matchesUnicode, upper);
|
||||
addSorted(m_matchesUnicode, lower);
|
||||
} else
|
||||
addSorted(m_matchesUnicode, ch);
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if this character has another case, and 'ch' is the upper case form.
|
||||
static inline bool isUnicodeUpper(UChar ch)
|
||||
{
|
||||
return ch != Unicode::toLower(ch);
|
||||
}
|
||||
|
||||
// returns true if this character has another case, and 'ch' is the lower case form.
|
||||
static inline bool isUnicodeLower(UChar ch)
|
||||
{
|
||||
return ch != Unicode::toUpper(ch);
|
||||
}
|
||||
|
||||
void putRange(UChar lo, UChar hi)
|
||||
{
|
||||
if (lo <= 0x7f) {
|
||||
char asciiLo = lo;
|
||||
char asciiHi = JS_MIN(hi, (UChar)0x7f);
|
||||
addSortedRange(m_ranges, lo, asciiHi);
|
||||
|
||||
if (m_isCaseInsensitive) {
|
||||
if ((asciiLo <= 'Z') && (asciiHi >= 'A'))
|
||||
addSortedRange(m_ranges, JS_MAX(asciiLo, 'A')+('a'-'A'), JS_MIN(asciiHi, 'Z')+('a'-'A'));
|
||||
if ((asciiLo <= 'z') && (asciiHi >= 'a'))
|
||||
addSortedRange(m_ranges, JS_MAX(asciiLo, 'a')+('A'-'a'), JS_MIN(asciiHi, 'z')+('A'-'a'));
|
||||
}
|
||||
}
|
||||
if (hi >= 0x80) {
|
||||
uint32 unicodeCurr = JS_MAX(lo, (UChar)0x80);
|
||||
addSortedRange(m_rangesUnicode, unicodeCurr, hi);
|
||||
|
||||
if (m_isCaseInsensitive) {
|
||||
while (unicodeCurr <= hi) {
|
||||
// If the upper bound of the range (hi) is 0xffff, the increments to
|
||||
// unicodeCurr in this loop may take it to 0x10000. This is fine
|
||||
// (if so we won't re-enter the loop, since the loop condition above
|
||||
// will definitely fail) - but this does mean we cannot use a UChar
|
||||
// to represent unicodeCurr, we must use a 32-bit value instead.
|
||||
JS_ASSERT(unicodeCurr <= 0xffff);
|
||||
|
||||
if (isUnicodeUpper(unicodeCurr)) {
|
||||
UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr);
|
||||
UChar lowerCaseRangeEnd = lowerCaseRangeBegin;
|
||||
while ((++unicodeCurr <= hi) && isUnicodeUpper(unicodeCurr) && (Unicode::toLower(unicodeCurr) == (lowerCaseRangeEnd + 1)))
|
||||
lowerCaseRangeEnd++;
|
||||
addSortedRange(m_rangesUnicode, lowerCaseRangeBegin, lowerCaseRangeEnd);
|
||||
} else if (isUnicodeLower(unicodeCurr)) {
|
||||
UChar upperCaseRangeBegin = Unicode::toUpper(unicodeCurr);
|
||||
UChar upperCaseRangeEnd = upperCaseRangeBegin;
|
||||
while ((++unicodeCurr <= hi) && isUnicodeLower(unicodeCurr) && (Unicode::toUpper(unicodeCurr) == (upperCaseRangeEnd + 1)))
|
||||
upperCaseRangeEnd++;
|
||||
addSortedRange(m_rangesUnicode, upperCaseRangeBegin, upperCaseRangeEnd);
|
||||
} else
|
||||
++unicodeCurr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CharacterClass* charClass()
|
||||
{
|
||||
CharacterClass* characterClass = new CharacterClass(0);
|
||||
|
||||
characterClass->m_matches.append(m_matches);
|
||||
characterClass->m_ranges.append(m_ranges);
|
||||
characterClass->m_matchesUnicode.append(m_matchesUnicode);
|
||||
characterClass->m_rangesUnicode.append(m_rangesUnicode);
|
||||
|
||||
reset();
|
||||
|
||||
return characterClass;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef js::Vector<UChar, 0, js::SystemAllocPolicy> UChars;
|
||||
typedef js::Vector<CharacterRange, 0, js::SystemAllocPolicy> CharacterRanges;
|
||||
void addSorted(UChars& matches, UChar ch)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
unsigned range = matches.length();
|
||||
|
||||
// binary chop, find position to insert char.
|
||||
while (range) {
|
||||
unsigned index = range >> 1;
|
||||
|
||||
int val = matches[pos+index] - ch;
|
||||
if (!val)
|
||||
return;
|
||||
else if (val > 0)
|
||||
range = index;
|
||||
else {
|
||||
pos += (index+1);
|
||||
range -= (index+1);
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == matches.length())
|
||||
matches.append(ch);
|
||||
else
|
||||
matches.insert(matches.begin() + pos, ch);
|
||||
}
|
||||
|
||||
void addSortedRange(CharacterRanges& ranges, UChar lo, UChar hi)
|
||||
{
|
||||
unsigned end = ranges.length();
|
||||
|
||||
// Simple linear scan - I doubt there are that many ranges anyway...
|
||||
// feel free to fix this with something faster (eg binary chop).
|
||||
for (unsigned i = 0; i < end; ++i) {
|
||||
// does the new range fall before the current position in the array
|
||||
if (hi < ranges[i].begin) {
|
||||
// optional optimization: concatenate appending ranges? - may not be worthwhile.
|
||||
if (hi == (ranges[i].begin - 1)) {
|
||||
ranges[i].begin = lo;
|
||||
return;
|
||||
}
|
||||
CharacterRange cr(lo, hi);
|
||||
ranges.insert(ranges.begin() + i, cr);
|
||||
return;
|
||||
}
|
||||
// Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining
|
||||
// If the new range start at or before the end of the last range, then the overlap (if it starts one after the
|
||||
// end of the last range they concatenate, which is just as good.
|
||||
if (lo <= (ranges[i].end + 1)) {
|
||||
// found an intersect! we'll replace this entry in the array.
|
||||
ranges[i].begin = JS_MIN(ranges[i].begin, lo);
|
||||
ranges[i].end = JS_MAX(ranges[i].end, hi);
|
||||
|
||||
// now check if the new range can subsume any subsequent ranges.
|
||||
unsigned next = i+1;
|
||||
// each iteration of the loop we will either remove something from the list, or break the loop.
|
||||
while (next < ranges.length()) {
|
||||
if (ranges[next].begin <= (ranges[i].end + 1)) {
|
||||
// the next entry now overlaps / concatenates this one.
|
||||
ranges[i].end = JS_MAX(ranges[i].end, ranges[next].end);
|
||||
ranges.erase(ranges.begin() + next);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// CharacterRange comes after all existing ranges.
|
||||
ranges.append(CharacterRange(lo, hi));
|
||||
}
|
||||
|
||||
bool m_isCaseInsensitive;
|
||||
|
||||
UChars m_matches;
|
||||
CharacterRanges m_ranges;
|
||||
UChars m_matchesUnicode;
|
||||
CharacterRanges m_rangesUnicode;
|
||||
};
|
||||
|
||||
class RegexPatternConstructor {
|
||||
public:
|
||||
RegexPatternConstructor(RegexPattern& pattern)
|
||||
: m_pattern(pattern)
|
||||
, m_characterClassConstructor(pattern.m_ignoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
~RegexPatternConstructor()
|
||||
{
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_pattern.reset();
|
||||
m_characterClassConstructor.reset();
|
||||
}
|
||||
|
||||
void assertionBOL()
|
||||
{
|
||||
m_alternative->m_terms.append(PatternTerm::BOL());
|
||||
}
|
||||
void assertionEOL()
|
||||
{
|
||||
m_alternative->m_terms.append(PatternTerm::EOL());
|
||||
}
|
||||
void assertionWordBoundary(bool invert)
|
||||
{
|
||||
m_alternative->m_terms.append(PatternTerm::WordBoundary(invert));
|
||||
}
|
||||
|
||||
void atomPatternCharacter(UChar ch)
|
||||
{
|
||||
// We handle case-insensitive checking of unicode characters which do have both
|
||||
// cases by handling them as if they were defined using a CharacterClass.
|
||||
if (m_pattern.m_ignoreCase && !isASCII(ch) && (Unicode::toUpper(ch) != Unicode::toLower(ch))) {
|
||||
atomCharacterClassBegin();
|
||||
atomCharacterClassAtom(ch);
|
||||
atomCharacterClassEnd();
|
||||
} else
|
||||
m_alternative->m_terms.append(PatternTerm(ch));
|
||||
}
|
||||
|
||||
void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
|
||||
{
|
||||
switch (classID) {
|
||||
case DigitClassID:
|
||||
m_alternative->m_terms.append(PatternTerm(m_pattern.digitsCharacterClass(), invert));
|
||||
break;
|
||||
case SpaceClassID:
|
||||
m_alternative->m_terms.append(PatternTerm(m_pattern.spacesCharacterClass(), invert));
|
||||
break;
|
||||
case WordClassID:
|
||||
m_alternative->m_terms.append(PatternTerm(m_pattern.wordcharCharacterClass(), invert));
|
||||
break;
|
||||
case NewlineClassID:
|
||||
m_alternative->m_terms.append(PatternTerm(m_pattern.newlineCharacterClass(), invert));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void atomCharacterClassBegin(bool invert = false)
|
||||
{
|
||||
m_invertCharacterClass = invert;
|
||||
}
|
||||
|
||||
void atomCharacterClassAtom(UChar ch)
|
||||
{
|
||||
m_characterClassConstructor.putChar(ch);
|
||||
}
|
||||
|
||||
void atomCharacterClassRange(UChar begin, UChar end)
|
||||
{
|
||||
m_characterClassConstructor.putRange(begin, end);
|
||||
}
|
||||
|
||||
void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
|
||||
{
|
||||
JS_ASSERT(classID != NewlineClassID);
|
||||
|
||||
switch (classID) {
|
||||
case DigitClassID:
|
||||
m_characterClassConstructor.append(invert ? m_pattern.nondigitsCharacterClass() : m_pattern.digitsCharacterClass());
|
||||
break;
|
||||
|
||||
case SpaceClassID:
|
||||
m_characterClassConstructor.append(invert ? m_pattern.nonspacesCharacterClass() : m_pattern.spacesCharacterClass());
|
||||
break;
|
||||
|
||||
case WordClassID:
|
||||
m_characterClassConstructor.append(invert ? m_pattern.nonwordcharCharacterClass() : m_pattern.wordcharCharacterClass());
|
||||
break;
|
||||
|
||||
default:
|
||||
JS_NOT_REACHED("blah");
|
||||
}
|
||||
}
|
||||
|
||||
void atomCharacterClassEnd()
|
||||
{
|
||||
CharacterClass* newCharacterClass = m_characterClassConstructor.charClass();
|
||||
m_pattern.m_userCharacterClasses.append(newCharacterClass);
|
||||
m_alternative->m_terms.append(PatternTerm(newCharacterClass, m_invertCharacterClass));
|
||||
}
|
||||
|
||||
void atomParenthesesSubpatternBegin(bool capture = true)
|
||||
{
|
||||
unsigned subpatternId = m_pattern.m_numSubpatterns + 1;
|
||||
if (capture)
|
||||
m_pattern.m_numSubpatterns++;
|
||||
|
||||
PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
|
||||
m_pattern.m_disjunctions.append(parenthesesDisjunction);
|
||||
m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture));
|
||||
m_alternative = parenthesesDisjunction->addNewAlternative();
|
||||
}
|
||||
|
||||
void atomParentheticalAssertionBegin(bool invert = false)
|
||||
{
|
||||
PatternDisjunction* parenthesesDisjunction = new PatternDisjunction(m_alternative);
|
||||
m_pattern.m_disjunctions.append(parenthesesDisjunction);
|
||||
m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert));
|
||||
m_alternative = parenthesesDisjunction->addNewAlternative();
|
||||
}
|
||||
|
||||
void atomParenthesesEnd()
|
||||
{
|
||||
JS_ASSERT(m_alternative->m_parent);
|
||||
JS_ASSERT(m_alternative->m_parent->m_parent);
|
||||
m_alternative = m_alternative->m_parent->m_parent;
|
||||
|
||||
m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
|
||||
}
|
||||
|
||||
void atomBackReference(unsigned subpatternId)
|
||||
{
|
||||
JS_ASSERT(subpatternId);
|
||||
m_pattern.m_containsBackreferences = true;
|
||||
m_pattern.m_maxBackReference = JS_MAX(m_pattern.m_maxBackReference, subpatternId);
|
||||
|
||||
if (subpatternId > m_pattern.m_numSubpatterns) {
|
||||
m_alternative->m_terms.append(PatternTerm::ForwardReference());
|
||||
return;
|
||||
}
|
||||
|
||||
PatternAlternative* currentAlternative = m_alternative;
|
||||
JS_ASSERT(currentAlternative);
|
||||
|
||||
// Note to self: if we waited until the AST was baked, we could also remove forwards refs
|
||||
while ((currentAlternative = currentAlternative->m_parent->m_parent)) {
|
||||
PatternTerm& term = currentAlternative->lastTerm();
|
||||
JS_ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
|
||||
|
||||
if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) {
|
||||
m_alternative->m_terms.append(PatternTerm::ForwardReference());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_alternative->m_terms.append(PatternTerm(subpatternId));
|
||||
}
|
||||
|
||||
PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction)
|
||||
{
|
||||
PatternDisjunction* newDisjunction = new PatternDisjunction();
|
||||
|
||||
newDisjunction->m_parent = disjunction->m_parent;
|
||||
for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
|
||||
PatternAlternative* alternative = disjunction->m_alternatives[alt];
|
||||
PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
|
||||
for (unsigned i = 0; i < alternative->m_terms.length(); ++i)
|
||||
newAlternative->m_terms.append(copyTerm(alternative->m_terms[i]));
|
||||
}
|
||||
|
||||
m_pattern.m_disjunctions.append(newDisjunction);
|
||||
return newDisjunction;
|
||||
}
|
||||
|
||||
PatternTerm copyTerm(PatternTerm& term)
|
||||
{
|
||||
if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion))
|
||||
return PatternTerm(term);
|
||||
|
||||
PatternTerm termCopy = term;
|
||||
termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction);
|
||||
return termCopy;
|
||||
}
|
||||
|
||||
void quantifyAtom(unsigned min, unsigned max, bool greedy)
|
||||
{
|
||||
JS_ASSERT(min <= max);
|
||||
JS_ASSERT(m_alternative->m_terms.length());
|
||||
|
||||
if (!max) {
|
||||
m_alternative->removeLastTerm();
|
||||
return;
|
||||
}
|
||||
|
||||
PatternTerm& term = m_alternative->lastTerm();
|
||||
JS_ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
|
||||
JS_ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
|
||||
|
||||
// For any assertion with a zero minimum, not matching is valid and has no effect,
|
||||
// remove it. Otherwise, we need to match as least once, but there is no point
|
||||
// matching more than once, so remove the quantifier. It is not entirely clear
|
||||
// from the spec whether or not this behavior is correct, but I believe this
|
||||
// matches Firefox. :-/
|
||||
if (term.type == PatternTerm::TypeParentheticalAssertion) {
|
||||
if (!min)
|
||||
m_alternative->removeLastTerm();
|
||||
return;
|
||||
}
|
||||
|
||||
if (min == 0)
|
||||
term.quantify(max, greedy ? QuantifierGreedy : QuantifierNonGreedy);
|
||||
else if (min == max)
|
||||
term.quantify(min, QuantifierFixedCount);
|
||||
else {
|
||||
term.quantify(min, QuantifierFixedCount);
|
||||
m_alternative->m_terms.append(copyTerm(term));
|
||||
// NOTE: this term is interesting from an analysis perspective, in that it can be ignored.....
|
||||
m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
|
||||
if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern)
|
||||
m_alternative->lastTerm().parentheses.isCopy = true;
|
||||
}
|
||||
}
|
||||
|
||||
void disjunction()
|
||||
{
|
||||
m_alternative = m_alternative->m_parent->addNewAlternative();
|
||||
}
|
||||
|
||||
void regexBegin()
|
||||
{
|
||||
m_pattern.m_body = new PatternDisjunction();
|
||||
m_alternative = m_pattern.m_body->addNewAlternative();
|
||||
m_pattern.m_disjunctions.append(m_pattern.m_body);
|
||||
}
|
||||
void regexEnd()
|
||||
{
|
||||
}
|
||||
void regexError()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition)
|
||||
{
|
||||
alternative->m_hasFixedSize = true;
|
||||
unsigned currentInputPosition = initialInputPosition;
|
||||
|
||||
for (unsigned i = 0; i < alternative->m_terms.length(); ++i) {
|
||||
PatternTerm& term = alternative->m_terms[i];
|
||||
|
||||
switch (term.type) {
|
||||
case PatternTerm::TypeAssertionBOL:
|
||||
case PatternTerm::TypeAssertionEOL:
|
||||
case PatternTerm::TypeAssertionWordBoundary:
|
||||
term.inputPosition = currentInputPosition;
|
||||
break;
|
||||
|
||||
case PatternTerm::TypeBackReference:
|
||||
term.inputPosition = currentInputPosition;
|
||||
term.frameLocation = currentCallFrameSize;
|
||||
currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference;
|
||||
alternative->m_hasFixedSize = false;
|
||||
break;
|
||||
|
||||
case PatternTerm::TypeForwardReference:
|
||||
break;
|
||||
|
||||
case PatternTerm::TypePatternCharacter:
|
||||
term.inputPosition = currentInputPosition;
|
||||
if (term.quantityType != QuantifierFixedCount) {
|
||||
term.frameLocation = currentCallFrameSize;
|
||||
currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter;
|
||||
alternative->m_hasFixedSize = false;
|
||||
} else
|
||||
currentInputPosition += term.quantityCount;
|
||||
break;
|
||||
|
||||
case PatternTerm::TypeCharacterClass:
|
||||
term.inputPosition = currentInputPosition;
|
||||
if (term.quantityType != QuantifierFixedCount) {
|
||||
term.frameLocation = currentCallFrameSize;
|
||||
currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass;
|
||||
alternative->m_hasFixedSize = false;
|
||||
} else
|
||||
currentInputPosition += term.quantityCount;
|
||||
break;
|
||||
|
||||
case PatternTerm::TypeParenthesesSubpattern:
|
||||
// Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own.
|
||||
term.frameLocation = currentCallFrameSize;
|
||||
if ((term.quantityCount == 1) && !term.parentheses.isCopy) {
|
||||
if (term.quantityType == QuantifierFixedCount) {
|
||||
currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
|
||||
currentInputPosition += term.parentheses.disjunction->m_minimumSize;
|
||||
} else {
|
||||
currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce;
|
||||
currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
|
||||
}
|
||||
term.inputPosition = currentInputPosition;
|
||||
} else {
|
||||
term.inputPosition = currentInputPosition;
|
||||
setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition);
|
||||
currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses;
|
||||
}
|
||||
// Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length.
|
||||
alternative->m_hasFixedSize = false;
|
||||
break;
|
||||
|
||||
case PatternTerm::TypeParentheticalAssertion:
|
||||
term.inputPosition = currentInputPosition;
|
||||
term.frameLocation = currentCallFrameSize;
|
||||
currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
alternative->m_minimumSize = currentInputPosition - initialInputPosition;
|
||||
return currentCallFrameSize;
|
||||
}
|
||||
|
||||
unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition)
|
||||
{
|
||||
if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.length() > 1))
|
||||
initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative;
|
||||
|
||||
unsigned minimumInputSize = UINT_MAX;
|
||||
unsigned maximumCallFrameSize = 0;
|
||||
bool hasFixedSize = true;
|
||||
|
||||
for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
|
||||
PatternAlternative* alternative = disjunction->m_alternatives[alt];
|
||||
unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition);
|
||||
minimumInputSize = JS_MIN(minimumInputSize, alternative->m_minimumSize);
|
||||
maximumCallFrameSize = JS_MAX(maximumCallFrameSize, currentAlternativeCallFrameSize);
|
||||
hasFixedSize &= alternative->m_hasFixedSize;
|
||||
}
|
||||
|
||||
JS_ASSERT(minimumInputSize != UINT_MAX);
|
||||
JS_ASSERT(maximumCallFrameSize >= initialCallFrameSize);
|
||||
|
||||
disjunction->m_hasFixedSize = hasFixedSize;
|
||||
disjunction->m_minimumSize = minimumInputSize;
|
||||
disjunction->m_callFrameSize = maximumCallFrameSize;
|
||||
return maximumCallFrameSize;
|
||||
}
|
||||
|
||||
void setupOffsets()
|
||||
{
|
||||
setupDisjunctionOffsets(m_pattern.m_body, 0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
RegexPattern& m_pattern;
|
||||
PatternAlternative* m_alternative;
|
||||
CharacterClassConstructor m_characterClassConstructor;
|
||||
bool m_invertCharacterClass;
|
||||
};
|
||||
|
||||
|
||||
int compileRegex(const UString& patternString, RegexPattern& pattern)
|
||||
{
|
||||
RegexPatternConstructor constructor(pattern);
|
||||
|
||||
if (int error = parse(constructor, patternString))
|
||||
return error;
|
||||
|
||||
// If the pattern contains illegal backreferences reset & reparse.
|
||||
// Quoting Netscape's "What's new in JavaScript 1.2",
|
||||
// "Note: if the number of left parentheses is less than the number specified
|
||||
// in \#, the \# is taken as an octal escape as described in the next row."
|
||||
if (pattern.containsIllegalBackReference()) {
|
||||
unsigned numSubpatterns = pattern.m_numSubpatterns;
|
||||
|
||||
constructor.reset();
|
||||
#ifdef DEBUG
|
||||
int error =
|
||||
#endif
|
||||
parse(constructor, patternString, numSubpatterns);
|
||||
|
||||
JS_ASSERT(!error);
|
||||
JS_ASSERT(numSubpatterns == pattern.m_numSubpatterns);
|
||||
}
|
||||
|
||||
constructor.setupOffsets();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} }
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RegexCompiler_h
|
||||
#define RegexCompiler_h
|
||||
|
||||
#include "RegexParser.h"
|
||||
#include "RegexPattern.h"
|
||||
|
||||
namespace JSC { namespace Yarr {
|
||||
|
||||
int compileRegex(const UString& patternString, RegexPattern& pattern);
|
||||
|
||||
} } // namespace JSC::Yarr
|
||||
|
||||
#endif // RegexCompiler_h
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RegexJIT_h
|
||||
#define RegexJIT_h
|
||||
|
||||
#include "assembler/assembler/MacroAssembler.h"
|
||||
#include "assembler/assembler/MacroAssemblerCodeRef.h"
|
||||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "RegexPattern.h"
|
||||
#include "yarr/jswtfbridge.h"
|
||||
|
||||
#include "yarr/pcre/pcre.h"
|
||||
struct JSRegExp; // temporary, remove when fallback is removed.
|
||||
|
||||
#if WTF_CPU_X86 && !WTF_COMPILER_MSVC
|
||||
#define YARR_CALL __attribute__ ((regparm (3)))
|
||||
#else
|
||||
#define YARR_CALL
|
||||
#endif
|
||||
|
||||
struct JSContext;
|
||||
|
||||
namespace JSC {
|
||||
|
||||
namespace Yarr {
|
||||
|
||||
class RegexCodeBlock {
|
||||
typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
|
||||
|
||||
public:
|
||||
RegexCodeBlock()
|
||||
: m_fallback(0)
|
||||
{
|
||||
}
|
||||
|
||||
~RegexCodeBlock()
|
||||
{
|
||||
if (m_fallback)
|
||||
jsRegExpFree(m_fallback);
|
||||
}
|
||||
|
||||
JSRegExp* getFallback() { return m_fallback; }
|
||||
void setFallback(JSRegExp* fallback) { m_fallback = fallback; }
|
||||
|
||||
bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); }
|
||||
void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
|
||||
|
||||
int execute(const UChar* input, unsigned start, unsigned length, int* output)
|
||||
{
|
||||
return JS_EXTENSION(reinterpret_cast<RegexJITCode>(m_ref.m_code.executableAddress())(input, start, length, output));
|
||||
}
|
||||
|
||||
private:
|
||||
MacroAssembler::CodeRef m_ref;
|
||||
JSRegExp* m_fallback;
|
||||
};
|
||||
|
||||
void jitCompileRegex(ExecutableAllocator &allocator, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, int& error, bool &fellBack, bool ignoreCase = false, bool multiline = false);
|
||||
|
||||
inline int executeRegex(JSContext *cx, RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize)
|
||||
{
|
||||
if (JSRegExp* fallback = jitObject.getFallback())
|
||||
return (jsRegExpExecute(cx, fallback, input, length, start, output, outputArraySize) < 0 ? -1 : output[0]);
|
||||
|
||||
return jitObject.execute(input, start, length, output);
|
||||
}
|
||||
|
||||
} } // namespace JSC::Yarr
|
||||
|
||||
#endif // RegexJIT_h
|
|
@ -0,0 +1,848 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RegexParser_h
|
||||
#define RegexParser_h
|
||||
|
||||
#include <limits.h>
|
||||
#include <wtf/ASCIICType.h>
|
||||
#include "yarr/jswtfbridge.h"
|
||||
|
||||
namespace JSC { namespace Yarr {
|
||||
|
||||
enum BuiltInCharacterClassID {
|
||||
DigitClassID,
|
||||
SpaceClassID,
|
||||
WordClassID,
|
||||
NewlineClassID
|
||||
};
|
||||
|
||||
// The Parser class should not be used directly - only via the Yarr::parse() method.
|
||||
template<class Delegate>
|
||||
class Parser {
|
||||
private:
|
||||
template<class FriendDelegate>
|
||||
friend int parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit);
|
||||
|
||||
enum ErrorCode {
|
||||
NoError,
|
||||
PatternTooLarge,
|
||||
QuantifierOutOfOrder,
|
||||
QuantifierWithoutAtom,
|
||||
MissingParentheses,
|
||||
ParenthesesUnmatched,
|
||||
ParenthesesTypeInvalid,
|
||||
CharacterClassUnmatched,
|
||||
CharacterClassOutOfOrder,
|
||||
EscapeUnterminated,
|
||||
QuantifierTooLarge,
|
||||
NumberOfErrorCodes
|
||||
};
|
||||
|
||||
/*
|
||||
* CharacterClassParserDelegate:
|
||||
*
|
||||
* The class CharacterClassParserDelegate is used in the parsing of character
|
||||
* classes. This class handles detection of character ranges. This class
|
||||
* implements enough of the delegate interface such that it can be passed to
|
||||
* parseEscape() as an EscapeDelegate. This allows parseEscape() to be reused
|
||||
* to perform the parsing of escape characters in character sets.
|
||||
*/
|
||||
class CharacterClassParserDelegate {
|
||||
public:
|
||||
CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err)
|
||||
: m_delegate(delegate)
|
||||
, m_err(err)
|
||||
, m_state(empty)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* begin():
|
||||
*
|
||||
* Called at beginning of construction.
|
||||
*/
|
||||
void begin(bool invert)
|
||||
{
|
||||
m_delegate.atomCharacterClassBegin(invert);
|
||||
}
|
||||
|
||||
/*
|
||||
* atomPatternCharacterUnescaped():
|
||||
*
|
||||
* This method is called directly from parseCharacterClass(), to report a new
|
||||
* pattern character token. This method differs from atomPatternCharacter(),
|
||||
* which will be called from parseEscape(), since a hypen provided via this
|
||||
* method may be indicating a character range, but a hyphen parsed by
|
||||
* parseEscape() cannot be interpreted as doing so.
|
||||
*/
|
||||
void atomPatternCharacterUnescaped(UChar ch)
|
||||
{
|
||||
switch (m_state) {
|
||||
case empty:
|
||||
m_character = ch;
|
||||
m_state = cachedCharacter;
|
||||
break;
|
||||
|
||||
case cachedCharacter:
|
||||
if (ch == '-')
|
||||
m_state = cachedCharacterHyphen;
|
||||
else {
|
||||
m_delegate.atomCharacterClassAtom(m_character);
|
||||
m_character = ch;
|
||||
}
|
||||
break;
|
||||
|
||||
case cachedCharacterHyphen:
|
||||
if (ch >= m_character)
|
||||
m_delegate.atomCharacterClassRange(m_character, ch);
|
||||
else
|
||||
m_err = CharacterClassOutOfOrder;
|
||||
m_state = empty;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* atomPatternCharacter():
|
||||
*
|
||||
* Adds a pattern character, called by parseEscape(), as such will not
|
||||
* interpret a hyphen as indicating a character range.
|
||||
*/
|
||||
void atomPatternCharacter(UChar ch)
|
||||
{
|
||||
// Flush if a character is already pending to prevent the
|
||||
// hyphen from begin interpreted as indicating a range.
|
||||
if((ch == '-') && (m_state == cachedCharacter))
|
||||
flush();
|
||||
|
||||
atomPatternCharacterUnescaped(ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* atomBuiltInCharacterClass():
|
||||
*
|
||||
* Adds a built-in character class, called by parseEscape().
|
||||
*/
|
||||
void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
|
||||
{
|
||||
flush();
|
||||
m_delegate.atomCharacterClassBuiltIn(classID, invert);
|
||||
}
|
||||
|
||||
/*
|
||||
* end():
|
||||
*
|
||||
* Called at end of construction.
|
||||
*/
|
||||
void end()
|
||||
{
|
||||
flush();
|
||||
m_delegate.atomCharacterClassEnd();
|
||||
}
|
||||
|
||||
// parseEscape() should never call these delegate methods when
|
||||
// invoked with inCharacterClass set.
|
||||
void assertionWordBoundary(bool) { JS_NOT_REACHED("parseEscape() should never call this"); }
|
||||
void atomBackReference(unsigned) { JS_NOT_REACHED("parseEscape() should never call this"); }
|
||||
|
||||
private:
|
||||
void flush()
|
||||
{
|
||||
if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen
|
||||
m_delegate.atomCharacterClassAtom(m_character);
|
||||
if (m_state == cachedCharacterHyphen)
|
||||
m_delegate.atomCharacterClassAtom('-');
|
||||
m_state = empty;
|
||||
}
|
||||
|
||||
Delegate& m_delegate;
|
||||
ErrorCode& m_err;
|
||||
enum CharacterClassConstructionState {
|
||||
empty,
|
||||
cachedCharacter,
|
||||
cachedCharacterHyphen
|
||||
} m_state;
|
||||
UChar m_character;
|
||||
};
|
||||
|
||||
Parser(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit)
|
||||
: m_delegate(delegate)
|
||||
, m_backReferenceLimit(backReferenceLimit)
|
||||
, m_err(NoError)
|
||||
, m_data(const_cast<UString &>(pattern).chars())
|
||||
, m_size(pattern.length())
|
||||
, m_index(0)
|
||||
, m_parenthesesNestingDepth(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* parseEscape():
|
||||
*
|
||||
* Helper for parseTokens() AND parseCharacterClass().
|
||||
* Unlike the other parser methods, this function does not report tokens
|
||||
* directly to the member delegate (m_delegate), instead tokens are
|
||||
* emitted to the delegate provided as an argument. In the case of atom
|
||||
* escapes, parseTokens() will call parseEscape() passing m_delegate as
|
||||
* an argument, and as such the escape will be reported to the delegate.
|
||||
*
|
||||
* However this method may also be used by parseCharacterClass(), in which
|
||||
* case a CharacterClassParserDelegate will be passed as the delegate that
|
||||
* tokens should be added to. A boolean flag is also provided to indicate
|
||||
* whether that an escape in a CharacterClass is being parsed (some parsing
|
||||
* rules change in this context).
|
||||
*
|
||||
* The boolean value returned by this method indicates whether the token
|
||||
* parsed was an atom (outside of a characted class \b and \B will be
|
||||
* interpreted as assertions).
|
||||
*/
|
||||
template<bool inCharacterClass, class EscapeDelegate>
|
||||
bool parseEscape(EscapeDelegate& delegate)
|
||||
{
|
||||
JS_ASSERT(!m_err);
|
||||
JS_ASSERT(peek() == '\\');
|
||||
consume();
|
||||
|
||||
if (atEndOfPattern()) {
|
||||
m_err = EscapeUnterminated;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (peek()) {
|
||||
// Assertions
|
||||
case 'b':
|
||||
consume();
|
||||
if (inCharacterClass)
|
||||
delegate.atomPatternCharacter('\b');
|
||||
else {
|
||||
delegate.assertionWordBoundary(false);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
consume();
|
||||
if (inCharacterClass)
|
||||
delegate.atomPatternCharacter('B');
|
||||
else {
|
||||
delegate.assertionWordBoundary(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
// CharacterClassEscape
|
||||
case 'd':
|
||||
consume();
|
||||
delegate.atomBuiltInCharacterClass(DigitClassID, false);
|
||||
break;
|
||||
case 's':
|
||||
consume();
|
||||
delegate.atomBuiltInCharacterClass(SpaceClassID, false);
|
||||
break;
|
||||
case 'w':
|
||||
consume();
|
||||
delegate.atomBuiltInCharacterClass(WordClassID, false);
|
||||
break;
|
||||
case 'D':
|
||||
consume();
|
||||
delegate.atomBuiltInCharacterClass(DigitClassID, true);
|
||||
break;
|
||||
case 'S':
|
||||
consume();
|
||||
delegate.atomBuiltInCharacterClass(SpaceClassID, true);
|
||||
break;
|
||||
case 'W':
|
||||
consume();
|
||||
delegate.atomBuiltInCharacterClass(WordClassID, true);
|
||||
break;
|
||||
|
||||
// DecimalEscape
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': {
|
||||
// To match Firefox, we parse an invalid backreference in the range [1-7] as an octal escape.
|
||||
// First, try to parse this as backreference.
|
||||
if (!inCharacterClass) {
|
||||
ParseState state = saveState();
|
||||
|
||||
unsigned backReference;
|
||||
if (!consumeNumber(backReference))
|
||||
return false;
|
||||
if (backReference <= m_backReferenceLimit) {
|
||||
delegate.atomBackReference(backReference);
|
||||
break;
|
||||
}
|
||||
|
||||
restoreState(state);
|
||||
}
|
||||
|
||||
// Not a backreference, and not octal.
|
||||
if (peek() >= '8') {
|
||||
delegate.atomPatternCharacter('\\');
|
||||
break;
|
||||
}
|
||||
|
||||
// Fall-through to handle this as an octal escape.
|
||||
}
|
||||
|
||||
// Octal escape
|
||||
case '0':
|
||||
delegate.atomPatternCharacter(consumeOctal());
|
||||
break;
|
||||
|
||||
// ControlEscape
|
||||
case 'f':
|
||||
consume();
|
||||
delegate.atomPatternCharacter('\f');
|
||||
break;
|
||||
case 'n':
|
||||
consume();
|
||||
delegate.atomPatternCharacter('\n');
|
||||
break;
|
||||
case 'r':
|
||||
consume();
|
||||
delegate.atomPatternCharacter('\r');
|
||||
break;
|
||||
case 't':
|
||||
consume();
|
||||
delegate.atomPatternCharacter('\t');
|
||||
break;
|
||||
case 'v':
|
||||
consume();
|
||||
delegate.atomPatternCharacter('\v');
|
||||
break;
|
||||
|
||||
// ControlLetter
|
||||
case 'c': {
|
||||
ParseState state = saveState();
|
||||
consume();
|
||||
if (!atEndOfPattern()) {
|
||||
int control = consume();
|
||||
|
||||
// To match Firefox, inside a character class, we also accept numbers and '_' as control characters.
|
||||
if (inCharacterClass ? WTF::isASCIIAlphanumeric(control) || (control == '_') : WTF::isASCIIAlpha(control)) {
|
||||
delegate.atomPatternCharacter(control & 0x1f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
restoreState(state);
|
||||
delegate.atomPatternCharacter('\\');
|
||||
break;
|
||||
}
|
||||
|
||||
// HexEscape
|
||||
case 'x': {
|
||||
consume();
|
||||
int x = tryConsumeHex(2);
|
||||
if (x == -1)
|
||||
delegate.atomPatternCharacter('x');
|
||||
else
|
||||
delegate.atomPatternCharacter(x);
|
||||
break;
|
||||
}
|
||||
|
||||
// UnicodeEscape
|
||||
case 'u': {
|
||||
consume();
|
||||
int u = tryConsumeHex(4);
|
||||
if (u == -1)
|
||||
delegate.atomPatternCharacter('u');
|
||||
else
|
||||
delegate.atomPatternCharacter(u);
|
||||
break;
|
||||
}
|
||||
|
||||
// IdentityEscape
|
||||
default:
|
||||
delegate.atomPatternCharacter(consume());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* parseAtomEscape(), parseCharacterClassEscape():
|
||||
*
|
||||
* These methods alias to parseEscape().
|
||||
*/
|
||||
bool parseAtomEscape()
|
||||
{
|
||||
return parseEscape<false>(m_delegate);
|
||||
}
|
||||
void parseCharacterClassEscape(CharacterClassParserDelegate& delegate)
|
||||
{
|
||||
parseEscape<true>(delegate);
|
||||
}
|
||||
|
||||
/*
|
||||
* parseCharacterClass():
|
||||
*
|
||||
* Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape)
|
||||
* to an instance of CharacterClassParserDelegate, to describe the character class to the
|
||||
* delegate.
|
||||
*/
|
||||
void parseCharacterClass()
|
||||
{
|
||||
JS_ASSERT(!m_err);
|
||||
JS_ASSERT(peek() == '[');
|
||||
consume();
|
||||
|
||||
CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err);
|
||||
|
||||
characterClassConstructor.begin(tryConsume('^'));
|
||||
|
||||
while (!atEndOfPattern()) {
|
||||
switch (peek()) {
|
||||
case ']':
|
||||
consume();
|
||||
characterClassConstructor.end();
|
||||
return;
|
||||
|
||||
case '\\':
|
||||
parseCharacterClassEscape(characterClassConstructor);
|
||||
break;
|
||||
|
||||
default:
|
||||
characterClassConstructor.atomPatternCharacterUnescaped(consume());
|
||||
}
|
||||
|
||||
if (m_err)
|
||||
return;
|
||||
}
|
||||
|
||||
m_err = CharacterClassUnmatched;
|
||||
}
|
||||
|
||||
/*
|
||||
* parseParenthesesBegin():
|
||||
*
|
||||
* Helper for parseTokens(); checks for parentheses types other than regular capturing subpatterns.
|
||||
*/
|
||||
void parseParenthesesBegin()
|
||||
{
|
||||
JS_ASSERT(!m_err);
|
||||
JS_ASSERT(peek() == '(');
|
||||
consume();
|
||||
|
||||
if (tryConsume('?')) {
|
||||
if (atEndOfPattern()) {
|
||||
m_err = ParenthesesTypeInvalid;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (consume()) {
|
||||
case ':':
|
||||
m_delegate.atomParenthesesSubpatternBegin(false);
|
||||
break;
|
||||
|
||||
case '=':
|
||||
m_delegate.atomParentheticalAssertionBegin();
|
||||
break;
|
||||
|
||||
case '!':
|
||||
m_delegate.atomParentheticalAssertionBegin(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
m_err = ParenthesesTypeInvalid;
|
||||
}
|
||||
} else
|
||||
m_delegate.atomParenthesesSubpatternBegin();
|
||||
|
||||
++m_parenthesesNestingDepth;
|
||||
}
|
||||
|
||||
/*
|
||||
* parseParenthesesEnd():
|
||||
*
|
||||
* Helper for parseTokens(); checks for parse errors (due to unmatched parentheses).
|
||||
*/
|
||||
void parseParenthesesEnd()
|
||||
{
|
||||
JS_ASSERT(!m_err);
|
||||
JS_ASSERT(peek() == ')');
|
||||
consume();
|
||||
|
||||
if (m_parenthesesNestingDepth > 0)
|
||||
m_delegate.atomParenthesesEnd();
|
||||
else
|
||||
m_err = ParenthesesUnmatched;
|
||||
|
||||
--m_parenthesesNestingDepth;
|
||||
}
|
||||
|
||||
/*
|
||||
* parseQuantifier():
|
||||
*
|
||||
* Helper for parseTokens(); checks for parse errors and non-greedy quantifiers.
|
||||
*/
|
||||
void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max)
|
||||
{
|
||||
JS_ASSERT(!m_err);
|
||||
JS_ASSERT(min <= max);
|
||||
|
||||
if (lastTokenWasAnAtom)
|
||||
m_delegate.quantifyAtom(min, max, !tryConsume('?'));
|
||||
else
|
||||
m_err = QuantifierWithoutAtom;
|
||||
}
|
||||
|
||||
/*
|
||||
* parseTokens():
|
||||
*
|
||||
* This method loops over the input pattern reporting tokens to the delegate.
|
||||
* The method returns when a parse error is detected, or the end of the pattern
|
||||
* is reached. One piece of state is tracked around the loop, which is whether
|
||||
* the last token passed to the delegate was an atom (this is necessary to detect
|
||||
* a parse error when a quantifier provided without an atom to quantify).
|
||||
*/
|
||||
void parseTokens()
|
||||
{
|
||||
bool lastTokenWasAnAtom = false;
|
||||
|
||||
while (!atEndOfPattern()) {
|
||||
switch (peek()) {
|
||||
case '|':
|
||||
consume();
|
||||
m_delegate.disjunction();
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
parseParenthesesBegin();
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
parseParenthesesEnd();
|
||||
lastTokenWasAnAtom = true;
|
||||
break;
|
||||
|
||||
case '^':
|
||||
consume();
|
||||
m_delegate.assertionBOL();
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
|
||||
case '$':
|
||||
consume();
|
||||
m_delegate.assertionEOL();
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
consume();
|
||||
m_delegate.atomBuiltInCharacterClass(NewlineClassID, true);
|
||||
lastTokenWasAnAtom = true;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
parseCharacterClass();
|
||||
lastTokenWasAnAtom = true;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
lastTokenWasAnAtom = parseAtomEscape();
|
||||
break;
|
||||
|
||||
case '*':
|
||||
consume();
|
||||
parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX);
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
consume();
|
||||
parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX);
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
consume();
|
||||
parseQuantifier(lastTokenWasAnAtom, 0, 1);
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
|
||||
case '{': {
|
||||
ParseState state = saveState();
|
||||
|
||||
consume();
|
||||
if (peekIsDigit()) {
|
||||
unsigned min;
|
||||
if (!consumeNumber(min))
|
||||
break;
|
||||
unsigned max = min;
|
||||
|
||||
if (tryConsume(',')) {
|
||||
if (peekIsDigit()) {
|
||||
if (!consumeNumber(max))
|
||||
break;
|
||||
} else {
|
||||
max = UINT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
if (tryConsume('}')) {
|
||||
if (min <= max)
|
||||
parseQuantifier(lastTokenWasAnAtom, min, max);
|
||||
else
|
||||
m_err = QuantifierOutOfOrder;
|
||||
lastTokenWasAnAtom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
restoreState(state);
|
||||
} // if we did not find a complete quantifer, fall through to the default case.
|
||||
|
||||
default:
|
||||
m_delegate.atomPatternCharacter(consume());
|
||||
lastTokenWasAnAtom = true;
|
||||
}
|
||||
|
||||
if (m_err)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_parenthesesNestingDepth > 0)
|
||||
m_err = MissingParentheses;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse():
|
||||
*
|
||||
* This method calls regexBegin(), calls parseTokens() to parse over the input
|
||||
* patterns, calls regexEnd() or regexError() as appropriate, and converts any
|
||||
* error code to a const char* for a result.
|
||||
*/
|
||||
int parse()
|
||||
{
|
||||
m_delegate.regexBegin();
|
||||
|
||||
if (m_size > MAX_PATTERN_SIZE)
|
||||
m_err = PatternTooLarge;
|
||||
else
|
||||
parseTokens();
|
||||
JS_ASSERT(atEndOfPattern() || m_err);
|
||||
|
||||
if (m_err)
|
||||
m_delegate.regexError();
|
||||
else
|
||||
m_delegate.regexEnd();
|
||||
|
||||
return static_cast<int>(m_err);
|
||||
}
|
||||
|
||||
|
||||
// Misc helper functions:
|
||||
|
||||
typedef unsigned ParseState;
|
||||
|
||||
ParseState saveState()
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
void restoreState(ParseState state)
|
||||
{
|
||||
m_index = state;
|
||||
}
|
||||
|
||||
bool atEndOfPattern()
|
||||
{
|
||||
JS_ASSERT(m_index <= m_size);
|
||||
return m_index == m_size;
|
||||
}
|
||||
|
||||
int peek()
|
||||
{
|
||||
JS_ASSERT(m_index < m_size);
|
||||
return m_data[m_index];
|
||||
}
|
||||
|
||||
bool peekIsDigit()
|
||||
{
|
||||
return !atEndOfPattern() && WTF::isASCIIDigit(peek());
|
||||
}
|
||||
|
||||
unsigned peekDigit()
|
||||
{
|
||||
JS_ASSERT(peekIsDigit());
|
||||
return peek() - '0';
|
||||
}
|
||||
|
||||
int consume()
|
||||
{
|
||||
JS_ASSERT(m_index < m_size);
|
||||
return m_data[m_index++];
|
||||
}
|
||||
|
||||
unsigned consumeDigit()
|
||||
{
|
||||
JS_ASSERT(peekIsDigit());
|
||||
return consume() - '0';
|
||||
}
|
||||
|
||||
bool consumeNumber(unsigned &accum)
|
||||
{
|
||||
accum = consumeDigit();
|
||||
while (peekIsDigit()) {
|
||||
unsigned newValue = accum * 10 + peekDigit();
|
||||
if (newValue < accum) { /* Overflow check. */
|
||||
m_err = QuantifierTooLarge;
|
||||
return false;
|
||||
}
|
||||
accum = newValue;
|
||||
consume();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned consumeOctal()
|
||||
{
|
||||
JS_ASSERT(WTF::isASCIIOctalDigit(peek()));
|
||||
|
||||
unsigned n = consumeDigit();
|
||||
while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek()))
|
||||
n = n * 8 + consumeDigit();
|
||||
return n;
|
||||
}
|
||||
|
||||
bool tryConsume(UChar ch)
|
||||
{
|
||||
if (atEndOfPattern() || (m_data[m_index] != ch))
|
||||
return false;
|
||||
++m_index;
|
||||
return true;
|
||||
}
|
||||
|
||||
int tryConsumeHex(int count)
|
||||
{
|
||||
ParseState state = saveState();
|
||||
|
||||
int n = 0;
|
||||
while (count--) {
|
||||
if (atEndOfPattern() || !WTF::isASCIIHexDigit(peek())) {
|
||||
restoreState(state);
|
||||
return -1;
|
||||
}
|
||||
n = (n << 4) | WTF::toASCIIHexValue(consume());
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
Delegate& m_delegate;
|
||||
unsigned m_backReferenceLimit;
|
||||
ErrorCode m_err;
|
||||
const UChar* m_data;
|
||||
unsigned m_size;
|
||||
unsigned m_index;
|
||||
unsigned m_parenthesesNestingDepth;
|
||||
|
||||
// Derived by empirical testing of compile time in PCRE and WREC.
|
||||
static const unsigned MAX_PATTERN_SIZE = 1024 * 1024;
|
||||
};
|
||||
|
||||
/*
|
||||
* Yarr::parse():
|
||||
*
|
||||
* The parse method is passed a pattern to be parsed and a delegate upon which
|
||||
* callbacks will be made to record the parsed tokens forming the regex.
|
||||
* Yarr::parse() returns null on success, or a const C string providing an error
|
||||
* message where a parse error occurs.
|
||||
*
|
||||
* The Delegate must implement the following interface:
|
||||
*
|
||||
* void assertionBOL();
|
||||
* void assertionEOL();
|
||||
* void assertionWordBoundary(bool invert);
|
||||
*
|
||||
* void atomPatternCharacter(UChar ch);
|
||||
* void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert);
|
||||
* void atomCharacterClassBegin(bool invert)
|
||||
* void atomCharacterClassAtom(UChar ch)
|
||||
* void atomCharacterClassRange(UChar begin, UChar end)
|
||||
* void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
|
||||
* void atomCharacterClassEnd()
|
||||
* void atomParenthesesSubpatternBegin(bool capture = true);
|
||||
* void atomParentheticalAssertionBegin(bool invert = false);
|
||||
* void atomParenthesesEnd();
|
||||
* void atomBackReference(unsigned subpatternId);
|
||||
*
|
||||
* void quantifyAtom(unsigned min, unsigned max, bool greedy);
|
||||
*
|
||||
* void disjunction();
|
||||
*
|
||||
* void regexBegin();
|
||||
* void regexEnd();
|
||||
* void regexError();
|
||||
*
|
||||
* Before any call recording tokens are made, regexBegin() will be called on the
|
||||
* delegate once. Once parsing is complete either regexEnd() or regexError() will
|
||||
* be called, as appropriate.
|
||||
*
|
||||
* The regular expression is described by a sequence of assertion*() and atom*()
|
||||
* callbacks to the delegate, describing the terms in the regular expression.
|
||||
* Following an atom a quantifyAtom() call may occur to indicate that the previous
|
||||
* atom should be quantified. In the case of atoms described across multiple
|
||||
* calls (parentheses and character classes) the call to quantifyAtom() will come
|
||||
* after the call to the atom*End() method, never after atom*Begin().
|
||||
*
|
||||
* Character classes may either be described by a single call to
|
||||
* atomBuiltInCharacterClass(), or by a sequence of atomCharacterClass*() calls.
|
||||
* In the latter case, ...Begin() will be called, followed by a sequence of
|
||||
* calls to ...Atom(), ...Range(), and ...BuiltIn(), followed by a call to ...End().
|
||||
*
|
||||
* Sequences of atoms and assertions are broken into alternatives via calls to
|
||||
* disjunction(). Assertions, atoms, and disjunctions emitted between calls to
|
||||
* atomParenthesesBegin() and atomParenthesesEnd() form the body of a subpattern.
|
||||
* atomParenthesesBegin() is passed a subpatternId. In the case of a regular
|
||||
* capturing subpattern, this will be the subpatternId associated with these
|
||||
* parentheses, and will also by definition be the lowest subpatternId of these
|
||||
* parentheses and of any nested paretheses. The atomParenthesesEnd() method
|
||||
* is passed the subpatternId of the last capturing subexpression nested within
|
||||
* these paretheses. In the case of a capturing subpattern with no nested
|
||||
* capturing subpatterns, the same subpatternId will be passed to the begin and
|
||||
* end functions. In the case of non-capturing subpatterns the subpatternId
|
||||
* passed to the begin method is also the first possible subpatternId that might
|
||||
* be nested within these paretheses. If a set of non-capturing parentheses does
|
||||
* not contain any capturing subpatterns, then the subpatternId passed to begin
|
||||
* will be greater than the subpatternId passed to end.
|
||||
*/
|
||||
|
||||
template<class Delegate>
|
||||
int parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX)
|
||||
{
|
||||
return Parser<Delegate>(delegate, pattern, backReferenceLimit).parse();
|
||||
}
|
||||
|
||||
} } // namespace JSC::Yarr
|
||||
|
||||
#endif // RegexParser_h
|
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RegexPattern_h
|
||||
#define RegexPattern_h
|
||||
|
||||
|
||||
#include "jsvector.h"
|
||||
#include "yarr/jswtfbridge.h"
|
||||
|
||||
|
||||
namespace JSC { namespace Yarr {
|
||||
|
||||
#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
|
||||
#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
|
||||
#define RegexStackSpaceForBackTrackInfoBackReference 2
|
||||
#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
|
||||
#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1
|
||||
#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
|
||||
#define RegexStackSpaceForBackTrackInfoParentheses 4
|
||||
|
||||
struct PatternDisjunction;
|
||||
|
||||
struct CharacterRange {
|
||||
UChar begin;
|
||||
UChar end;
|
||||
|
||||
CharacterRange(UChar begin, UChar end)
|
||||
: begin(begin)
|
||||
, end(end)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Wraps a table and indicates inversion. Can be efficiently borrowed
|
||||
* between character classes, so it's refcounted.
|
||||
*/
|
||||
struct CharacterClassTable {
|
||||
const char* m_table;
|
||||
bool m_inverted;
|
||||
jsrefcount m_refcount;
|
||||
|
||||
/* Ownership transferred to caller. */
|
||||
static CharacterClassTable *create(const char* table, bool inverted)
|
||||
{
|
||||
return new CharacterClassTable(table, inverted);
|
||||
}
|
||||
|
||||
void incref() { JS_ATOMIC_INCREMENT(&m_refcount); }
|
||||
void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) delete this; }
|
||||
|
||||
private:
|
||||
CharacterClassTable(const char* table, bool inverted)
|
||||
: m_table(table)
|
||||
, m_inverted(inverted)
|
||||
, m_refcount(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct CharacterClass {
|
||||
// All CharacterClass instances have to have the full set of matches and ranges,
|
||||
// they may have an optional table for faster lookups (which must match the
|
||||
// specified matches and ranges)
|
||||
CharacterClass(CharacterClassTable *table)
|
||||
: m_table(table)
|
||||
{
|
||||
if (m_table)
|
||||
m_table->incref();
|
||||
}
|
||||
~CharacterClass()
|
||||
{
|
||||
if (m_table)
|
||||
m_table->decref();
|
||||
}
|
||||
typedef js::Vector<UChar, 0, js::SystemAllocPolicy> UChars;
|
||||
typedef js::Vector<CharacterRange, 0, js::SystemAllocPolicy> CharacterRanges;
|
||||
UChars m_matches;
|
||||
CharacterRanges m_ranges;
|
||||
UChars m_matchesUnicode;
|
||||
CharacterRanges m_rangesUnicode;
|
||||
CharacterClassTable *m_table;
|
||||
};
|
||||
|
||||
enum QuantifierType {
|
||||
QuantifierFixedCount,
|
||||
QuantifierGreedy,
|
||||
QuantifierNonGreedy
|
||||
};
|
||||
|
||||
struct PatternTerm {
|
||||
enum Type {
|
||||
TypeAssertionBOL,
|
||||
TypeAssertionEOL,
|
||||
TypeAssertionWordBoundary,
|
||||
TypePatternCharacter,
|
||||
TypeCharacterClass,
|
||||
TypeBackReference,
|
||||
TypeForwardReference,
|
||||
TypeParenthesesSubpattern,
|
||||
TypeParentheticalAssertion
|
||||
} type;
|
||||
bool invertOrCapture;
|
||||
union {
|
||||
UChar patternCharacter;
|
||||
CharacterClass* characterClass;
|
||||
unsigned subpatternId;
|
||||
struct {
|
||||
PatternDisjunction* disjunction;
|
||||
unsigned subpatternId;
|
||||
unsigned lastSubpatternId;
|
||||
bool isCopy;
|
||||
} parentheses;
|
||||
};
|
||||
QuantifierType quantityType;
|
||||
unsigned quantityCount;
|
||||
int inputPosition;
|
||||
unsigned frameLocation;
|
||||
|
||||
PatternTerm(UChar ch)
|
||||
: type(PatternTerm::TypePatternCharacter)
|
||||
{
|
||||
patternCharacter = ch;
|
||||
quantityType = QuantifierFixedCount;
|
||||
quantityCount = 1;
|
||||
}
|
||||
|
||||
PatternTerm(CharacterClass* charClass, bool invert)
|
||||
: type(PatternTerm::TypeCharacterClass)
|
||||
, invertOrCapture(invert)
|
||||
{
|
||||
characterClass = charClass;
|
||||
quantityType = QuantifierFixedCount;
|
||||
quantityCount = 1;
|
||||
}
|
||||
|
||||
PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture)
|
||||
: type(type)
|
||||
, invertOrCapture(invertOrCapture)
|
||||
{
|
||||
parentheses.disjunction = disjunction;
|
||||
parentheses.subpatternId = subpatternId;
|
||||
parentheses.isCopy = false;
|
||||
quantityType = QuantifierFixedCount;
|
||||
quantityCount = 1;
|
||||
}
|
||||
|
||||
PatternTerm(Type type, bool invert = false)
|
||||
: type(type)
|
||||
, invertOrCapture(invert)
|
||||
{
|
||||
quantityType = QuantifierFixedCount;
|
||||
quantityCount = 1;
|
||||
}
|
||||
|
||||
PatternTerm(unsigned spatternId)
|
||||
: type(TypeBackReference)
|
||||
, invertOrCapture(false)
|
||||
{
|
||||
subpatternId = spatternId;
|
||||
quantityType = QuantifierFixedCount;
|
||||
quantityCount = 1;
|
||||
}
|
||||
|
||||
static PatternTerm ForwardReference()
|
||||
{
|
||||
return PatternTerm(TypeForwardReference);
|
||||
}
|
||||
|
||||
static PatternTerm BOL()
|
||||
{
|
||||
return PatternTerm(TypeAssertionBOL);
|
||||
}
|
||||
|
||||
static PatternTerm EOL()
|
||||
{
|
||||
return PatternTerm(TypeAssertionEOL);
|
||||
}
|
||||
|
||||
static PatternTerm WordBoundary(bool invert)
|
||||
{
|
||||
return PatternTerm(TypeAssertionWordBoundary, invert);
|
||||
}
|
||||
|
||||
bool invert()
|
||||
{
|
||||
return invertOrCapture;
|
||||
}
|
||||
|
||||
bool capture()
|
||||
{
|
||||
return invertOrCapture;
|
||||
}
|
||||
|
||||
void quantify(unsigned count, QuantifierType type)
|
||||
{
|
||||
quantityCount = count;
|
||||
quantityType = type;
|
||||
}
|
||||
};
|
||||
|
||||
struct PatternAlternative {
|
||||
PatternAlternative(PatternDisjunction* disjunction)
|
||||
: m_parent(disjunction)
|
||||
{
|
||||
}
|
||||
|
||||
PatternTerm& lastTerm()
|
||||
{
|
||||
JS_ASSERT(m_terms.length());
|
||||
return m_terms[m_terms.length() - 1];
|
||||
}
|
||||
|
||||
void removeLastTerm()
|
||||
{
|
||||
JS_ASSERT(m_terms.length());
|
||||
m_terms.popBack();
|
||||
}
|
||||
|
||||
js::Vector<PatternTerm, 0, js::SystemAllocPolicy> m_terms;
|
||||
PatternDisjunction* m_parent;
|
||||
unsigned m_minimumSize;
|
||||
bool m_hasFixedSize;
|
||||
};
|
||||
|
||||
struct PatternDisjunction {
|
||||
PatternDisjunction(PatternAlternative* parent = 0)
|
||||
: m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
~PatternDisjunction()
|
||||
{
|
||||
deleteAllValues(m_alternatives);
|
||||
}
|
||||
|
||||
PatternAlternative* addNewAlternative()
|
||||
{
|
||||
PatternAlternative* alternative = new PatternAlternative(this);
|
||||
m_alternatives.append(alternative);
|
||||
return alternative;
|
||||
}
|
||||
|
||||
js::Vector<PatternAlternative*, 0, js::SystemAllocPolicy> m_alternatives;
|
||||
PatternAlternative* m_parent;
|
||||
unsigned m_minimumSize;
|
||||
unsigned m_callFrameSize;
|
||||
bool m_hasFixedSize;
|
||||
};
|
||||
|
||||
// You probably don't want to be calling these functions directly
|
||||
// (please to be calling newlineCharacterClass() et al on your
|
||||
// friendly neighborhood RegexPattern instance to get nicely
|
||||
// cached copies).
|
||||
CharacterClass* newlineCreate();
|
||||
CharacterClass* digitsCreate();
|
||||
CharacterClass* spacesCreate();
|
||||
CharacterClass* wordcharCreate();
|
||||
CharacterClass* nondigitsCreate();
|
||||
CharacterClass* nonspacesCreate();
|
||||
CharacterClass* nonwordcharCreate();
|
||||
|
||||
struct RegexPattern {
|
||||
RegexPattern(bool ignoreCase, bool multiline)
|
||||
: m_ignoreCase(ignoreCase)
|
||||
, m_multiline(multiline)
|
||||
, m_numSubpatterns(0)
|
||||
, m_maxBackReference(0)
|
||||
, m_containsBackreferences(false)
|
||||
, newlineCached(0)
|
||||
, digitsCached(0)
|
||||
, spacesCached(0)
|
||||
, wordcharCached(0)
|
||||
, nondigitsCached(0)
|
||||
, nonspacesCached(0)
|
||||
, nonwordcharCached(0)
|
||||
{
|
||||
}
|
||||
|
||||
~RegexPattern()
|
||||
{
|
||||
deleteAllValues(m_disjunctions);
|
||||
deleteAllValues(m_userCharacterClasses);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_numSubpatterns = 0;
|
||||
m_maxBackReference = 0;
|
||||
|
||||
m_containsBackreferences = false;
|
||||
|
||||
newlineCached = 0;
|
||||
digitsCached = 0;
|
||||
spacesCached = 0;
|
||||
wordcharCached = 0;
|
||||
nondigitsCached = 0;
|
||||
nonspacesCached = 0;
|
||||
nonwordcharCached = 0;
|
||||
|
||||
deleteAllValues(m_disjunctions);
|
||||
m_disjunctions.clear();
|
||||
deleteAllValues(m_userCharacterClasses);
|
||||
m_userCharacterClasses.clear();
|
||||
}
|
||||
|
||||
bool containsIllegalBackReference()
|
||||
{
|
||||
return m_maxBackReference > m_numSubpatterns;
|
||||
}
|
||||
|
||||
CharacterClass* newlineCharacterClass()
|
||||
{
|
||||
if (!newlineCached)
|
||||
m_userCharacterClasses.append(newlineCached = newlineCreate());
|
||||
return newlineCached;
|
||||
}
|
||||
CharacterClass* digitsCharacterClass()
|
||||
{
|
||||
if (!digitsCached)
|
||||
m_userCharacterClasses.append(digitsCached = digitsCreate());
|
||||
return digitsCached;
|
||||
}
|
||||
CharacterClass* spacesCharacterClass()
|
||||
{
|
||||
if (!spacesCached)
|
||||
m_userCharacterClasses.append(spacesCached = spacesCreate());
|
||||
return spacesCached;
|
||||
}
|
||||
CharacterClass* wordcharCharacterClass()
|
||||
{
|
||||
if (!wordcharCached)
|
||||
m_userCharacterClasses.append(wordcharCached = wordcharCreate());
|
||||
return wordcharCached;
|
||||
}
|
||||
CharacterClass* nondigitsCharacterClass()
|
||||
{
|
||||
if (!nondigitsCached)
|
||||
m_userCharacterClasses.append(nondigitsCached = nondigitsCreate());
|
||||
return nondigitsCached;
|
||||
}
|
||||
CharacterClass* nonspacesCharacterClass()
|
||||
{
|
||||
if (!nonspacesCached)
|
||||
m_userCharacterClasses.append(nonspacesCached = nonspacesCreate());
|
||||
return nonspacesCached;
|
||||
}
|
||||
CharacterClass* nonwordcharCharacterClass()
|
||||
{
|
||||
if (!nonwordcharCached)
|
||||
m_userCharacterClasses.append(nonwordcharCached = nonwordcharCreate());
|
||||
return nonwordcharCached;
|
||||
}
|
||||
|
||||
bool m_ignoreCase;
|
||||
bool m_multiline;
|
||||
unsigned m_numSubpatterns;
|
||||
unsigned m_maxBackReference;
|
||||
bool m_containsBackreferences;
|
||||
PatternDisjunction *m_body;
|
||||
js::Vector<PatternDisjunction*, 4, js::SystemAllocPolicy> m_disjunctions;
|
||||
js::Vector<CharacterClass*, 0, js::SystemAllocPolicy> m_userCharacterClasses;
|
||||
|
||||
private:
|
||||
CharacterClass* newlineCached;
|
||||
CharacterClass* digitsCached;
|
||||
CharacterClass* spacesCached;
|
||||
CharacterClass* wordcharCached;
|
||||
CharacterClass* nondigitsCached;
|
||||
CharacterClass* nonspacesCached;
|
||||
CharacterClass* nonwordcharCached;
|
||||
};
|
||||
|
||||
} } // namespace JSC::Yarr
|
||||
|
||||
#endif // RegexPattern_h
|
Загрузка…
Ссылка в новой задаче