Bug 564953: Port of Yarr regexp engine and Nitro macroassembler. No PPC support. (r=gal,lw)

This commit is contained in:
Chris Leary 2010-07-02 22:25:37 -07:00
Родитель 0a7922e78a
Коммит 9975411941
74 изменённых файлов: 32143 добавлений и 5654 удалений

Просмотреть файл

@ -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, &regexpPool);
FreeOldArenas(runtime, &regExpPool);
}

Просмотреть файл

@ -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;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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___ */

419
js/src/jsregexpinlines.h Normal file
Просмотреть файл

@ -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)

Просмотреть файл

@ -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;

5
js/src/yarr/Makefile Normal file
Просмотреть файл

@ -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

75
js/src/yarr/jswtfbridge.h Normal file
Просмотреть файл

@ -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

12
js/src/yarr/pcre/AUTHORS Normal file
Просмотреть файл

@ -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.

35
js/src/yarr/pcre/COPYING Normal file
Просмотреть файл

@ -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 */

273
js/src/yarr/pcre/dftables Executable file
Просмотреть файл

@ -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;
}

69
js/src/yarr/pcre/pcre.h Normal file
Просмотреть файл

@ -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

12
js/src/yarr/pcre/pcre.pri Normal file
Просмотреть файл

@ -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