first commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
go-pcre
|
||||
go-pcre.exe
|
||||
@@ -0,0 +1,55 @@
|
||||
# go-pcre
|
||||
|
||||
[](https://pkg.go.dev/github.com/scorpionknifes/go-pcre)
|
||||
|
||||
This is a Go language package providing support for
|
||||
Perl Compatible Regular Expressions (PCRE).
|
||||
|
||||
Current version is pcre 8.45
|
||||
|
||||
## Features:
|
||||
|
||||
- Support Windows, Linux & MacOS
|
||||
|
||||
## Installation
|
||||
|
||||
Install the package with the following:
|
||||
|
||||
go get github.com/scorpionknifes/go-pcre
|
||||
|
||||
## Usage
|
||||
|
||||
Go programs that depend on this package should import
|
||||
this package as follows to allow automatic downloading:
|
||||
|
||||
import "github.com/scorpionknifes/go-pcre"
|
||||
|
||||
## History
|
||||
|
||||
This is a clone of [go-pcre](https://github.com/rubrikinc/go-pcre)
|
||||
|
||||
This was a clone of
|
||||
[golang-pkg-pcre](http://git.enyo.de/fw/debian/golang-pkg-pcre.git)
|
||||
by Florian Weimer, which has been placed on Github by Glenn Brown,
|
||||
so it can be fetched automatically by Go's package installer.
|
||||
|
||||
Glenn Brown added `FindIndex()` and `ReplaceAll()`
|
||||
to mimic functions in Go's default regexp package.
|
||||
|
||||
Mathieu Payeur Levallois added `Matcher.ExtractString()`.
|
||||
|
||||
Malte Nuhn added `GroupIndices()` to retrieve positions of a matching group.
|
||||
|
||||
Chandra Sekar S added `Index()` and stopped invoking `Match()` twice in `FindIndex()`.
|
||||
|
||||
Misakwa added support for `pkg-config` to locate `libpcre`.
|
||||
|
||||
Yann Ramin added `ReplaceAllString()` and changed `Compile()` return type to `error`.
|
||||
|
||||
Nikolay Sivko modified `name2index()` to return error instead of panic.
|
||||
|
||||
Harry Waye exposed raw `pcre_exec`.
|
||||
|
||||
Hazzadous added partial match support.
|
||||
|
||||
Pavel Gryaznov added support for JIT compilation.
|
||||
@@ -0,0 +1,60 @@
|
||||
/* config.h for CMake builds */
|
||||
|
||||
/* #undef HAVE_DIRENT_H */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
/* #undef HAVE_UNISTD_H */
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* #undef HAVE_TYPE_TRAITS_H */
|
||||
/* #undef HAVE_BITS_TYPE_TRAITS_H */
|
||||
|
||||
/* #undef HAVE_BCOPY */
|
||||
#define HAVE_MEMMOVE 1
|
||||
#define HAVE_STRERROR 1
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1800
|
||||
#define HAVE_STRTOLL 1
|
||||
#else
|
||||
/* #undef HAVE_STRTOLL */
|
||||
#endif
|
||||
/* #undef HAVE_STRTOQ */
|
||||
#define HAVE__STRTOI64 1
|
||||
|
||||
/* #undef PCRE_STATIC */ /* Defined through project settings. */
|
||||
|
||||
#define SUPPORT_PCRE8 1
|
||||
#define SUPPORT_PCRE16 1
|
||||
#define SUPPORT_PCRE32 1
|
||||
#define SUPPORT_JIT 1
|
||||
#define SUPPORT_PCREGREP_JIT 1
|
||||
#define SUPPORT_UTF 1
|
||||
#define SUPPORT_UCP 1
|
||||
/* #undef EBCDIC */
|
||||
/* #undef EBCDIC_NL25 */
|
||||
/* #undef BSR_ANYCRLF */
|
||||
/* #undef NO_RECURSE */
|
||||
|
||||
#define HAVE_LONG_LONG 1
|
||||
#define HAVE_UNSIGNED_LONG_LONG 1
|
||||
|
||||
/* #undef SUPPORT_LIBBZ2 */
|
||||
/* #undef SUPPORT_LIBZ */
|
||||
/* #undef SUPPORT_LIBEDIT */
|
||||
/* #undef SUPPORT_LIBREADLINE */
|
||||
|
||||
/* #undef SUPPORT_VALGRIND */
|
||||
/* #undef SUPPORT_GCOV */
|
||||
|
||||
#define NEWLINE 10
|
||||
#define POSIX_MALLOC_THRESHOLD 10
|
||||
#define LINK_SIZE 2
|
||||
#define PARENS_NEST_LIMIT 250
|
||||
#define MATCH_LIMIT 10000000
|
||||
#define MATCH_LIMIT_RECURSION MATCH_LIMIT
|
||||
#define PCREGREP_BUFSIZE 20480
|
||||
|
||||
#define MAX_NAME_SIZE 32
|
||||
#define MAX_NAME_COUNT 10000
|
||||
|
||||
/* end config.h for CMake builds */
|
||||
@@ -0,0 +1,650 @@
|
||||
// Copyright (c) 2011 Florian Weimer. 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.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package pcre
|
||||
|
||||
// #cgo CFLAGS: -DPCRE_STATIC
|
||||
// #include <string.h>
|
||||
// #include "./pcre.h"
|
||||
// static inline void pcre_free_stub(void *re) {
|
||||
// pcre_free(re);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Flags for Compile and Match functions.
|
||||
const (
|
||||
ANCHORED = C.PCRE_ANCHORED
|
||||
BSR_ANYCRLF = C.PCRE_BSR_ANYCRLF
|
||||
BSR_UNICODE = C.PCRE_BSR_UNICODE
|
||||
NEWLINE_ANY = C.PCRE_NEWLINE_ANY
|
||||
NEWLINE_ANYCRLF = C.PCRE_NEWLINE_ANYCRLF
|
||||
NEWLINE_CR = C.PCRE_NEWLINE_CR
|
||||
NEWLINE_CRLF = C.PCRE_NEWLINE_CRLF
|
||||
NEWLINE_LF = C.PCRE_NEWLINE_LF
|
||||
NO_START_OPTIMIZE = C.PCRE_NO_START_OPTIMIZE
|
||||
NO_UTF8_CHECK = C.PCRE_NO_UTF8_CHECK
|
||||
)
|
||||
|
||||
// Flags for Compile functions
|
||||
const (
|
||||
CASELESS = C.PCRE_CASELESS
|
||||
DOLLAR_ENDONLY = C.PCRE_DOLLAR_ENDONLY
|
||||
DOTALL = C.PCRE_DOTALL
|
||||
DUPNAMES = C.PCRE_DUPNAMES
|
||||
EXTENDED = C.PCRE_EXTENDED
|
||||
EXTRA = C.PCRE_EXTRA
|
||||
FIRSTLINE = C.PCRE_FIRSTLINE
|
||||
JAVASCRIPT_COMPAT = C.PCRE_JAVASCRIPT_COMPAT
|
||||
MULTILINE = C.PCRE_MULTILINE
|
||||
NEVER_UTF = C.PCRE_NEVER_UTF
|
||||
NO_AUTO_CAPTURE = C.PCRE_NO_AUTO_CAPTURE
|
||||
UNGREEDY = C.PCRE_UNGREEDY
|
||||
UTF8 = C.PCRE_UTF8
|
||||
UCP = C.PCRE_UCP
|
||||
)
|
||||
|
||||
// Flags for Match functions
|
||||
const (
|
||||
NOTBOL = C.PCRE_NOTBOL
|
||||
NOTEOL = C.PCRE_NOTEOL
|
||||
NOTEMPTY = C.PCRE_NOTEMPTY
|
||||
NOTEMPTY_ATSTART = C.PCRE_NOTEMPTY_ATSTART
|
||||
PARTIAL_HARD = C.PCRE_PARTIAL_HARD
|
||||
PARTIAL_SOFT = C.PCRE_PARTIAL_SOFT
|
||||
)
|
||||
|
||||
// Flags for Study function
|
||||
const (
|
||||
STUDY_JIT_COMPILE = C.PCRE_STUDY_JIT_COMPILE
|
||||
STUDY_JIT_PARTIAL_SOFT_COMPILE = C.PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
|
||||
STUDY_JIT_PARTIAL_HARD_COMPILE = C.PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE
|
||||
)
|
||||
|
||||
// Exec-time and get/set-time error codes
|
||||
const (
|
||||
ERROR_NOMATCH = C.PCRE_ERROR_NOMATCH
|
||||
ERROR_NULL = C.PCRE_ERROR_NULL
|
||||
ERROR_BADOPTION = C.PCRE_ERROR_BADOPTION
|
||||
ERROR_BADMAGIC = C.PCRE_ERROR_BADMAGIC
|
||||
ERROR_UNKNOWN_OPCODE = C.PCRE_ERROR_UNKNOWN_OPCODE
|
||||
ERROR_UNKNOWN_NODE = C.PCRE_ERROR_UNKNOWN_NODE
|
||||
ERROR_NOMEMORY = C.PCRE_ERROR_NOMEMORY
|
||||
ERROR_NOSUBSTRING = C.PCRE_ERROR_NOSUBSTRING
|
||||
ERROR_MATCHLIMIT = C.PCRE_ERROR_MATCHLIMIT
|
||||
ERROR_CALLOUT = C.PCRE_ERROR_CALLOUT
|
||||
ERROR_BADUTF8 = C.PCRE_ERROR_BADUTF8
|
||||
ERROR_BADUTF8_OFFSET = C.PCRE_ERROR_BADUTF8_OFFSET
|
||||
ERROR_PARTIAL = C.PCRE_ERROR_PARTIAL
|
||||
ERROR_BADPARTIAL = C.PCRE_ERROR_BADPARTIAL
|
||||
ERROR_RECURSIONLIMIT = C.PCRE_ERROR_RECURSIONLIMIT
|
||||
ERROR_INTERNAL = C.PCRE_ERROR_INTERNAL
|
||||
ERROR_BADCOUNT = C.PCRE_ERROR_BADCOUNT
|
||||
ERROR_JIT_STACKLIMIT = C.PCRE_ERROR_JIT_STACKLIMIT
|
||||
)
|
||||
|
||||
// Regexp holds a reference to a compiled regular expression.
|
||||
// Use Compile or MustCompile to create such objects.
|
||||
// Use FreeRegexp to free memory when done with the struct.
|
||||
type Regexp struct {
|
||||
ptr *C.pcre
|
||||
extra *C.pcre_extra
|
||||
}
|
||||
|
||||
// Number of bytes in the compiled pattern
|
||||
func pcreSize(ptr *C.pcre) (size C.size_t) {
|
||||
C.pcre_fullinfo(ptr, nil, C.PCRE_INFO_SIZE, unsafe.Pointer(&size))
|
||||
return
|
||||
}
|
||||
|
||||
// Number of capture groups
|
||||
func pcreGroups(ptr *C.pcre) (count C.int) {
|
||||
C.pcre_fullinfo(ptr, nil,
|
||||
C.PCRE_INFO_CAPTURECOUNT, unsafe.Pointer(&count))
|
||||
return
|
||||
}
|
||||
|
||||
// Free c allocated memory related to regexp.
|
||||
func (re *Regexp) FreeRegexp() {
|
||||
// pcre_free is a function pointer, call a stub that calls it.
|
||||
if re.ptr != nil {
|
||||
C.pcre_free_stub(unsafe.Pointer(re.ptr))
|
||||
re.ptr = nil
|
||||
}
|
||||
if re.extra != nil {
|
||||
C.pcre_free_study(re.extra)
|
||||
re.extra = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the pattern and return a compiled regexp.
|
||||
// If compilation fails, the second return value holds a *CompileError.
|
||||
func Compile(pattern string, flags int) (Regexp, error) {
|
||||
re := Regexp{}
|
||||
pattern1 := C.CString(pattern)
|
||||
defer C.free(unsafe.Pointer(pattern1))
|
||||
if clen := int(C.strlen(pattern1)); clen != len(pattern) {
|
||||
return Regexp{}, &CompileError{
|
||||
Pattern: pattern,
|
||||
Message: "NUL byte in pattern",
|
||||
Offset: clen,
|
||||
}
|
||||
}
|
||||
var errptr *C.char
|
||||
var erroffset C.int
|
||||
re.ptr = C.pcre_compile(pattern1, C.int(flags), &errptr, &erroffset, nil)
|
||||
if re.ptr == nil {
|
||||
return Regexp{}, &CompileError{
|
||||
Pattern: pattern,
|
||||
Message: C.GoString(errptr),
|
||||
Offset: int(erroffset),
|
||||
}
|
||||
}
|
||||
return re, nil
|
||||
}
|
||||
|
||||
// CompileJIT is a combination of Compile and Study. It first compiles
|
||||
// the pattern and if this succeeds calls Study on the compiled pattern.
|
||||
// comFlags are Compile flags, jitFlags are study flags.
|
||||
// If compilation fails, the second return value holds a *CompileError.
|
||||
func CompileJIT(pattern string, comFlags, jitFlags int) (Regexp, error) {
|
||||
re, err := Compile(pattern, comFlags)
|
||||
if err == nil {
|
||||
err = (&re).Study(jitFlags)
|
||||
}
|
||||
return re, err
|
||||
}
|
||||
|
||||
// MustCompile compiles the pattern. If compilation fails, panic.
|
||||
func MustCompile(pattern string, flags int) (re Regexp) {
|
||||
re, err := Compile(pattern, flags)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MustCompileJIT compiles and studies the pattern. On failure it panics.
|
||||
func MustCompileJIT(pattern string, comFlags, jitFlags int) (re Regexp) {
|
||||
re, err := CompileJIT(pattern, comFlags, jitFlags)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Study adds Just-In-Time compilation to a Regexp. This may give a huge
|
||||
// speed boost when matching. If an error occurs, return value is non-nil.
|
||||
// Flags optionally specifies JIT compilation options for partial matches.
|
||||
func (re *Regexp) Study(flags int) error {
|
||||
if re.extra != nil {
|
||||
return fmt.Errorf("Study: Regexp has already been optimized")
|
||||
}
|
||||
if flags == 0 {
|
||||
flags = STUDY_JIT_COMPILE
|
||||
}
|
||||
|
||||
var err *C.char
|
||||
re.extra = C.pcre_study(re.ptr, C.int(flags), &err)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", C.GoString(err))
|
||||
}
|
||||
if re.extra == nil {
|
||||
// Studying the pattern may not produce useful information.
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Groups returns the number of capture groups in the compiled pattern.
|
||||
func (re Regexp) Groups() int {
|
||||
if re.ptr == nil {
|
||||
panic("Regexp.Groups: uninitialized")
|
||||
}
|
||||
return int(pcreGroups(re.ptr))
|
||||
}
|
||||
|
||||
// Matcher objects provide a place for storing match results.
|
||||
// They can be created by the Matcher and MatcherString functions,
|
||||
// or they can be initialized with Reset or ResetString.
|
||||
type Matcher struct {
|
||||
re Regexp
|
||||
groups int
|
||||
ovector []C.int // scratch space for capture offsets
|
||||
matches bool // last match was successful
|
||||
partial bool // was the last match a partial match?
|
||||
subjects string // one of these fields is set to record the subject,
|
||||
subjectb []byte // so that Group/GroupString can return slices
|
||||
err error
|
||||
}
|
||||
|
||||
// NewMatcher creates a new matcher object for the given Regexp.
|
||||
func (re Regexp) NewMatcher() (m *Matcher) {
|
||||
m = new(Matcher)
|
||||
m.Init(&re)
|
||||
return
|
||||
}
|
||||
|
||||
// Matcher creates a new matcher object, with the byte slice as subject.
|
||||
// It also starts a first match on subject. Test for success with Matches().
|
||||
func (re Regexp) Matcher(subject []byte, flags int) (m *Matcher) {
|
||||
m = re.NewMatcher()
|
||||
m.Match(subject, flags)
|
||||
return
|
||||
}
|
||||
|
||||
// MatcherString creates a new matcher, with the specified subject string.
|
||||
// It also starts a first match on subject. Test for success with Matches().
|
||||
func (re Regexp) MatcherString(subject string, flags int) (m *Matcher) {
|
||||
m = re.NewMatcher()
|
||||
m.MatchString(subject, flags)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// Reset switches the matcher object to the specified regexp and subject.
|
||||
// It also starts a first match on subject.
|
||||
func (m *Matcher) Reset(re Regexp, subject []byte, flags int) bool {
|
||||
m.Init(&re)
|
||||
return m.Match(subject, flags)
|
||||
}
|
||||
|
||||
// ResetString switches the matcher object to the given regexp and subject.
|
||||
// It also starts a first match on subject.
|
||||
func (m *Matcher) ResetString(re Regexp, subject string, flags int) bool {
|
||||
m.Init(&re)
|
||||
return m.MatchString(subject, flags)
|
||||
}
|
||||
|
||||
// Init binds an existing Matcher object to the given Regexp.
|
||||
func (m *Matcher) Init(re *Regexp) {
|
||||
if re.ptr == nil {
|
||||
panic("Matcher.Init: uninitialized")
|
||||
}
|
||||
m.matches = false
|
||||
m.err = nil
|
||||
if m.re.ptr != nil && m.re.ptr == re.ptr {
|
||||
// Skip group count extraction if the matcher has
|
||||
// already been initialized with the same regular
|
||||
// expression.
|
||||
return
|
||||
}
|
||||
m.re = *re
|
||||
m.groups = re.Groups()
|
||||
if ovectorlen := 3 * (1 + m.groups); len(m.ovector) < ovectorlen {
|
||||
m.ovector = make([]C.int, ovectorlen)
|
||||
}
|
||||
}
|
||||
|
||||
// Err returns first error encountered by Matcher.
|
||||
func (m *Matcher) Err() error {
|
||||
return m.err
|
||||
}
|
||||
|
||||
var nullbyte = []byte{0}
|
||||
|
||||
// Match tries to match the specified byte slice to
|
||||
// the current pattern by calling Exec and collects the result.
|
||||
// Returns true if the match succeeds.
|
||||
// Match is a no-op if err is not nil.
|
||||
func (m *Matcher) Match(subject []byte, flags int) bool {
|
||||
if m.err != nil {
|
||||
return false
|
||||
}
|
||||
if m.re.ptr == nil {
|
||||
panic("Matcher.Match: uninitialized")
|
||||
}
|
||||
rc := m.Exec(subject, flags)
|
||||
m.matches, m.err = matched(rc)
|
||||
m.partial = (rc == ERROR_PARTIAL)
|
||||
return m.matches
|
||||
}
|
||||
|
||||
// MatchString tries to match the specified subject string to
|
||||
// the current pattern by calling ExecString and collects the result.
|
||||
// Returns true if the match succeeds.
|
||||
func (m *Matcher) MatchString(subject string, flags int) bool {
|
||||
if m.err != nil {
|
||||
return false
|
||||
}
|
||||
if m.re.ptr == nil {
|
||||
panic("Matcher.MatchString: uninitialized")
|
||||
}
|
||||
rc := m.ExecString(subject, flags)
|
||||
m.matches, m.err = matched(rc)
|
||||
m.partial = (rc == ERROR_PARTIAL)
|
||||
return m.matches
|
||||
}
|
||||
|
||||
// Exec tries to match the specified byte slice to
|
||||
// the current pattern. Returns the raw pcre_exec error code.
|
||||
func (m *Matcher) Exec(subject []byte, flags int) int {
|
||||
if m.re.ptr == nil {
|
||||
panic("Matcher.Exec: uninitialized")
|
||||
}
|
||||
length := len(subject)
|
||||
m.subjects = ""
|
||||
m.subjectb = subject
|
||||
if length == 0 {
|
||||
subject = nullbyte // make first character adressable
|
||||
}
|
||||
subjectptr := (*C.char)(unsafe.Pointer(&subject[0]))
|
||||
return m.exec(subjectptr, length, flags)
|
||||
}
|
||||
|
||||
// ExecString tries to match the specified subject string to
|
||||
// the current pattern. It returns the raw pcre_exec error code.
|
||||
func (m *Matcher) ExecString(subject string, flags int) int {
|
||||
if m.re.ptr == nil {
|
||||
panic("Matcher.ExecString: uninitialized")
|
||||
}
|
||||
length := len(subject)
|
||||
m.subjects = subject
|
||||
m.subjectb = nil
|
||||
if length == 0 {
|
||||
subject = "\000" // make first character addressable
|
||||
}
|
||||
// The following is a non-portable kludge to avoid a copy
|
||||
subjectptr := *(**C.char)(unsafe.Pointer(&subject))
|
||||
return m.exec(subjectptr, length, flags)
|
||||
}
|
||||
|
||||
func (m *Matcher) exec(subjectptr *C.char, length, flags int) int {
|
||||
rc := C.pcre_exec(m.re.ptr, m.re.extra,
|
||||
subjectptr, C.int(length),
|
||||
0, C.int(flags), &m.ovector[0], C.int(len(m.ovector)))
|
||||
return int(rc)
|
||||
}
|
||||
|
||||
// matched checks the return code of a pattern match for success.
|
||||
func matched(rc int) (bool, error) {
|
||||
switch {
|
||||
case rc >= 0 || rc == C.PCRE_ERROR_PARTIAL:
|
||||
return true, nil
|
||||
case rc == C.PCRE_ERROR_NOMATCH:
|
||||
return false, nil
|
||||
case rc == C.PCRE_ERROR_BADOPTION:
|
||||
return false, errors.New("PCRE.Match: invalid option flag")
|
||||
}
|
||||
err := errors.New(
|
||||
"unexpected return code from pcre_exec: " + strconv.Itoa(rc),
|
||||
)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Matches returns true if a previous call to Matcher, MatcherString, Reset,
|
||||
// ResetString, Match or MatchString succeeded.
|
||||
func (m *Matcher) Matches() bool {
|
||||
return m.matches
|
||||
}
|
||||
|
||||
// Partial returns true if a previous call to Matcher, MatcherString, Reset,
|
||||
// ResetString, Match or MatchString found a partial match.
|
||||
func (m *Matcher) Partial() bool {
|
||||
return m.partial
|
||||
}
|
||||
|
||||
// Groups returns the number of groups in the current pattern.
|
||||
func (m *Matcher) Groups() int {
|
||||
return m.groups
|
||||
}
|
||||
|
||||
// Present returns true if the numbered capture group is present in the last
|
||||
// match (performed by Matcher, MatcherString, Reset, ResetString,
|
||||
// Match, or MatchString). Group numbers start at 1. A capture group
|
||||
// can be present and match the empty string.
|
||||
func (m *Matcher) Present(group int) bool {
|
||||
return m.ovector[2*group] >= 0
|
||||
}
|
||||
|
||||
// Group returns the numbered capture group of the last match (performed by
|
||||
// Matcher, MatcherString, Reset, ResetString, Match, or MatchString).
|
||||
// Group 0 is the part of the subject which matches the whole pattern;
|
||||
// the first actual capture group is numbered 1. Capture groups which
|
||||
// are not present return a nil slice.
|
||||
func (m *Matcher) Group(group int) []byte {
|
||||
start := m.ovector[2*group]
|
||||
end := m.ovector[2*group+1]
|
||||
if start >= 0 {
|
||||
if m.subjectb != nil {
|
||||
return m.subjectb[start:end]
|
||||
}
|
||||
return []byte(m.subjects[start:end])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Extract returns a slice of byte slices for a single match.
|
||||
// The first byte slice contains the complete match.
|
||||
// Subsequent byte slices contain the captured groups.
|
||||
// If there was no match then nil is returned.
|
||||
func (m *Matcher) Extract() [][]byte {
|
||||
if !m.matches {
|
||||
return nil
|
||||
}
|
||||
extract := make([][]byte, m.groups+1)
|
||||
extract[0] = m.subjectb
|
||||
for i := 1; i <= m.groups; i++ {
|
||||
x0 := m.ovector[2*i]
|
||||
x1 := m.ovector[2*i+1]
|
||||
extract[i] = m.subjectb[x0:x1]
|
||||
}
|
||||
return extract
|
||||
}
|
||||
|
||||
// ExtractString returns a slice of strings for a single match.
|
||||
// The first string contains the complete match.
|
||||
// Subsequent strings in the slice contain the captured groups.
|
||||
// If there was no match then nil is returned.
|
||||
func (m *Matcher) ExtractString() []string {
|
||||
if !m.matches {
|
||||
return nil
|
||||
}
|
||||
extract := make([]string, m.groups+1)
|
||||
extract[0] = m.subjects
|
||||
for i := 1; i <= m.groups; i++ {
|
||||
x0 := m.ovector[2*i]
|
||||
x1 := m.ovector[2*i+1]
|
||||
extract[i] = m.subjects[x0:x1]
|
||||
}
|
||||
return extract
|
||||
}
|
||||
|
||||
// GroupIndices returns the numbered capture group positions of the last
|
||||
// match (performed by Matcher, MatcherString, Reset, ResetString, Match,
|
||||
// or MatchString). Group 0 is the part of the subject which matches
|
||||
// the whole pattern; the first actual capture group is numbered 1.
|
||||
// Capture groups which are not present return a nil slice.
|
||||
func (m *Matcher) GroupIndices(group int) []int {
|
||||
start := m.ovector[2*group]
|
||||
end := m.ovector[2*group+1]
|
||||
if start >= 0 {
|
||||
return []int{int(start), int(end)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GroupString returns the numbered capture group as a string. Group 0
|
||||
// is the part of the subject which matches the whole pattern; the first
|
||||
// actual capture group is numbered 1. Capture groups which are not
|
||||
// present return an empty string.
|
||||
func (m *Matcher) GroupString(group int) string {
|
||||
start := m.ovector[2*group]
|
||||
end := m.ovector[2*group+1]
|
||||
if start >= 0 {
|
||||
if m.subjectb != nil {
|
||||
return string(m.subjectb[start:end])
|
||||
}
|
||||
return m.subjects[start:end]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Index returns the start and end of the first match, if a previous
|
||||
// call to Matcher, MatcherString, Reset, ResetString, Match or
|
||||
// MatchString succeeded. loc[0] is the start and loc[1] is the end.
|
||||
func (m *Matcher) Index() (loc []int) {
|
||||
if !m.matches {
|
||||
return nil
|
||||
}
|
||||
loc = []int{int(m.ovector[0]), int(m.ovector[1])}
|
||||
return
|
||||
}
|
||||
|
||||
// name2index converts a group name to its group index number.
|
||||
func (m *Matcher) name2index(name string) (int, error) {
|
||||
if m.re.ptr == nil {
|
||||
return 0, fmt.Errorf("Matcher.Named: uninitialized")
|
||||
}
|
||||
name1 := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(name1))
|
||||
group := int(C.pcre_get_stringnumber(m.re.ptr, name1))
|
||||
if group < 0 {
|
||||
return group, fmt.Errorf("Matcher.Named: unknown name: " + name)
|
||||
}
|
||||
return group, nil
|
||||
}
|
||||
|
||||
// Named returns the value of the named capture group.
|
||||
// This is a nil slice if the capture group is not present.
|
||||
// If the name does not refer to a group then error is non-nil.
|
||||
func (m *Matcher) Named(group string) ([]byte, error) {
|
||||
groupNum, err := m.name2index(group)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return m.Group(groupNum), nil
|
||||
}
|
||||
|
||||
// NamedString returns the value of the named capture group,
|
||||
// or an empty string if the capture group is not present.
|
||||
// If the name does not refer to a group then error is non-nil.
|
||||
func (m *Matcher) NamedString(group string) (string, error) {
|
||||
groupNum, err := m.name2index(group)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return m.GroupString(groupNum), nil
|
||||
}
|
||||
|
||||
// NamedPresent returns true if the named capture group is present.
|
||||
// If the name does not refer to a group then error is non-nil.
|
||||
func (m *Matcher) NamedPresent(group string) (bool, error) {
|
||||
groupNum, err := m.name2index(group)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return m.Present(groupNum), nil
|
||||
}
|
||||
|
||||
// FindIndex returns the start and end of the first match,
|
||||
// or nil if no match. loc[0] is the start and loc[1] is the end.
|
||||
func (re *Regexp) FindIndex(bytes []byte, flags int) (loc []int) {
|
||||
m := re.Matcher(bytes, flags)
|
||||
if m.Matches() {
|
||||
loc = []int{int(m.ovector[0]), int(m.ovector[1])}
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReplaceAll returns a copy of a byte slice
|
||||
// where all pattern matches are replaced by repl.
|
||||
func (re Regexp) ReplaceAll(bytes, repl []byte, flags int) ([]byte, error) {
|
||||
m := re.Matcher(bytes, flags)
|
||||
r := []byte{}
|
||||
for m.matches {
|
||||
r = append(append(r, bytes[:m.ovector[0]]...), repl...)
|
||||
bytes = bytes[m.ovector[1]:]
|
||||
m.Match(bytes, flags)
|
||||
}
|
||||
return append(r, bytes...), m.err
|
||||
}
|
||||
|
||||
// ReplaceAllString is equivalent to ReplaceAll with string return type.
|
||||
func (re Regexp) ReplaceAllString(in, repl string, flags int) (string, error) {
|
||||
str, err := re.ReplaceAll([]byte(in), []byte(repl), flags)
|
||||
return string(str), err
|
||||
}
|
||||
|
||||
// Match holds details about a single successful regex match.
|
||||
type Match struct {
|
||||
Finding string // Text that was found.
|
||||
Loc []int // Index bounds for location of finding.
|
||||
}
|
||||
|
||||
// FindAll finds all instances that match the regex.
|
||||
func (re Regexp) FindAll(subject string, flags int) ([]Match, error) {
|
||||
matches := make([]Match, 0)
|
||||
m := re.MatcherString(subject, flags)
|
||||
offset := 0
|
||||
for m.Matches() {
|
||||
leftIdx := int(m.ovector[0]) + offset
|
||||
rightIdx := int(m.ovector[1]) + offset
|
||||
matches = append(
|
||||
matches,
|
||||
Match{
|
||||
subject[leftIdx:rightIdx],
|
||||
[]int{leftIdx, rightIdx},
|
||||
},
|
||||
)
|
||||
offset += maxInt(1, int(m.ovector[1]))
|
||||
if offset < len(subject) {
|
||||
m.MatchString(subject[offset:], flags)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return matches, m.err
|
||||
}
|
||||
|
||||
// CompileError holds details about a compilation error,
|
||||
// as returned by the Compile function. The offset is
|
||||
// the byte position in the pattern string at which the
|
||||
// error was detected.
|
||||
type CompileError struct {
|
||||
Pattern string // The failed pattern
|
||||
Message string // The error message
|
||||
Offset int // Byte position of error
|
||||
}
|
||||
|
||||
// Error converts a compile error to a string
|
||||
func (e *CompileError) Error() string {
|
||||
return e.Pattern + " (" + strconv.Itoa(e.Offset) + "): " + e.Message
|
||||
}
|
||||
|
||||
func maxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,677 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* This is the public header file for the PCRE library, to be #included by
|
||||
applications that call the PCRE functions.
|
||||
|
||||
Copyright (c) 1997-2014 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _PCRE_H
|
||||
#define _PCRE_H
|
||||
|
||||
/* The current PCRE version information. */
|
||||
|
||||
#define PCRE_MAJOR 8
|
||||
#define PCRE_MINOR 45
|
||||
#define PCRE_PRERELEASE
|
||||
#define PCRE_DATE 2021-06-15
|
||||
|
||||
/* When an application links to a PCRE DLL in Windows, the symbols that are
|
||||
imported have to be identified as such. When building PCRE, the appropriate
|
||||
export setting is defined in pcre_internal.h, which includes this file. So we
|
||||
don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */
|
||||
|
||||
#if defined(_WIN32) && !defined(PCRE_STATIC)
|
||||
# ifndef PCRE_EXP_DECL
|
||||
# define PCRE_EXP_DECL extern __declspec(dllimport)
|
||||
# endif
|
||||
# ifdef __cplusplus
|
||||
# ifndef PCRECPP_EXP_DECL
|
||||
# define PCRECPP_EXP_DECL extern __declspec(dllimport)
|
||||
# endif
|
||||
# ifndef PCRECPP_EXP_DEFN
|
||||
# define PCRECPP_EXP_DEFN __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* By default, we use the standard "extern" declarations. */
|
||||
|
||||
#ifndef PCRE_EXP_DECL
|
||||
# ifdef __cplusplus
|
||||
# define PCRE_EXP_DECL extern "C"
|
||||
# else
|
||||
# define PCRE_EXP_DECL extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# ifndef PCRECPP_EXP_DECL
|
||||
# define PCRECPP_EXP_DECL extern
|
||||
# endif
|
||||
# ifndef PCRECPP_EXP_DEFN
|
||||
# define PCRECPP_EXP_DEFN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Have to include stdlib.h in order to ensure that size_t is defined;
|
||||
it is needed here for malloc. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Allow for C++ users */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Public options. Some are compile-time only, some are run-time only, and some
|
||||
are both. Most of the compile-time options are saved with the compiled regex so
|
||||
that they can be inspected during studying (and therefore JIT compiling). Note
|
||||
that pcre_study() has its own set of options. Originally, all the options
|
||||
defined here used distinct bits. However, almost all the bits in a 32-bit word
|
||||
are now used, so in order to conserve them, option bits that were previously
|
||||
only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
|
||||
also be used for compile-time options that affect only compiling and are not
|
||||
relevant for studying or JIT compiling.
|
||||
|
||||
Some options for pcre_compile() change its behaviour but do not affect the
|
||||
behaviour of the execution functions. Other options are passed through to the
|
||||
execution functions and affect their behaviour, with or without affecting the
|
||||
behaviour of pcre_compile().
|
||||
|
||||
Options that can be passed to pcre_compile() are tagged Cx below, with these
|
||||
variants:
|
||||
|
||||
C1 Affects compile only
|
||||
C2 Does not affect compile; affects exec, dfa_exec
|
||||
C3 Affects compile, exec, dfa_exec
|
||||
C4 Affects compile, exec, dfa_exec, study
|
||||
C5 Affects compile, exec, study
|
||||
|
||||
Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged with
|
||||
E and D, respectively. They take precedence over C3, C4, and C5 settings passed
|
||||
from pcre_compile(). Those that are compatible with JIT execution are flagged
|
||||
with J. */
|
||||
|
||||
#define PCRE_CASELESS 0x00000001 /* C1 */
|
||||
#define PCRE_MULTILINE 0x00000002 /* C1 */
|
||||
#define PCRE_DOTALL 0x00000004 /* C1 */
|
||||
#define PCRE_EXTENDED 0x00000008 /* C1 */
|
||||
#define PCRE_ANCHORED 0x00000010 /* C4 E D */
|
||||
#define PCRE_DOLLAR_ENDONLY 0x00000020 /* C2 */
|
||||
#define PCRE_EXTRA 0x00000040 /* C1 */
|
||||
#define PCRE_NOTBOL 0x00000080 /* E D J */
|
||||
#define PCRE_NOTEOL 0x00000100 /* E D J */
|
||||
#define PCRE_UNGREEDY 0x00000200 /* C1 */
|
||||
#define PCRE_NOTEMPTY 0x00000400 /* E D J */
|
||||
#define PCRE_UTF8 0x00000800 /* C4 ) */
|
||||
#define PCRE_UTF16 0x00000800 /* C4 ) Synonyms */
|
||||
#define PCRE_UTF32 0x00000800 /* C4 ) */
|
||||
#define PCRE_NO_AUTO_CAPTURE 0x00001000 /* C1 */
|
||||
#define PCRE_NO_UTF8_CHECK 0x00002000 /* C1 E D J ) */
|
||||
#define PCRE_NO_UTF16_CHECK 0x00002000 /* C1 E D J ) Synonyms */
|
||||
#define PCRE_NO_UTF32_CHECK 0x00002000 /* C1 E D J ) */
|
||||
#define PCRE_AUTO_CALLOUT 0x00004000 /* C1 */
|
||||
#define PCRE_PARTIAL_SOFT 0x00008000 /* E D J ) Synonyms */
|
||||
#define PCRE_PARTIAL 0x00008000 /* E D J ) */
|
||||
|
||||
/* This pair use the same bit. */
|
||||
#define PCRE_NEVER_UTF 0x00010000 /* C1 ) Overlaid */
|
||||
#define PCRE_DFA_SHORTEST 0x00010000 /* D ) Overlaid */
|
||||
|
||||
/* This pair use the same bit. */
|
||||
#define PCRE_NO_AUTO_POSSESS 0x00020000 /* C1 ) Overlaid */
|
||||
#define PCRE_DFA_RESTART 0x00020000 /* D ) Overlaid */
|
||||
|
||||
#define PCRE_FIRSTLINE 0x00040000 /* C3 */
|
||||
#define PCRE_DUPNAMES 0x00080000 /* C1 */
|
||||
#define PCRE_NEWLINE_CR 0x00100000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_LF 0x00200000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_CRLF 0x00300000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_ANY 0x00400000 /* C3 E D */
|
||||
#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* C3 E D */
|
||||
#define PCRE_BSR_ANYCRLF 0x00800000 /* C3 E D */
|
||||
#define PCRE_BSR_UNICODE 0x01000000 /* C3 E D */
|
||||
#define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* C5 */
|
||||
#define PCRE_NO_START_OPTIMIZE 0x04000000 /* C2 E D ) Synonyms */
|
||||
#define PCRE_NO_START_OPTIMISE 0x04000000 /* C2 E D ) */
|
||||
#define PCRE_PARTIAL_HARD 0x08000000 /* E D J */
|
||||
#define PCRE_NOTEMPTY_ATSTART 0x10000000 /* E D J */
|
||||
#define PCRE_UCP 0x20000000 /* C3 */
|
||||
|
||||
/* Exec-time and get/set-time error codes */
|
||||
|
||||
#define PCRE_ERROR_NOMATCH (-1)
|
||||
#define PCRE_ERROR_NULL (-2)
|
||||
#define PCRE_ERROR_BADOPTION (-3)
|
||||
#define PCRE_ERROR_BADMAGIC (-4)
|
||||
#define PCRE_ERROR_UNKNOWN_OPCODE (-5)
|
||||
#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */
|
||||
#define PCRE_ERROR_NOMEMORY (-6)
|
||||
#define PCRE_ERROR_NOSUBSTRING (-7)
|
||||
#define PCRE_ERROR_MATCHLIMIT (-8)
|
||||
#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
|
||||
#define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16/32 */
|
||||
#define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16/32 */
|
||||
#define PCRE_ERROR_BADUTF32 (-10) /* Same for 8/16/32 */
|
||||
#define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Same for 8/16 */
|
||||
#define PCRE_ERROR_BADUTF16_OFFSET (-11) /* Same for 8/16 */
|
||||
#define PCRE_ERROR_PARTIAL (-12)
|
||||
#define PCRE_ERROR_BADPARTIAL (-13)
|
||||
#define PCRE_ERROR_INTERNAL (-14)
|
||||
#define PCRE_ERROR_BADCOUNT (-15)
|
||||
#define PCRE_ERROR_DFA_UITEM (-16)
|
||||
#define PCRE_ERROR_DFA_UCOND (-17)
|
||||
#define PCRE_ERROR_DFA_UMLIMIT (-18)
|
||||
#define PCRE_ERROR_DFA_WSSIZE (-19)
|
||||
#define PCRE_ERROR_DFA_RECURSE (-20)
|
||||
#define PCRE_ERROR_RECURSIONLIMIT (-21)
|
||||
#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */
|
||||
#define PCRE_ERROR_BADNEWLINE (-23)
|
||||
#define PCRE_ERROR_BADOFFSET (-24)
|
||||
#define PCRE_ERROR_SHORTUTF8 (-25)
|
||||
#define PCRE_ERROR_SHORTUTF16 (-25) /* Same for 8/16 */
|
||||
#define PCRE_ERROR_RECURSELOOP (-26)
|
||||
#define PCRE_ERROR_JIT_STACKLIMIT (-27)
|
||||
#define PCRE_ERROR_BADMODE (-28)
|
||||
#define PCRE_ERROR_BADENDIANNESS (-29)
|
||||
#define PCRE_ERROR_DFA_BADRESTART (-30)
|
||||
#define PCRE_ERROR_JIT_BADOPTION (-31)
|
||||
#define PCRE_ERROR_BADLENGTH (-32)
|
||||
#define PCRE_ERROR_UNSET (-33)
|
||||
|
||||
/* Specific error codes for UTF-8 validity checks */
|
||||
|
||||
#define PCRE_UTF8_ERR0 0
|
||||
#define PCRE_UTF8_ERR1 1
|
||||
#define PCRE_UTF8_ERR2 2
|
||||
#define PCRE_UTF8_ERR3 3
|
||||
#define PCRE_UTF8_ERR4 4
|
||||
#define PCRE_UTF8_ERR5 5
|
||||
#define PCRE_UTF8_ERR6 6
|
||||
#define PCRE_UTF8_ERR7 7
|
||||
#define PCRE_UTF8_ERR8 8
|
||||
#define PCRE_UTF8_ERR9 9
|
||||
#define PCRE_UTF8_ERR10 10
|
||||
#define PCRE_UTF8_ERR11 11
|
||||
#define PCRE_UTF8_ERR12 12
|
||||
#define PCRE_UTF8_ERR13 13
|
||||
#define PCRE_UTF8_ERR14 14
|
||||
#define PCRE_UTF8_ERR15 15
|
||||
#define PCRE_UTF8_ERR16 16
|
||||
#define PCRE_UTF8_ERR17 17
|
||||
#define PCRE_UTF8_ERR18 18
|
||||
#define PCRE_UTF8_ERR19 19
|
||||
#define PCRE_UTF8_ERR20 20
|
||||
#define PCRE_UTF8_ERR21 21
|
||||
#define PCRE_UTF8_ERR22 22 /* Unused (was non-character) */
|
||||
|
||||
/* Specific error codes for UTF-16 validity checks */
|
||||
|
||||
#define PCRE_UTF16_ERR0 0
|
||||
#define PCRE_UTF16_ERR1 1
|
||||
#define PCRE_UTF16_ERR2 2
|
||||
#define PCRE_UTF16_ERR3 3
|
||||
#define PCRE_UTF16_ERR4 4 /* Unused (was non-character) */
|
||||
|
||||
/* Specific error codes for UTF-32 validity checks */
|
||||
|
||||
#define PCRE_UTF32_ERR0 0
|
||||
#define PCRE_UTF32_ERR1 1
|
||||
#define PCRE_UTF32_ERR2 2 /* Unused (was non-character) */
|
||||
#define PCRE_UTF32_ERR3 3
|
||||
|
||||
/* Request types for pcre_fullinfo() */
|
||||
|
||||
#define PCRE_INFO_OPTIONS 0
|
||||
#define PCRE_INFO_SIZE 1
|
||||
#define PCRE_INFO_CAPTURECOUNT 2
|
||||
#define PCRE_INFO_BACKREFMAX 3
|
||||
#define PCRE_INFO_FIRSTBYTE 4
|
||||
#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */
|
||||
#define PCRE_INFO_FIRSTTABLE 5
|
||||
#define PCRE_INFO_LASTLITERAL 6
|
||||
#define PCRE_INFO_NAMEENTRYSIZE 7
|
||||
#define PCRE_INFO_NAMECOUNT 8
|
||||
#define PCRE_INFO_NAMETABLE 9
|
||||
#define PCRE_INFO_STUDYSIZE 10
|
||||
#define PCRE_INFO_DEFAULT_TABLES 11
|
||||
#define PCRE_INFO_OKPARTIAL 12
|
||||
#define PCRE_INFO_JCHANGED 13
|
||||
#define PCRE_INFO_HASCRORLF 14
|
||||
#define PCRE_INFO_MINLENGTH 15
|
||||
#define PCRE_INFO_JIT 16
|
||||
#define PCRE_INFO_JITSIZE 17
|
||||
#define PCRE_INFO_MAXLOOKBEHIND 18
|
||||
#define PCRE_INFO_FIRSTCHARACTER 19
|
||||
#define PCRE_INFO_FIRSTCHARACTERFLAGS 20
|
||||
#define PCRE_INFO_REQUIREDCHAR 21
|
||||
#define PCRE_INFO_REQUIREDCHARFLAGS 22
|
||||
#define PCRE_INFO_MATCHLIMIT 23
|
||||
#define PCRE_INFO_RECURSIONLIMIT 24
|
||||
#define PCRE_INFO_MATCH_EMPTY 25
|
||||
|
||||
/* Request types for pcre_config(). Do not re-arrange, in order to remain
|
||||
compatible. */
|
||||
|
||||
#define PCRE_CONFIG_UTF8 0
|
||||
#define PCRE_CONFIG_NEWLINE 1
|
||||
#define PCRE_CONFIG_LINK_SIZE 2
|
||||
#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3
|
||||
#define PCRE_CONFIG_MATCH_LIMIT 4
|
||||
#define PCRE_CONFIG_STACKRECURSE 5
|
||||
#define PCRE_CONFIG_UNICODE_PROPERTIES 6
|
||||
#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7
|
||||
#define PCRE_CONFIG_BSR 8
|
||||
#define PCRE_CONFIG_JIT 9
|
||||
#define PCRE_CONFIG_UTF16 10
|
||||
#define PCRE_CONFIG_JITTARGET 11
|
||||
#define PCRE_CONFIG_UTF32 12
|
||||
#define PCRE_CONFIG_PARENS_LIMIT 13
|
||||
|
||||
/* Request types for pcre_study(). Do not re-arrange, in order to remain
|
||||
compatible. */
|
||||
|
||||
#define PCRE_STUDY_JIT_COMPILE 0x0001
|
||||
#define PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE 0x0002
|
||||
#define PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE 0x0004
|
||||
#define PCRE_STUDY_EXTRA_NEEDED 0x0008
|
||||
|
||||
/* Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
|
||||
these bits, just add new ones on the end, in order to remain compatible. */
|
||||
|
||||
#define PCRE_EXTRA_STUDY_DATA 0x0001
|
||||
#define PCRE_EXTRA_MATCH_LIMIT 0x0002
|
||||
#define PCRE_EXTRA_CALLOUT_DATA 0x0004
|
||||
#define PCRE_EXTRA_TABLES 0x0008
|
||||
#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010
|
||||
#define PCRE_EXTRA_MARK 0x0020
|
||||
#define PCRE_EXTRA_EXECUTABLE_JIT 0x0040
|
||||
|
||||
/* Types */
|
||||
|
||||
struct real_pcre8_or_16; /* declaration; the definition is private */
|
||||
typedef struct real_pcre8_or_16 pcre;
|
||||
|
||||
struct real_pcre8_or_16; /* declaration; the definition is private */
|
||||
typedef struct real_pcre8_or_16 pcre16;
|
||||
|
||||
struct real_pcre32; /* declaration; the definition is private */
|
||||
typedef struct real_pcre32 pcre32;
|
||||
|
||||
struct real_pcre_jit_stack; /* declaration; the definition is private */
|
||||
typedef struct real_pcre_jit_stack pcre_jit_stack;
|
||||
|
||||
struct real_pcre16_jit_stack; /* declaration; the definition is private */
|
||||
typedef struct real_pcre16_jit_stack pcre16_jit_stack;
|
||||
|
||||
struct real_pcre32_jit_stack; /* declaration; the definition is private */
|
||||
typedef struct real_pcre32_jit_stack pcre32_jit_stack;
|
||||
|
||||
/* If PCRE is compiled with 16 bit character support, PCRE_UCHAR16 must contain
|
||||
a 16 bit wide signed data type. Otherwise it can be a dummy data type since
|
||||
pcre16 functions are not implemented. There is a check for this in pcre_internal.h. */
|
||||
#ifndef PCRE_UCHAR16
|
||||
#define PCRE_UCHAR16 unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef PCRE_SPTR16
|
||||
#define PCRE_SPTR16 const PCRE_UCHAR16 *
|
||||
#endif
|
||||
|
||||
/* If PCRE is compiled with 32 bit character support, PCRE_UCHAR32 must contain
|
||||
a 32 bit wide signed data type. Otherwise it can be a dummy data type since
|
||||
pcre32 functions are not implemented. There is a check for this in pcre_internal.h. */
|
||||
#ifndef PCRE_UCHAR32
|
||||
#define PCRE_UCHAR32 unsigned int
|
||||
#endif
|
||||
|
||||
#ifndef PCRE_SPTR32
|
||||
#define PCRE_SPTR32 const PCRE_UCHAR32 *
|
||||
#endif
|
||||
|
||||
/* When PCRE is compiled as a C++ library, the subject pointer type can be
|
||||
replaced with a custom type. For conventional use, the public interface is a
|
||||
const char *. */
|
||||
|
||||
#ifndef PCRE_SPTR
|
||||
#define PCRE_SPTR const char *
|
||||
#endif
|
||||
|
||||
/* The structure for passing additional data to pcre_exec(). This is defined in
|
||||
such as way as to be extensible. Always add new fields at the end, in order to
|
||||
remain compatible. */
|
||||
|
||||
typedef struct pcre_extra {
|
||||
unsigned long int flags; /* Bits for which fields are set */
|
||||
void *study_data; /* Opaque data from pcre_study() */
|
||||
unsigned long int match_limit; /* Maximum number of calls to match() */
|
||||
void *callout_data; /* Data passed back in callouts */
|
||||
const unsigned char *tables; /* Pointer to character tables */
|
||||
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
|
||||
unsigned char **mark; /* For passing back a mark pointer */
|
||||
void *executable_jit; /* Contains a pointer to a compiled jit code */
|
||||
} pcre_extra;
|
||||
|
||||
/* Same structure as above, but with 16 bit char pointers. */
|
||||
|
||||
typedef struct pcre16_extra {
|
||||
unsigned long int flags; /* Bits for which fields are set */
|
||||
void *study_data; /* Opaque data from pcre_study() */
|
||||
unsigned long int match_limit; /* Maximum number of calls to match() */
|
||||
void *callout_data; /* Data passed back in callouts */
|
||||
const unsigned char *tables; /* Pointer to character tables */
|
||||
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
|
||||
PCRE_UCHAR16 **mark; /* For passing back a mark pointer */
|
||||
void *executable_jit; /* Contains a pointer to a compiled jit code */
|
||||
} pcre16_extra;
|
||||
|
||||
/* Same structure as above, but with 32 bit char pointers. */
|
||||
|
||||
typedef struct pcre32_extra {
|
||||
unsigned long int flags; /* Bits for which fields are set */
|
||||
void *study_data; /* Opaque data from pcre_study() */
|
||||
unsigned long int match_limit; /* Maximum number of calls to match() */
|
||||
void *callout_data; /* Data passed back in callouts */
|
||||
const unsigned char *tables; /* Pointer to character tables */
|
||||
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
|
||||
PCRE_UCHAR32 **mark; /* For passing back a mark pointer */
|
||||
void *executable_jit; /* Contains a pointer to a compiled jit code */
|
||||
} pcre32_extra;
|
||||
|
||||
/* The structure for passing out data via the pcre_callout_function. We use a
|
||||
structure so that new fields can be added on the end in future versions,
|
||||
without changing the API of the function, thereby allowing old clients to work
|
||||
without modification. */
|
||||
|
||||
typedef struct pcre_callout_block {
|
||||
int version; /* Identifies version of block */
|
||||
/* ------------------------ Version 0 ------------------------------- */
|
||||
int callout_number; /* Number compiled into pattern */
|
||||
int *offset_vector; /* The offset vector */
|
||||
PCRE_SPTR subject; /* The subject being matched */
|
||||
int subject_length; /* The length of the subject */
|
||||
int start_match; /* Offset to start of this match attempt */
|
||||
int current_position; /* Where we currently are in the subject */
|
||||
int capture_top; /* Max current capture */
|
||||
int capture_last; /* Most recently closed capture */
|
||||
void *callout_data; /* Data passed in with the call */
|
||||
/* ------------------- Added for Version 1 -------------------------- */
|
||||
int pattern_position; /* Offset to next item in the pattern */
|
||||
int next_item_length; /* Length of next item in the pattern */
|
||||
/* ------------------- Added for Version 2 -------------------------- */
|
||||
const unsigned char *mark; /* Pointer to current mark or NULL */
|
||||
/* ------------------------------------------------------------------ */
|
||||
} pcre_callout_block;
|
||||
|
||||
/* Same structure as above, but with 16 bit char pointers. */
|
||||
|
||||
typedef struct pcre16_callout_block {
|
||||
int version; /* Identifies version of block */
|
||||
/* ------------------------ Version 0 ------------------------------- */
|
||||
int callout_number; /* Number compiled into pattern */
|
||||
int *offset_vector; /* The offset vector */
|
||||
PCRE_SPTR16 subject; /* The subject being matched */
|
||||
int subject_length; /* The length of the subject */
|
||||
int start_match; /* Offset to start of this match attempt */
|
||||
int current_position; /* Where we currently are in the subject */
|
||||
int capture_top; /* Max current capture */
|
||||
int capture_last; /* Most recently closed capture */
|
||||
void *callout_data; /* Data passed in with the call */
|
||||
/* ------------------- Added for Version 1 -------------------------- */
|
||||
int pattern_position; /* Offset to next item in the pattern */
|
||||
int next_item_length; /* Length of next item in the pattern */
|
||||
/* ------------------- Added for Version 2 -------------------------- */
|
||||
const PCRE_UCHAR16 *mark; /* Pointer to current mark or NULL */
|
||||
/* ------------------------------------------------------------------ */
|
||||
} pcre16_callout_block;
|
||||
|
||||
/* Same structure as above, but with 32 bit char pointers. */
|
||||
|
||||
typedef struct pcre32_callout_block {
|
||||
int version; /* Identifies version of block */
|
||||
/* ------------------------ Version 0 ------------------------------- */
|
||||
int callout_number; /* Number compiled into pattern */
|
||||
int *offset_vector; /* The offset vector */
|
||||
PCRE_SPTR32 subject; /* The subject being matched */
|
||||
int subject_length; /* The length of the subject */
|
||||
int start_match; /* Offset to start of this match attempt */
|
||||
int current_position; /* Where we currently are in the subject */
|
||||
int capture_top; /* Max current capture */
|
||||
int capture_last; /* Most recently closed capture */
|
||||
void *callout_data; /* Data passed in with the call */
|
||||
/* ------------------- Added for Version 1 -------------------------- */
|
||||
int pattern_position; /* Offset to next item in the pattern */
|
||||
int next_item_length; /* Length of next item in the pattern */
|
||||
/* ------------------- Added for Version 2 -------------------------- */
|
||||
const PCRE_UCHAR32 *mark; /* Pointer to current mark or NULL */
|
||||
/* ------------------------------------------------------------------ */
|
||||
} pcre32_callout_block;
|
||||
|
||||
/* Indirection for store get and free functions. These can be set to
|
||||
alternative malloc/free functions if required. Special ones are used in the
|
||||
non-recursive case for "frames". There is also an optional callout function
|
||||
that is triggered by the (?) regex item. For Virtual Pascal, these definitions
|
||||
have to take another form. */
|
||||
|
||||
#ifndef VPCOMPAT
|
||||
PCRE_EXP_DECL void *(*pcre_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre_free)(void *);
|
||||
PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre_stack_free)(void *);
|
||||
PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *);
|
||||
PCRE_EXP_DECL int (*pcre_stack_guard)(void);
|
||||
|
||||
PCRE_EXP_DECL void *(*pcre16_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre16_free)(void *);
|
||||
PCRE_EXP_DECL void *(*pcre16_stack_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre16_stack_free)(void *);
|
||||
PCRE_EXP_DECL int (*pcre16_callout)(pcre16_callout_block *);
|
||||
PCRE_EXP_DECL int (*pcre16_stack_guard)(void);
|
||||
|
||||
PCRE_EXP_DECL void *(*pcre32_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre32_free)(void *);
|
||||
PCRE_EXP_DECL void *(*pcre32_stack_malloc)(size_t);
|
||||
PCRE_EXP_DECL void (*pcre32_stack_free)(void *);
|
||||
PCRE_EXP_DECL int (*pcre32_callout)(pcre32_callout_block *);
|
||||
PCRE_EXP_DECL int (*pcre32_stack_guard)(void);
|
||||
#else /* VPCOMPAT */
|
||||
PCRE_EXP_DECL void *pcre_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre_free(void *);
|
||||
PCRE_EXP_DECL void *pcre_stack_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre_stack_free(void *);
|
||||
PCRE_EXP_DECL int pcre_callout(pcre_callout_block *);
|
||||
PCRE_EXP_DECL int pcre_stack_guard(void);
|
||||
|
||||
PCRE_EXP_DECL void *pcre16_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre16_free(void *);
|
||||
PCRE_EXP_DECL void *pcre16_stack_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre16_stack_free(void *);
|
||||
PCRE_EXP_DECL int pcre16_callout(pcre16_callout_block *);
|
||||
PCRE_EXP_DECL int pcre16_stack_guard(void);
|
||||
|
||||
PCRE_EXP_DECL void *pcre32_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre32_free(void *);
|
||||
PCRE_EXP_DECL void *pcre32_stack_malloc(size_t);
|
||||
PCRE_EXP_DECL void pcre32_stack_free(void *);
|
||||
PCRE_EXP_DECL int pcre32_callout(pcre32_callout_block *);
|
||||
PCRE_EXP_DECL int pcre32_stack_guard(void);
|
||||
#endif /* VPCOMPAT */
|
||||
|
||||
/* User defined callback which provides a stack just before the match starts. */
|
||||
|
||||
typedef pcre_jit_stack *(*pcre_jit_callback)(void *);
|
||||
typedef pcre16_jit_stack *(*pcre16_jit_callback)(void *);
|
||||
typedef pcre32_jit_stack *(*pcre32_jit_callback)(void *);
|
||||
|
||||
/* Exported PCRE functions */
|
||||
|
||||
PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL pcre16 *pcre16_compile(PCRE_SPTR16, int, const char **, int *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL pcre32 *pcre32_compile(PCRE_SPTR32, int, const char **, int *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **,
|
||||
int *, const unsigned char *);
|
||||
PCRE_EXP_DECL pcre16 *pcre16_compile2(PCRE_SPTR16, int, int *, const char **,
|
||||
int *, const unsigned char *);
|
||||
PCRE_EXP_DECL pcre32 *pcre32_compile2(PCRE_SPTR32, int, int *, const char **,
|
||||
int *, const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre_config(int, void *);
|
||||
PCRE_EXP_DECL int pcre16_config(int, void *);
|
||||
PCRE_EXP_DECL int pcre32_config(int, void *);
|
||||
PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *,
|
||||
int *, int, const char *, char *, int);
|
||||
PCRE_EXP_DECL int pcre16_copy_named_substring(const pcre16 *, PCRE_SPTR16,
|
||||
int *, int, PCRE_SPTR16, PCRE_UCHAR16 *, int);
|
||||
PCRE_EXP_DECL int pcre32_copy_named_substring(const pcre32 *, PCRE_SPTR32,
|
||||
int *, int, PCRE_SPTR32, PCRE_UCHAR32 *, int);
|
||||
PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int,
|
||||
char *, int);
|
||||
PCRE_EXP_DECL int pcre16_copy_substring(PCRE_SPTR16, int *, int, int,
|
||||
PCRE_UCHAR16 *, int);
|
||||
PCRE_EXP_DECL int pcre32_copy_substring(PCRE_SPTR32, int *, int, int,
|
||||
PCRE_UCHAR32 *, int);
|
||||
PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *,
|
||||
const char *, int, int, int, int *, int , int *, int);
|
||||
PCRE_EXP_DECL int pcre16_dfa_exec(const pcre16 *, const pcre16_extra *,
|
||||
PCRE_SPTR16, int, int, int, int *, int , int *, int);
|
||||
PCRE_EXP_DECL int pcre32_dfa_exec(const pcre32 *, const pcre32_extra *,
|
||||
PCRE_SPTR32, int, int, int, int *, int , int *, int);
|
||||
PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
|
||||
int, int, int, int *, int);
|
||||
PCRE_EXP_DECL int pcre16_exec(const pcre16 *, const pcre16_extra *,
|
||||
PCRE_SPTR16, int, int, int, int *, int);
|
||||
PCRE_EXP_DECL int pcre32_exec(const pcre32 *, const pcre32_extra *,
|
||||
PCRE_SPTR32, int, int, int, int *, int);
|
||||
PCRE_EXP_DECL int pcre_jit_exec(const pcre *, const pcre_extra *,
|
||||
PCRE_SPTR, int, int, int, int *, int,
|
||||
pcre_jit_stack *);
|
||||
PCRE_EXP_DECL int pcre16_jit_exec(const pcre16 *, const pcre16_extra *,
|
||||
PCRE_SPTR16, int, int, int, int *, int,
|
||||
pcre16_jit_stack *);
|
||||
PCRE_EXP_DECL int pcre32_jit_exec(const pcre32 *, const pcre32_extra *,
|
||||
PCRE_SPTR32, int, int, int, int *, int,
|
||||
pcre32_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre_free_substring(const char *);
|
||||
PCRE_EXP_DECL void pcre16_free_substring(PCRE_SPTR16);
|
||||
PCRE_EXP_DECL void pcre32_free_substring(PCRE_SPTR32);
|
||||
PCRE_EXP_DECL void pcre_free_substring_list(const char **);
|
||||
PCRE_EXP_DECL void pcre16_free_substring_list(PCRE_SPTR16 *);
|
||||
PCRE_EXP_DECL void pcre32_free_substring_list(PCRE_SPTR32 *);
|
||||
PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int,
|
||||
void *);
|
||||
PCRE_EXP_DECL int pcre16_fullinfo(const pcre16 *, const pcre16_extra *, int,
|
||||
void *);
|
||||
PCRE_EXP_DECL int pcre32_fullinfo(const pcre32 *, const pcre32_extra *, int,
|
||||
void *);
|
||||
PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *,
|
||||
int *, int, const char *, const char **);
|
||||
PCRE_EXP_DECL int pcre16_get_named_substring(const pcre16 *, PCRE_SPTR16,
|
||||
int *, int, PCRE_SPTR16, PCRE_SPTR16 *);
|
||||
PCRE_EXP_DECL int pcre32_get_named_substring(const pcre32 *, PCRE_SPTR32,
|
||||
int *, int, PCRE_SPTR32, PCRE_SPTR32 *);
|
||||
PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *);
|
||||
PCRE_EXP_DECL int pcre16_get_stringnumber(const pcre16 *, PCRE_SPTR16);
|
||||
PCRE_EXP_DECL int pcre32_get_stringnumber(const pcre32 *, PCRE_SPTR32);
|
||||
PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *,
|
||||
char **, char **);
|
||||
PCRE_EXP_DECL int pcre16_get_stringtable_entries(const pcre16 *, PCRE_SPTR16,
|
||||
PCRE_UCHAR16 **, PCRE_UCHAR16 **);
|
||||
PCRE_EXP_DECL int pcre32_get_stringtable_entries(const pcre32 *, PCRE_SPTR32,
|
||||
PCRE_UCHAR32 **, PCRE_UCHAR32 **);
|
||||
PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int,
|
||||
const char **);
|
||||
PCRE_EXP_DECL int pcre16_get_substring(PCRE_SPTR16, int *, int, int,
|
||||
PCRE_SPTR16 *);
|
||||
PCRE_EXP_DECL int pcre32_get_substring(PCRE_SPTR32, int *, int, int,
|
||||
PCRE_SPTR32 *);
|
||||
PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int,
|
||||
const char ***);
|
||||
PCRE_EXP_DECL int pcre16_get_substring_list(PCRE_SPTR16, int *, int,
|
||||
PCRE_SPTR16 **);
|
||||
PCRE_EXP_DECL int pcre32_get_substring_list(PCRE_SPTR32, int *, int,
|
||||
PCRE_SPTR32 **);
|
||||
PCRE_EXP_DECL const unsigned char *pcre_maketables(void);
|
||||
PCRE_EXP_DECL const unsigned char *pcre16_maketables(void);
|
||||
PCRE_EXP_DECL const unsigned char *pcre32_maketables(void);
|
||||
PCRE_EXP_DECL int pcre_refcount(pcre *, int);
|
||||
PCRE_EXP_DECL int pcre16_refcount(pcre16 *, int);
|
||||
PCRE_EXP_DECL int pcre32_refcount(pcre32 *, int);
|
||||
PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **);
|
||||
PCRE_EXP_DECL pcre16_extra *pcre16_study(const pcre16 *, int, const char **);
|
||||
PCRE_EXP_DECL pcre32_extra *pcre32_study(const pcre32 *, int, const char **);
|
||||
PCRE_EXP_DECL void pcre_free_study(pcre_extra *);
|
||||
PCRE_EXP_DECL void pcre16_free_study(pcre16_extra *);
|
||||
PCRE_EXP_DECL void pcre32_free_study(pcre32_extra *);
|
||||
PCRE_EXP_DECL const char *pcre_version(void);
|
||||
PCRE_EXP_DECL const char *pcre16_version(void);
|
||||
PCRE_EXP_DECL const char *pcre32_version(void);
|
||||
|
||||
/* Utility functions for byte order swaps. */
|
||||
PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *, pcre_extra *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *, pcre16_extra *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *, pcre32_extra *,
|
||||
const unsigned char *);
|
||||
PCRE_EXP_DECL int pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *,
|
||||
PCRE_SPTR16, int, int *, int);
|
||||
PCRE_EXP_DECL int pcre32_utf32_to_host_byte_order(PCRE_UCHAR32 *,
|
||||
PCRE_SPTR32, int, int *, int);
|
||||
|
||||
/* JIT compiler related functions. */
|
||||
|
||||
PCRE_EXP_DECL pcre_jit_stack *pcre_jit_stack_alloc(int, int);
|
||||
PCRE_EXP_DECL pcre16_jit_stack *pcre16_jit_stack_alloc(int, int);
|
||||
PCRE_EXP_DECL pcre32_jit_stack *pcre32_jit_stack_alloc(int, int);
|
||||
PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *);
|
||||
PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *,
|
||||
pcre_jit_callback, void *);
|
||||
PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *,
|
||||
pcre16_jit_callback, void *);
|
||||
PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *,
|
||||
pcre32_jit_callback, void *);
|
||||
PCRE_EXP_DECL void pcre_jit_free_unused_memory(void);
|
||||
PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void);
|
||||
PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* End of pcre.h */
|
||||
@@ -0,0 +1,317 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2014 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 tests a compiled pattern to
|
||||
see if it was compiled with the opposite endianness. If so, it uses an
|
||||
auxiliary local function to flip the appropriate bytes. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Swap byte functions *
|
||||
*************************************************/
|
||||
|
||||
/* The following functions swap the bytes of a pcre_uint16
|
||||
and pcre_uint32 value.
|
||||
|
||||
Arguments:
|
||||
value any number
|
||||
|
||||
Returns: the byte swapped value
|
||||
*/
|
||||
|
||||
static pcre_uint32
|
||||
swap_uint32(pcre_uint32 value)
|
||||
{
|
||||
return ((value & 0x000000ff) << 24) |
|
||||
((value & 0x0000ff00) << 8) |
|
||||
((value & 0x00ff0000) >> 8) |
|
||||
(value >> 24);
|
||||
}
|
||||
|
||||
static pcre_uint16
|
||||
swap_uint16(pcre_uint16 value)
|
||||
{
|
||||
return (value >> 8) | (value << 8);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Test for a byte-flipped compiled regex *
|
||||
*************************************************/
|
||||
|
||||
/* This function swaps the bytes of a compiled pattern usually
|
||||
loaded form the disk. It also sets the tables pointer, which
|
||||
is likely an invalid pointer after reload.
|
||||
|
||||
Arguments:
|
||||
argument_re points to the compiled expression
|
||||
extra_data points to extra data or is NULL
|
||||
tables points to the character tables or NULL
|
||||
|
||||
Returns: 0 if the swap is successful, negative on error
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *argument_re,
|
||||
pcre_extra *extra_data, const unsigned char *tables)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *argument_re,
|
||||
pcre16_extra *extra_data, const unsigned char *tables)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *argument_re,
|
||||
pcre32_extra *extra_data, const unsigned char *tables)
|
||||
#endif
|
||||
{
|
||||
REAL_PCRE *re = (REAL_PCRE *)argument_re;
|
||||
pcre_study_data *study;
|
||||
#ifndef COMPILE_PCRE8
|
||||
pcre_uchar *ptr;
|
||||
int length;
|
||||
#if defined SUPPORT_UTF && defined COMPILE_PCRE16
|
||||
BOOL utf;
|
||||
BOOL utf16_char;
|
||||
#endif /* SUPPORT_UTF && COMPILE_PCRE16 */
|
||||
#endif /* !COMPILE_PCRE8 */
|
||||
|
||||
if (re == NULL) return PCRE_ERROR_NULL;
|
||||
if (re->magic_number == MAGIC_NUMBER)
|
||||
{
|
||||
if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
|
||||
re->tables = tables;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (re->magic_number != REVERSED_MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
|
||||
if ((swap_uint32(re->flags) & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
|
||||
|
||||
re->magic_number = MAGIC_NUMBER;
|
||||
re->size = swap_uint32(re->size);
|
||||
re->options = swap_uint32(re->options);
|
||||
re->flags = swap_uint32(re->flags);
|
||||
re->limit_match = swap_uint32(re->limit_match);
|
||||
re->limit_recursion = swap_uint32(re->limit_recursion);
|
||||
|
||||
#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
|
||||
re->first_char = swap_uint16(re->first_char);
|
||||
re->req_char = swap_uint16(re->req_char);
|
||||
#elif defined COMPILE_PCRE32
|
||||
re->first_char = swap_uint32(re->first_char);
|
||||
re->req_char = swap_uint32(re->req_char);
|
||||
#endif
|
||||
|
||||
re->max_lookbehind = swap_uint16(re->max_lookbehind);
|
||||
re->top_bracket = swap_uint16(re->top_bracket);
|
||||
re->top_backref = swap_uint16(re->top_backref);
|
||||
re->name_table_offset = swap_uint16(re->name_table_offset);
|
||||
re->name_entry_size = swap_uint16(re->name_entry_size);
|
||||
re->name_count = swap_uint16(re->name_count);
|
||||
re->ref_count = swap_uint16(re->ref_count);
|
||||
re->tables = tables;
|
||||
|
||||
if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0)
|
||||
{
|
||||
study = (pcre_study_data *)extra_data->study_data;
|
||||
study->size = swap_uint32(study->size);
|
||||
study->flags = swap_uint32(study->flags);
|
||||
study->minlength = swap_uint32(study->minlength);
|
||||
}
|
||||
|
||||
#ifndef COMPILE_PCRE8
|
||||
ptr = (pcre_uchar *)re + re->name_table_offset;
|
||||
length = re->name_count * re->name_entry_size;
|
||||
#if defined SUPPORT_UTF && defined COMPILE_PCRE16
|
||||
utf = (re->options & PCRE_UTF16) != 0;
|
||||
utf16_char = FALSE;
|
||||
#endif /* SUPPORT_UTF && COMPILE_PCRE16 */
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
/* Swap previous characters. */
|
||||
while (length-- > 0)
|
||||
{
|
||||
#if defined COMPILE_PCRE16
|
||||
*ptr = swap_uint16(*ptr);
|
||||
#elif defined COMPILE_PCRE32
|
||||
*ptr = swap_uint32(*ptr);
|
||||
#endif
|
||||
ptr++;
|
||||
}
|
||||
#if defined SUPPORT_UTF && defined COMPILE_PCRE16
|
||||
if (utf16_char)
|
||||
{
|
||||
if (HAS_EXTRALEN(ptr[-1]))
|
||||
{
|
||||
/* We know that there is only one extra character in UTF-16. */
|
||||
*ptr = swap_uint16(*ptr);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
utf16_char = FALSE;
|
||||
#endif /* SUPPORT_UTF */
|
||||
|
||||
/* Get next opcode. */
|
||||
length = 0;
|
||||
#if defined COMPILE_PCRE16
|
||||
*ptr = swap_uint16(*ptr);
|
||||
#elif defined COMPILE_PCRE32
|
||||
*ptr = swap_uint32(*ptr);
|
||||
#endif
|
||||
switch (*ptr)
|
||||
{
|
||||
case OP_END:
|
||||
return 0;
|
||||
|
||||
#if defined SUPPORT_UTF && defined COMPILE_PCRE16
|
||||
case OP_CHAR:
|
||||
case OP_CHARI:
|
||||
case OP_NOT:
|
||||
case OP_NOTI:
|
||||
case OP_STAR:
|
||||
case OP_MINSTAR:
|
||||
case OP_PLUS:
|
||||
case OP_MINPLUS:
|
||||
case OP_QUERY:
|
||||
case OP_MINQUERY:
|
||||
case OP_UPTO:
|
||||
case OP_MINUPTO:
|
||||
case OP_EXACT:
|
||||
case OP_POSSTAR:
|
||||
case OP_POSPLUS:
|
||||
case OP_POSQUERY:
|
||||
case OP_POSUPTO:
|
||||
case OP_STARI:
|
||||
case OP_MINSTARI:
|
||||
case OP_PLUSI:
|
||||
case OP_MINPLUSI:
|
||||
case OP_QUERYI:
|
||||
case OP_MINQUERYI:
|
||||
case OP_UPTOI:
|
||||
case OP_MINUPTOI:
|
||||
case OP_EXACTI:
|
||||
case OP_POSSTARI:
|
||||
case OP_POSPLUSI:
|
||||
case OP_POSQUERYI:
|
||||
case OP_POSUPTOI:
|
||||
case OP_NOTSTAR:
|
||||
case OP_NOTMINSTAR:
|
||||
case OP_NOTPLUS:
|
||||
case OP_NOTMINPLUS:
|
||||
case OP_NOTQUERY:
|
||||
case OP_NOTMINQUERY:
|
||||
case OP_NOTUPTO:
|
||||
case OP_NOTMINUPTO:
|
||||
case OP_NOTEXACT:
|
||||
case OP_NOTPOSSTAR:
|
||||
case OP_NOTPOSPLUS:
|
||||
case OP_NOTPOSQUERY:
|
||||
case OP_NOTPOSUPTO:
|
||||
case OP_NOTSTARI:
|
||||
case OP_NOTMINSTARI:
|
||||
case OP_NOTPLUSI:
|
||||
case OP_NOTMINPLUSI:
|
||||
case OP_NOTQUERYI:
|
||||
case OP_NOTMINQUERYI:
|
||||
case OP_NOTUPTOI:
|
||||
case OP_NOTMINUPTOI:
|
||||
case OP_NOTEXACTI:
|
||||
case OP_NOTPOSSTARI:
|
||||
case OP_NOTPOSPLUSI:
|
||||
case OP_NOTPOSQUERYI:
|
||||
case OP_NOTPOSUPTOI:
|
||||
if (utf) utf16_char = TRUE;
|
||||
#endif
|
||||
/* Fall through. */
|
||||
|
||||
default:
|
||||
length = PRIV(OP_lengths)[*ptr] - 1;
|
||||
break;
|
||||
|
||||
case OP_CLASS:
|
||||
case OP_NCLASS:
|
||||
/* Skip the character bit map. */
|
||||
ptr += 32/sizeof(pcre_uchar);
|
||||
length = 0;
|
||||
break;
|
||||
|
||||
case OP_XCLASS:
|
||||
/* Reverse the size of the XCLASS instance. */
|
||||
ptr++;
|
||||
#if defined COMPILE_PCRE16
|
||||
*ptr = swap_uint16(*ptr);
|
||||
#elif defined COMPILE_PCRE32
|
||||
*ptr = swap_uint32(*ptr);
|
||||
#endif
|
||||
#ifndef COMPILE_PCRE32
|
||||
if (LINK_SIZE > 1)
|
||||
{
|
||||
/* LINK_SIZE can be 1 or 2 in 16 bit mode. */
|
||||
ptr++;
|
||||
*ptr = swap_uint16(*ptr);
|
||||
}
|
||||
#endif
|
||||
ptr++;
|
||||
length = (GET(ptr, -LINK_SIZE)) - (1 + LINK_SIZE + 1);
|
||||
#if defined COMPILE_PCRE16
|
||||
*ptr = swap_uint16(*ptr);
|
||||
#elif defined COMPILE_PCRE32
|
||||
*ptr = swap_uint32(*ptr);
|
||||
#endif
|
||||
if ((*ptr & XCL_MAP) != 0)
|
||||
{
|
||||
/* Skip the character bit map. */
|
||||
ptr += 32/sizeof(pcre_uchar);
|
||||
length -= 32/sizeof(pcre_uchar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
/* Control should never reach here in 16/32 bit mode. */
|
||||
#else /* In 8-bit mode, the pattern does not need to be processed. */
|
||||
return 0;
|
||||
#endif /* !COMPILE_PCRE8 */
|
||||
}
|
||||
|
||||
/* End of pcre_byte_order.c */
|
||||
@@ -0,0 +1,196 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* This file contains character tables that are used when no external tables
|
||||
are passed to PCRE by the application that calls it. The tables are used only
|
||||
for characters whose code values are less than 256.
|
||||
|
||||
This is a default version of the tables that assumes ASCII encoding. A program
|
||||
called dftables (which is distributed with PCRE) can be used to build
|
||||
alternative versions of this file. This is necessary if you are running in an
|
||||
EBCDIC environment, or if you want to default to a different encoding, for
|
||||
example ISO-8859-1. When dftables is run, it creates these tables in the
|
||||
current locale. If PCRE is configured with --enable-rebuild-chartables, this
|
||||
happens automatically.
|
||||
|
||||
The following #includes are present because without them gcc 4.x may remove the
|
||||
array definition from the final binary if PCRE is built into a static library
|
||||
and dead code stripping is activated. This leads to link errors. Pulling in the
|
||||
header ensures that the array gets flagged as "someone outside this compilation
|
||||
unit might reference this" and so it will always be supplied to the linker. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
const pcre_uint8 PRIV(default_tables)[] = {
|
||||
|
||||
/* This table is a lower casing table. */
|
||||
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 97, 98, 99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,
|
||||
112,113,114,115,116,117,118,119,
|
||||
120,121,122, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,
|
||||
112,113,114,115,116,117,118,119,
|
||||
120,121,122,123,124,125,126,127,
|
||||
128,129,130,131,132,133,134,135,
|
||||
136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,
|
||||
152,153,154,155,156,157,158,159,
|
||||
160,161,162,163,164,165,166,167,
|
||||
168,169,170,171,172,173,174,175,
|
||||
176,177,178,179,180,181,182,183,
|
||||
184,185,186,187,188,189,190,191,
|
||||
192,193,194,195,196,197,198,199,
|
||||
200,201,202,203,204,205,206,207,
|
||||
208,209,210,211,212,213,214,215,
|
||||
216,217,218,219,220,221,222,223,
|
||||
224,225,226,227,228,229,230,231,
|
||||
232,233,234,235,236,237,238,239,
|
||||
240,241,242,243,244,245,246,247,
|
||||
248,249,250,251,252,253,254,255,
|
||||
|
||||
/* This table is a case flipping table. */
|
||||
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 97, 98, 99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,
|
||||
112,113,114,115,116,117,118,119,
|
||||
120,121,122, 91, 92, 93, 94, 95,
|
||||
96, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90,123,124,125,126,127,
|
||||
128,129,130,131,132,133,134,135,
|
||||
136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,
|
||||
152,153,154,155,156,157,158,159,
|
||||
160,161,162,163,164,165,166,167,
|
||||
168,169,170,171,172,173,174,175,
|
||||
176,177,178,179,180,181,182,183,
|
||||
184,185,186,187,188,189,190,191,
|
||||
192,193,194,195,196,197,198,199,
|
||||
200,201,202,203,204,205,206,207,
|
||||
208,209,210,211,212,213,214,215,
|
||||
216,217,218,219,220,221,222,223,
|
||||
224,225,226,227,228,229,230,231,
|
||||
232,233,234,235,236,237,238,239,
|
||||
240,241,242,243,244,245,246,247,
|
||||
248,249,250,251,252,253,254,255,
|
||||
|
||||
/* 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 that have their own maps are: space, xdigit, digit, upper, lower, word,
|
||||
graph, print, punct, and cntrl. Other classes are built from combinations. */
|
||||
|
||||
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,
|
||||
0x7e,0x00,0x00,0x00,0x7e,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,0x00,0x00,
|
||||
0xfe,0xff,0xff,0x07,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,0xfe,0xff,0xff,0x07,
|
||||
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,
|
||||
|
||||
0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
|
||||
0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
|
||||
0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
|
||||
0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
|
||||
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
|
||||
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
|
||||
0x02 letter
|
||||
0x04 decimal digit
|
||||
0x08 hexadecimal digit
|
||||
0x10 alphanumeric or '_'
|
||||
0x80 regular expression metacharacter or binary zero
|
||||
*/
|
||||
|
||||
0x80,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,0x80,0x00,0x00,0x00, /* - ' */
|
||||
0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */
|
||||
0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
|
||||
0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */
|
||||
0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */
|
||||
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */
|
||||
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */
|
||||
0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */
|
||||
0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */
|
||||
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */
|
||||
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */
|
||||
0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
|
||||
|
||||
/* End of pcre_chartables.c */
|
||||
+9808
File diff suppressed because it is too large
Load Diff
+188
@@ -0,0 +1,188 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 the external function pcre_config(). */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Keep the original link size. */
|
||||
static int real_link_size = LINK_SIZE;
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Return info about what features are configured *
|
||||
*************************************************/
|
||||
|
||||
/* This function has an extensible interface so that additional items can be
|
||||
added compatibly.
|
||||
|
||||
Arguments:
|
||||
what what information is required
|
||||
where where to put the information
|
||||
|
||||
Returns: 0 if data returned, negative on error
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_config(int what, void *where)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_config(int what, void *where)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_config(int what, void *where)
|
||||
#endif
|
||||
{
|
||||
switch (what)
|
||||
{
|
||||
case PCRE_CONFIG_UTF8:
|
||||
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
|
||||
*((int *)where) = 0;
|
||||
return PCRE_ERROR_BADOPTION;
|
||||
#else
|
||||
#if defined SUPPORT_UTF
|
||||
*((int *)where) = 1;
|
||||
#else
|
||||
*((int *)where) = 0;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PCRE_CONFIG_UTF16:
|
||||
#if defined COMPILE_PCRE8 || defined COMPILE_PCRE32
|
||||
*((int *)where) = 0;
|
||||
return PCRE_ERROR_BADOPTION;
|
||||
#else
|
||||
#if defined SUPPORT_UTF
|
||||
*((int *)where) = 1;
|
||||
#else
|
||||
*((int *)where) = 0;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PCRE_CONFIG_UTF32:
|
||||
#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
|
||||
*((int *)where) = 0;
|
||||
return PCRE_ERROR_BADOPTION;
|
||||
#else
|
||||
#if defined SUPPORT_UTF
|
||||
*((int *)where) = 1;
|
||||
#else
|
||||
*((int *)where) = 0;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PCRE_CONFIG_UNICODE_PROPERTIES:
|
||||
#ifdef SUPPORT_UCP
|
||||
*((int *)where) = 1;
|
||||
#else
|
||||
*((int *)where) = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_JIT:
|
||||
#ifdef SUPPORT_JIT
|
||||
*((int *)where) = 1;
|
||||
#else
|
||||
*((int *)where) = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_JITTARGET:
|
||||
#ifdef SUPPORT_JIT
|
||||
*((const char **)where) = PRIV(jit_get_target)();
|
||||
#else
|
||||
*((const char **)where) = NULL;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_NEWLINE:
|
||||
*((int *)where) = NEWLINE;
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_BSR:
|
||||
#ifdef BSR_ANYCRLF
|
||||
*((int *)where) = 1;
|
||||
#else
|
||||
*((int *)where) = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_LINK_SIZE:
|
||||
*((int *)where) = real_link_size;
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_POSIX_MALLOC_THRESHOLD:
|
||||
*((int *)where) = POSIX_MALLOC_THRESHOLD;
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_PARENS_LIMIT:
|
||||
*((unsigned long int *)where) = PARENS_NEST_LIMIT;
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_MATCH_LIMIT:
|
||||
*((unsigned long int *)where) = MATCH_LIMIT;
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_MATCH_LIMIT_RECURSION:
|
||||
*((unsigned long int *)where) = MATCH_LIMIT_RECURSION;
|
||||
break;
|
||||
|
||||
case PCRE_CONFIG_STACKRECURSE:
|
||||
#ifdef NO_RECURSE
|
||||
*((int *)where) = 0;
|
||||
#else
|
||||
*((int *)where) = 1;
|
||||
#endif
|
||||
break;
|
||||
|
||||
default: return PCRE_ERROR_BADOPTION;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* End of pcre_config.c */
|
||||
+3674
File diff suppressed because it is too large
Load Diff
+7171
File diff suppressed because it is too large
Load Diff
+243
@@ -0,0 +1,243 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2013 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 the external function pcre_fullinfo(), which returns
|
||||
information about a compiled pattern. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Return info about compiled pattern *
|
||||
*************************************************/
|
||||
|
||||
/* This is a newer "info" function which has an extensible interface so
|
||||
that additional items can be added compatibly.
|
||||
|
||||
Arguments:
|
||||
argument_re points to compiled code
|
||||
extra_data points extra data, or NULL
|
||||
what what information is required
|
||||
where where to put the information
|
||||
|
||||
Returns: 0 if data returned, negative on error
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data,
|
||||
int what, void *where)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_fullinfo(const pcre16 *argument_re, const pcre16_extra *extra_data,
|
||||
int what, void *where)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_fullinfo(const pcre32 *argument_re, const pcre32_extra *extra_data,
|
||||
int what, void *where)
|
||||
#endif
|
||||
{
|
||||
const REAL_PCRE *re = (const REAL_PCRE *)argument_re;
|
||||
const pcre_study_data *study = NULL;
|
||||
|
||||
if (re == NULL || where == NULL) return PCRE_ERROR_NULL;
|
||||
|
||||
if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0)
|
||||
study = (const pcre_study_data *)extra_data->study_data;
|
||||
|
||||
/* Check that the first field in the block is the magic number. If it is not,
|
||||
return with PCRE_ERROR_BADMAGIC. However, if the magic number is equal to
|
||||
REVERSED_MAGIC_NUMBER we return with PCRE_ERROR_BADENDIANNESS, which
|
||||
means that the pattern is likely compiled with different endianness. */
|
||||
|
||||
if (re->magic_number != MAGIC_NUMBER)
|
||||
return re->magic_number == REVERSED_MAGIC_NUMBER?
|
||||
PCRE_ERROR_BADENDIANNESS:PCRE_ERROR_BADMAGIC;
|
||||
|
||||
/* Check that this pattern was compiled in the correct bit mode */
|
||||
|
||||
if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
|
||||
|
||||
switch (what)
|
||||
{
|
||||
case PCRE_INFO_OPTIONS:
|
||||
*((unsigned long int *)where) = re->options & PUBLIC_COMPILE_OPTIONS;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_SIZE:
|
||||
*((size_t *)where) = re->size;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_STUDYSIZE:
|
||||
*((size_t *)where) = (study == NULL)? 0 : study->size;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_JITSIZE:
|
||||
#ifdef SUPPORT_JIT
|
||||
*((size_t *)where) =
|
||||
(extra_data != NULL &&
|
||||
(extra_data->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
|
||||
extra_data->executable_jit != NULL)?
|
||||
PRIV(jit_get_size)(extra_data->executable_jit) : 0;
|
||||
#else
|
||||
*((size_t *)where) = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PCRE_INFO_CAPTURECOUNT:
|
||||
*((int *)where) = re->top_bracket;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_BACKREFMAX:
|
||||
*((int *)where) = re->top_backref;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_FIRSTBYTE:
|
||||
*((int *)where) =
|
||||
((re->flags & PCRE_FIRSTSET) != 0)? (int)re->first_char :
|
||||
((re->flags & PCRE_STARTLINE) != 0)? -1 : -2;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_FIRSTCHARACTER:
|
||||
*((pcre_uint32 *)where) =
|
||||
(re->flags & PCRE_FIRSTSET) != 0 ? re->first_char : 0;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_FIRSTCHARACTERFLAGS:
|
||||
*((int *)where) =
|
||||
((re->flags & PCRE_FIRSTSET) != 0) ? 1 :
|
||||
((re->flags & PCRE_STARTLINE) != 0) ? 2 : 0;
|
||||
break;
|
||||
|
||||
/* Make sure we pass back the pointer to the bit vector in the external
|
||||
block, not the internal copy (with flipped integer fields). */
|
||||
|
||||
case PCRE_INFO_FIRSTTABLE:
|
||||
*((const pcre_uint8 **)where) =
|
||||
(study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0)?
|
||||
((const pcre_study_data *)extra_data->study_data)->start_bits : NULL;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_MINLENGTH:
|
||||
*((int *)where) =
|
||||
(study != NULL && (study->flags & PCRE_STUDY_MINLEN) != 0)?
|
||||
(int)(study->minlength) : -1;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_JIT:
|
||||
*((int *)where) = extra_data != NULL &&
|
||||
(extra_data->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
|
||||
extra_data->executable_jit != NULL;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_LASTLITERAL:
|
||||
*((int *)where) =
|
||||
((re->flags & PCRE_REQCHSET) != 0)? (int)re->req_char : -1;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_REQUIREDCHAR:
|
||||
*((pcre_uint32 *)where) =
|
||||
((re->flags & PCRE_REQCHSET) != 0) ? re->req_char : 0;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_REQUIREDCHARFLAGS:
|
||||
*((int *)where) =
|
||||
((re->flags & PCRE_REQCHSET) != 0);
|
||||
break;
|
||||
|
||||
case PCRE_INFO_NAMEENTRYSIZE:
|
||||
*((int *)where) = re->name_entry_size;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_NAMECOUNT:
|
||||
*((int *)where) = re->name_count;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_NAMETABLE:
|
||||
*((const pcre_uchar **)where) = (const pcre_uchar *)re + re->name_table_offset;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_DEFAULT_TABLES:
|
||||
*((const pcre_uint8 **)where) = (const pcre_uint8 *)(PRIV(default_tables));
|
||||
break;
|
||||
|
||||
/* From release 8.00 this will always return TRUE because NOPARTIAL is
|
||||
no longer ever set (the restrictions have been removed). */
|
||||
|
||||
case PCRE_INFO_OKPARTIAL:
|
||||
*((int *)where) = (re->flags & PCRE_NOPARTIAL) == 0;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_JCHANGED:
|
||||
*((int *)where) = (re->flags & PCRE_JCHANGED) != 0;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_HASCRORLF:
|
||||
*((int *)where) = (re->flags & PCRE_HASCRORLF) != 0;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_MAXLOOKBEHIND:
|
||||
*((int *)where) = re->max_lookbehind;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_MATCHLIMIT:
|
||||
if ((re->flags & PCRE_MLSET) == 0) return PCRE_ERROR_UNSET;
|
||||
*((pcre_uint32 *)where) = re->limit_match;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_RECURSIONLIMIT:
|
||||
if ((re->flags & PCRE_RLSET) == 0) return PCRE_ERROR_UNSET;
|
||||
*((pcre_uint32 *)where) = re->limit_recursion;
|
||||
break;
|
||||
|
||||
case PCRE_INFO_MATCH_EMPTY:
|
||||
*((int *)where) = (re->flags & PCRE_MATCH_EMPTY) != 0;
|
||||
break;
|
||||
|
||||
default: return PCRE_ERROR_BADOPTION;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* End of pcre_fullinfo.c */
|
||||
+667
@@ -0,0 +1,667 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 convenience functions for extracting substrings
|
||||
from the subject string after a regex match has succeeded. The original idea
|
||||
for these functions came from Scott Wimer. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Find number for named string *
|
||||
*************************************************/
|
||||
|
||||
/* This function is used by the get_first_set() function below, as well
|
||||
as being generally available. It assumes that names are unique.
|
||||
|
||||
Arguments:
|
||||
code the compiled regex
|
||||
stringname the name whose number is required
|
||||
|
||||
Returns: the number of the named parentheses, or a negative number
|
||||
(PCRE_ERROR_NOSUBSTRING) if not found
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_get_stringnumber(const pcre *code, const char *stringname)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_get_stringnumber(const pcre16 *code, PCRE_SPTR16 stringname)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_get_stringnumber(const pcre32 *code, PCRE_SPTR32 stringname)
|
||||
#endif
|
||||
{
|
||||
int rc;
|
||||
int entrysize;
|
||||
int top, bot;
|
||||
pcre_uchar *nametable;
|
||||
|
||||
#ifdef COMPILE_PCRE8
|
||||
if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
|
||||
return rc;
|
||||
if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
|
||||
|
||||
if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
|
||||
return rc;
|
||||
if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
|
||||
return rc;
|
||||
#endif
|
||||
#ifdef COMPILE_PCRE16
|
||||
if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
|
||||
return rc;
|
||||
if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
|
||||
|
||||
if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
|
||||
return rc;
|
||||
if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
|
||||
return rc;
|
||||
#endif
|
||||
#ifdef COMPILE_PCRE32
|
||||
if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
|
||||
return rc;
|
||||
if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
|
||||
|
||||
if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
|
||||
return rc;
|
||||
if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
|
||||
return rc;
|
||||
#endif
|
||||
|
||||
bot = 0;
|
||||
while (top > bot)
|
||||
{
|
||||
int mid = (top + bot) / 2;
|
||||
pcre_uchar *entry = nametable + entrysize*mid;
|
||||
int c = STRCMP_UC_UC((pcre_uchar *)stringname,
|
||||
(pcre_uchar *)(entry + IMM2_SIZE));
|
||||
if (c == 0) return GET2(entry, 0);
|
||||
if (c > 0) bot = mid + 1; else top = mid;
|
||||
}
|
||||
|
||||
return PCRE_ERROR_NOSUBSTRING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Find (multiple) entries for named string *
|
||||
*************************************************/
|
||||
|
||||
/* This is used by the get_first_set() function below, as well as being
|
||||
generally available. It is used when duplicated names are permitted.
|
||||
|
||||
Arguments:
|
||||
code the compiled regex
|
||||
stringname the name whose entries required
|
||||
firstptr where to put the pointer to the first entry
|
||||
lastptr where to put the pointer to the last entry
|
||||
|
||||
Returns: the length of each entry, or a negative number
|
||||
(PCRE_ERROR_NOSUBSTRING) if not found
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_get_stringtable_entries(const pcre *code, const char *stringname,
|
||||
char **firstptr, char **lastptr)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_get_stringtable_entries(const pcre16 *code, PCRE_SPTR16 stringname,
|
||||
PCRE_UCHAR16 **firstptr, PCRE_UCHAR16 **lastptr)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_get_stringtable_entries(const pcre32 *code, PCRE_SPTR32 stringname,
|
||||
PCRE_UCHAR32 **firstptr, PCRE_UCHAR32 **lastptr)
|
||||
#endif
|
||||
{
|
||||
int rc;
|
||||
int entrysize;
|
||||
int top, bot;
|
||||
pcre_uchar *nametable, *lastentry;
|
||||
|
||||
#ifdef COMPILE_PCRE8
|
||||
if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
|
||||
return rc;
|
||||
if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
|
||||
|
||||
if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
|
||||
return rc;
|
||||
if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
|
||||
return rc;
|
||||
#endif
|
||||
#ifdef COMPILE_PCRE16
|
||||
if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
|
||||
return rc;
|
||||
if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
|
||||
|
||||
if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
|
||||
return rc;
|
||||
if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
|
||||
return rc;
|
||||
#endif
|
||||
#ifdef COMPILE_PCRE32
|
||||
if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
|
||||
return rc;
|
||||
if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
|
||||
|
||||
if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
|
||||
return rc;
|
||||
if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
|
||||
return rc;
|
||||
#endif
|
||||
|
||||
lastentry = nametable + entrysize * (top - 1);
|
||||
bot = 0;
|
||||
while (top > bot)
|
||||
{
|
||||
int mid = (top + bot) / 2;
|
||||
pcre_uchar *entry = nametable + entrysize*mid;
|
||||
int c = STRCMP_UC_UC((pcre_uchar *)stringname,
|
||||
(pcre_uchar *)(entry + IMM2_SIZE));
|
||||
if (c == 0)
|
||||
{
|
||||
pcre_uchar *first = entry;
|
||||
pcre_uchar *last = entry;
|
||||
while (first > nametable)
|
||||
{
|
||||
if (STRCMP_UC_UC((pcre_uchar *)stringname,
|
||||
(pcre_uchar *)(first - entrysize + IMM2_SIZE)) != 0) break;
|
||||
first -= entrysize;
|
||||
}
|
||||
while (last < lastentry)
|
||||
{
|
||||
if (STRCMP_UC_UC((pcre_uchar *)stringname,
|
||||
(pcre_uchar *)(last + entrysize + IMM2_SIZE)) != 0) break;
|
||||
last += entrysize;
|
||||
}
|
||||
#if defined COMPILE_PCRE8
|
||||
*firstptr = (char *)first;
|
||||
*lastptr = (char *)last;
|
||||
#elif defined COMPILE_PCRE16
|
||||
*firstptr = (PCRE_UCHAR16 *)first;
|
||||
*lastptr = (PCRE_UCHAR16 *)last;
|
||||
#elif defined COMPILE_PCRE32
|
||||
*firstptr = (PCRE_UCHAR32 *)first;
|
||||
*lastptr = (PCRE_UCHAR32 *)last;
|
||||
#endif
|
||||
return entrysize;
|
||||
}
|
||||
if (c > 0) bot = mid + 1; else top = mid;
|
||||
}
|
||||
|
||||
return PCRE_ERROR_NOSUBSTRING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Find first set of multiple named strings *
|
||||
*************************************************/
|
||||
|
||||
/* This function allows for duplicate names in the table of named substrings.
|
||||
It returns the number of the first one that was set in a pattern match.
|
||||
|
||||
Arguments:
|
||||
code the compiled regex
|
||||
stringname the name of the capturing substring
|
||||
ovector the vector of matched substrings
|
||||
stringcount number of captured substrings
|
||||
|
||||
Returns: the number of the first that is set,
|
||||
or the number of the last one if none are set,
|
||||
or a negative number on error
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
static int
|
||||
get_first_set(const pcre *code, const char *stringname, int *ovector,
|
||||
int stringcount)
|
||||
#elif defined COMPILE_PCRE16
|
||||
static int
|
||||
get_first_set(const pcre16 *code, PCRE_SPTR16 stringname, int *ovector,
|
||||
int stringcount)
|
||||
#elif defined COMPILE_PCRE32
|
||||
static int
|
||||
get_first_set(const pcre32 *code, PCRE_SPTR32 stringname, int *ovector,
|
||||
int stringcount)
|
||||
#endif
|
||||
{
|
||||
const REAL_PCRE *re = (const REAL_PCRE *)code;
|
||||
int entrysize;
|
||||
pcre_uchar *entry;
|
||||
#if defined COMPILE_PCRE8
|
||||
char *first, *last;
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_UCHAR16 *first, *last;
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_UCHAR32 *first, *last;
|
||||
#endif
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0)
|
||||
return pcre_get_stringnumber(code, stringname);
|
||||
entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last);
|
||||
#elif defined COMPILE_PCRE16
|
||||
if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0)
|
||||
return pcre16_get_stringnumber(code, stringname);
|
||||
entrysize = pcre16_get_stringtable_entries(code, stringname, &first, &last);
|
||||
#elif defined COMPILE_PCRE32
|
||||
if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0)
|
||||
return pcre32_get_stringnumber(code, stringname);
|
||||
entrysize = pcre32_get_stringtable_entries(code, stringname, &first, &last);
|
||||
#endif
|
||||
if (entrysize <= 0) return entrysize;
|
||||
for (entry = (pcre_uchar *)first; entry <= (pcre_uchar *)last; entry += entrysize)
|
||||
{
|
||||
int n = GET2(entry, 0);
|
||||
if (n < stringcount && ovector[n*2] >= 0) return n;
|
||||
}
|
||||
return GET2(entry, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Copy captured string to given buffer *
|
||||
*************************************************/
|
||||
|
||||
/* This function copies a single captured substring into a given buffer.
|
||||
Note that we use memcpy() rather than strncpy() in case there are binary zeros
|
||||
in the string.
|
||||
|
||||
Arguments:
|
||||
subject the subject string that was matched
|
||||
ovector pointer to the offsets table
|
||||
stringcount the number of substrings that were captured
|
||||
(i.e. the yield of the pcre_exec call, unless
|
||||
that was zero, in which case it should be 1/3
|
||||
of the offset table size)
|
||||
stringnumber the number of the required substring
|
||||
buffer where to put the substring
|
||||
size the size of the buffer
|
||||
|
||||
Returns: if successful:
|
||||
the length of the copied string, not including the zero
|
||||
that is put on the end; can be zero
|
||||
if not successful:
|
||||
PCRE_ERROR_NOMEMORY (-6) buffer too small
|
||||
PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_copy_substring(const char *subject, int *ovector, int stringcount,
|
||||
int stringnumber, char *buffer, int size)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_copy_substring(PCRE_SPTR16 subject, int *ovector, int stringcount,
|
||||
int stringnumber, PCRE_UCHAR16 *buffer, int size)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_copy_substring(PCRE_SPTR32 subject, int *ovector, int stringcount,
|
||||
int stringnumber, PCRE_UCHAR32 *buffer, int size)
|
||||
#endif
|
||||
{
|
||||
int yield;
|
||||
if (stringnumber < 0 || stringnumber >= stringcount)
|
||||
return PCRE_ERROR_NOSUBSTRING;
|
||||
stringnumber *= 2;
|
||||
yield = ovector[stringnumber+1] - ovector[stringnumber];
|
||||
if (size < yield + 1) return PCRE_ERROR_NOMEMORY;
|
||||
memcpy(buffer, subject + ovector[stringnumber], IN_UCHARS(yield));
|
||||
buffer[yield] = 0;
|
||||
return yield;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Copy named captured string to given buffer *
|
||||
*************************************************/
|
||||
|
||||
/* This function copies a single captured substring into a given buffer,
|
||||
identifying it by name. If the regex permits duplicate names, the first
|
||||
substring that is set is chosen.
|
||||
|
||||
Arguments:
|
||||
code the compiled regex
|
||||
subject the subject string that was matched
|
||||
ovector pointer to the offsets table
|
||||
stringcount the number of substrings that were captured
|
||||
(i.e. the yield of the pcre_exec call, unless
|
||||
that was zero, in which case it should be 1/3
|
||||
of the offset table size)
|
||||
stringname the name of the required substring
|
||||
buffer where to put the substring
|
||||
size the size of the buffer
|
||||
|
||||
Returns: if successful:
|
||||
the length of the copied string, not including the zero
|
||||
that is put on the end; can be zero
|
||||
if not successful:
|
||||
PCRE_ERROR_NOMEMORY (-6) buffer too small
|
||||
PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_copy_named_substring(const pcre *code, const char *subject,
|
||||
int *ovector, int stringcount, const char *stringname,
|
||||
char *buffer, int size)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_copy_named_substring(const pcre16 *code, PCRE_SPTR16 subject,
|
||||
int *ovector, int stringcount, PCRE_SPTR16 stringname,
|
||||
PCRE_UCHAR16 *buffer, int size)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_copy_named_substring(const pcre32 *code, PCRE_SPTR32 subject,
|
||||
int *ovector, int stringcount, PCRE_SPTR32 stringname,
|
||||
PCRE_UCHAR32 *buffer, int size)
|
||||
#endif
|
||||
{
|
||||
int n = get_first_set(code, stringname, ovector, stringcount);
|
||||
if (n <= 0) return n;
|
||||
#if defined COMPILE_PCRE8
|
||||
return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size);
|
||||
#elif defined COMPILE_PCRE16
|
||||
return pcre16_copy_substring(subject, ovector, stringcount, n, buffer, size);
|
||||
#elif defined COMPILE_PCRE32
|
||||
return pcre32_copy_substring(subject, ovector, stringcount, n, buffer, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Copy all captured strings to new store *
|
||||
*************************************************/
|
||||
|
||||
/* This function gets one chunk of store and builds a list of pointers and all
|
||||
of the captured substrings in it. A NULL pointer is put on the end of the list.
|
||||
|
||||
Arguments:
|
||||
subject the subject string that was matched
|
||||
ovector pointer to the offsets table
|
||||
stringcount the number of substrings that were captured
|
||||
(i.e. the yield of the pcre_exec call, unless
|
||||
that was zero, in which case it should be 1/3
|
||||
of the offset table size)
|
||||
listptr set to point to the list of pointers
|
||||
|
||||
Returns: if successful: 0
|
||||
if not successful:
|
||||
PCRE_ERROR_NOMEMORY (-6) failed to get store
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_get_substring_list(const char *subject, int *ovector, int stringcount,
|
||||
const char ***listptr)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_get_substring_list(PCRE_SPTR16 subject, int *ovector, int stringcount,
|
||||
PCRE_SPTR16 **listptr)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_get_substring_list(PCRE_SPTR32 subject, int *ovector, int stringcount,
|
||||
PCRE_SPTR32 **listptr)
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
int size = sizeof(pcre_uchar *);
|
||||
int double_count = stringcount * 2;
|
||||
pcre_uchar **stringlist;
|
||||
pcre_uchar *p;
|
||||
|
||||
for (i = 0; i < double_count; i += 2)
|
||||
{
|
||||
size += sizeof(pcre_uchar *) + IN_UCHARS(1);
|
||||
if (ovector[i+1] > ovector[i]) size += IN_UCHARS(ovector[i+1] - ovector[i]);
|
||||
}
|
||||
|
||||
stringlist = (pcre_uchar **)(PUBL(malloc))(size);
|
||||
if (stringlist == NULL) return PCRE_ERROR_NOMEMORY;
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
*listptr = (const char **)stringlist;
|
||||
#elif defined COMPILE_PCRE16
|
||||
*listptr = (PCRE_SPTR16 *)stringlist;
|
||||
#elif defined COMPILE_PCRE32
|
||||
*listptr = (PCRE_SPTR32 *)stringlist;
|
||||
#endif
|
||||
p = (pcre_uchar *)(stringlist + stringcount + 1);
|
||||
|
||||
for (i = 0; i < double_count; i += 2)
|
||||
{
|
||||
int len = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0;
|
||||
memcpy(p, subject + ovector[i], IN_UCHARS(len));
|
||||
*stringlist++ = p;
|
||||
p += len;
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
*stringlist = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Free store obtained by get_substring_list *
|
||||
*************************************************/
|
||||
|
||||
/* This function exists for the benefit of people calling PCRE from non-C
|
||||
programs that can call its functions, but not free() or (PUBL(free))()
|
||||
directly.
|
||||
|
||||
Argument: the result of a previous pcre_get_substring_list()
|
||||
Returns: nothing
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
|
||||
pcre_free_substring_list(const char **pointer)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
|
||||
pcre16_free_substring_list(PCRE_SPTR16 *pointer)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
|
||||
pcre32_free_substring_list(PCRE_SPTR32 *pointer)
|
||||
#endif
|
||||
{
|
||||
(PUBL(free))((void *)pointer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Copy captured string to new store *
|
||||
*************************************************/
|
||||
|
||||
/* This function copies a single captured substring into a piece of new
|
||||
store
|
||||
|
||||
Arguments:
|
||||
subject the subject string that was matched
|
||||
ovector pointer to the offsets table
|
||||
stringcount the number of substrings that were captured
|
||||
(i.e. the yield of the pcre_exec call, unless
|
||||
that was zero, in which case it should be 1/3
|
||||
of the offset table size)
|
||||
stringnumber the number of the required substring
|
||||
stringptr where to put a pointer to the substring
|
||||
|
||||
Returns: if successful:
|
||||
the length of the string, not including the zero that
|
||||
is put on the end; can be zero
|
||||
if not successful:
|
||||
PCRE_ERROR_NOMEMORY (-6) failed to get store
|
||||
PCRE_ERROR_NOSUBSTRING (-7) substring not present
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_get_substring(const char *subject, int *ovector, int stringcount,
|
||||
int stringnumber, const char **stringptr)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_get_substring(PCRE_SPTR16 subject, int *ovector, int stringcount,
|
||||
int stringnumber, PCRE_SPTR16 *stringptr)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_get_substring(PCRE_SPTR32 subject, int *ovector, int stringcount,
|
||||
int stringnumber, PCRE_SPTR32 *stringptr)
|
||||
#endif
|
||||
{
|
||||
int yield;
|
||||
pcre_uchar *substring;
|
||||
if (stringnumber < 0 || stringnumber >= stringcount)
|
||||
return PCRE_ERROR_NOSUBSTRING;
|
||||
stringnumber *= 2;
|
||||
yield = ovector[stringnumber+1] - ovector[stringnumber];
|
||||
substring = (pcre_uchar *)(PUBL(malloc))(IN_UCHARS(yield + 1));
|
||||
if (substring == NULL) return PCRE_ERROR_NOMEMORY;
|
||||
memcpy(substring, subject + ovector[stringnumber], IN_UCHARS(yield));
|
||||
substring[yield] = 0;
|
||||
#if defined COMPILE_PCRE8
|
||||
*stringptr = (const char *)substring;
|
||||
#elif defined COMPILE_PCRE16
|
||||
*stringptr = (PCRE_SPTR16)substring;
|
||||
#elif defined COMPILE_PCRE32
|
||||
*stringptr = (PCRE_SPTR32)substring;
|
||||
#endif
|
||||
return yield;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Copy named captured string to new store *
|
||||
*************************************************/
|
||||
|
||||
/* This function copies a single captured substring, identified by name, into
|
||||
new store. If the regex permits duplicate names, the first substring that is
|
||||
set is chosen.
|
||||
|
||||
Arguments:
|
||||
code the compiled regex
|
||||
subject the subject string that was matched
|
||||
ovector pointer to the offsets table
|
||||
stringcount the number of substrings that were captured
|
||||
(i.e. the yield of the pcre_exec call, unless
|
||||
that was zero, in which case it should be 1/3
|
||||
of the offset table size)
|
||||
stringname the name of the required substring
|
||||
stringptr where to put the pointer
|
||||
|
||||
Returns: if successful:
|
||||
the length of the copied string, not including the zero
|
||||
that is put on the end; can be zero
|
||||
if not successful:
|
||||
PCRE_ERROR_NOMEMORY (-6) couldn't get memory
|
||||
PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_get_named_substring(const pcre *code, const char *subject,
|
||||
int *ovector, int stringcount, const char *stringname,
|
||||
const char **stringptr)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_get_named_substring(const pcre16 *code, PCRE_SPTR16 subject,
|
||||
int *ovector, int stringcount, PCRE_SPTR16 stringname,
|
||||
PCRE_SPTR16 *stringptr)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_get_named_substring(const pcre32 *code, PCRE_SPTR32 subject,
|
||||
int *ovector, int stringcount, PCRE_SPTR32 stringname,
|
||||
PCRE_SPTR32 *stringptr)
|
||||
#endif
|
||||
{
|
||||
int n = get_first_set(code, stringname, ovector, stringcount);
|
||||
if (n <= 0) return n;
|
||||
#if defined COMPILE_PCRE8
|
||||
return pcre_get_substring(subject, ovector, stringcount, n, stringptr);
|
||||
#elif defined COMPILE_PCRE16
|
||||
return pcre16_get_substring(subject, ovector, stringcount, n, stringptr);
|
||||
#elif defined COMPILE_PCRE32
|
||||
return pcre32_get_substring(subject, ovector, stringcount, n, stringptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Free store obtained by get_substring *
|
||||
*************************************************/
|
||||
|
||||
/* This function exists for the benefit of people calling PCRE from non-C
|
||||
programs that can call its functions, but not free() or (PUBL(free))()
|
||||
directly.
|
||||
|
||||
Argument: the result of a previous pcre_get_substring()
|
||||
Returns: nothing
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
|
||||
pcre_free_substring(const char *pointer)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
|
||||
pcre16_free_substring(PCRE_SPTR16 pointer)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
|
||||
pcre32_free_substring(PCRE_SPTR32 pointer)
|
||||
#endif
|
||||
{
|
||||
(PUBL(free))((void *)pointer);
|
||||
}
|
||||
|
||||
/* End of pcre_get.c */
|
||||
@@ -0,0 +1,84 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2014 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 global variables that are exported by the PCRE library.
|
||||
PCRE is thread-clean and doesn't use any global variables in the normal sense.
|
||||
However, it calls memory allocation and freeing functions via the four
|
||||
indirections below, and it can optionally do callouts, using the fifth
|
||||
indirection. These values can be changed by the caller, but are shared between
|
||||
all threads.
|
||||
|
||||
For MS Visual Studio and Symbian OS, there are problems in initializing these
|
||||
variables to non-local functions. In these cases, therefore, an indirection via
|
||||
a local function is used.
|
||||
|
||||
Also, when compiling for Virtual Pascal, things are done differently, and
|
||||
global variables are not used. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
#if defined _MSC_VER || defined __SYMBIAN32__
|
||||
static void* LocalPcreMalloc(size_t aSize)
|
||||
{
|
||||
return malloc(aSize);
|
||||
}
|
||||
static void LocalPcreFree(void* aPtr)
|
||||
{
|
||||
free(aPtr);
|
||||
}
|
||||
PCRE_EXP_DATA_DEFN void *(*PUBL(malloc))(size_t) = LocalPcreMalloc;
|
||||
PCRE_EXP_DATA_DEFN void (*PUBL(free))(void *) = LocalPcreFree;
|
||||
PCRE_EXP_DATA_DEFN void *(*PUBL(stack_malloc))(size_t) = LocalPcreMalloc;
|
||||
PCRE_EXP_DATA_DEFN void (*PUBL(stack_free))(void *) = LocalPcreFree;
|
||||
PCRE_EXP_DATA_DEFN int (*PUBL(callout))(PUBL(callout_block) *) = NULL;
|
||||
PCRE_EXP_DATA_DEFN int (*PUBL(stack_guard))(void) = NULL;
|
||||
|
||||
#elif !defined VPCOMPAT
|
||||
PCRE_EXP_DATA_DEFN void *(*PUBL(malloc))(size_t) = malloc;
|
||||
PCRE_EXP_DATA_DEFN void (*PUBL(free))(void *) = free;
|
||||
PCRE_EXP_DATA_DEFN void *(*PUBL(stack_malloc))(size_t) = malloc;
|
||||
PCRE_EXP_DATA_DEFN void (*PUBL(stack_free))(void *) = free;
|
||||
PCRE_EXP_DATA_DEFN int (*PUBL(callout))(PUBL(callout_block) *) = NULL;
|
||||
PCRE_EXP_DATA_DEFN int (*PUBL(stack_guard))(void) = NULL;
|
||||
#endif
|
||||
|
||||
/* End of pcre_globals.c */
|
||||
+2807
File diff suppressed because it is too large
Load Diff
+11911
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,154 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 the external function pcre_maketables(), which builds
|
||||
character tables for PCRE in the current locale. The file is compiled on its
|
||||
own as part of the PCRE library. However, it is also included in the
|
||||
compilation of dftables.c, in which case the macro DFTABLES is defined. */
|
||||
|
||||
|
||||
#ifndef DFTABLES
|
||||
# include "config.h"
|
||||
# include "pcre_internal.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Create PCRE character tables *
|
||||
*************************************************/
|
||||
|
||||
/* This function builds a set of character tables for use by PCRE and returns
|
||||
a pointer to them. They are build using the ctype functions, and consequently
|
||||
their contents will depend upon the current locale setting. When compiled as
|
||||
part of the library, the store is obtained via PUBL(malloc)(), but when
|
||||
compiled inside dftables, use malloc().
|
||||
|
||||
Arguments: none
|
||||
Returns: pointer to the contiguous block of data
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
const unsigned char *
|
||||
pcre_maketables(void)
|
||||
#elif defined COMPILE_PCRE16
|
||||
const unsigned char *
|
||||
pcre16_maketables(void)
|
||||
#elif defined COMPILE_PCRE32
|
||||
const unsigned char *
|
||||
pcre32_maketables(void)
|
||||
#endif
|
||||
{
|
||||
unsigned char *yield, *p;
|
||||
int i;
|
||||
|
||||
#ifndef DFTABLES
|
||||
yield = (unsigned char*)(PUBL(malloc))(tables_length);
|
||||
#else
|
||||
yield = (unsigned char*)malloc(tables_length);
|
||||
#endif
|
||||
|
||||
if (yield == NULL) return NULL;
|
||||
p = yield;
|
||||
|
||||
/* First comes the lower casing table */
|
||||
|
||||
for (i = 0; i < 256; i++) *p++ = tolower(i);
|
||||
|
||||
/* Next the case-flipping table */
|
||||
|
||||
for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i);
|
||||
|
||||
/* Then the character class tables. Don't try to be clever and save effort on
|
||||
exclusive ones - in some locales things may be different.
|
||||
|
||||
Note that the table for "space" includes everything "isspace" gives, including
|
||||
VT in the default locale. This makes it work for the POSIX class [:space:].
|
||||
From release 8.34 is is also correct for Perl space, because Perl added VT at
|
||||
release 5.18.
|
||||
|
||||
Note also that it is possible for a character to be alnum or alpha without
|
||||
being lower or upper, such as "male and female ordinals" (\xAA and \xBA) in the
|
||||
fr_FR locale (at least under Debian Linux's locales as of 12/2005). So we must
|
||||
test for alnum specially. */
|
||||
|
||||
memset(p, 0, cbit_length);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (isdigit(i)) p[cbit_digit + i/8] |= 1 << (i&7);
|
||||
if (isupper(i)) p[cbit_upper + i/8] |= 1 << (i&7);
|
||||
if (islower(i)) p[cbit_lower + i/8] |= 1 << (i&7);
|
||||
if (isalnum(i)) p[cbit_word + i/8] |= 1 << (i&7);
|
||||
if (i == '_') p[cbit_word + i/8] |= 1 << (i&7);
|
||||
if (isspace(i)) p[cbit_space + i/8] |= 1 << (i&7);
|
||||
if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7);
|
||||
if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7);
|
||||
if (isprint(i)) p[cbit_print + i/8] |= 1 << (i&7);
|
||||
if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7);
|
||||
if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7);
|
||||
}
|
||||
p += cbit_length;
|
||||
|
||||
/* Finally, the character type table. In this, we used to exclude VT from the
|
||||
white space chars, because Perl didn't recognize it as such for \s and for
|
||||
comments within regexes. However, Perl changed at release 5.18, so PCRE changed
|
||||
at release 8.34. */
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
int x = 0;
|
||||
if (isspace(i)) x += ctype_space;
|
||||
if (isalpha(i)) x += ctype_letter;
|
||||
if (isdigit(i)) x += ctype_digit;
|
||||
if (isxdigit(i)) x += ctype_xdigit;
|
||||
if (isalnum(i) || i == '_') x += ctype_word;
|
||||
|
||||
/* Note: strchr includes the terminating zero in the characters it considers.
|
||||
In this instance, that is ok because we want binary zero to be flagged as a
|
||||
meta-character, which in this sense is any character that terminates a run
|
||||
of data characters. */
|
||||
|
||||
if (strchr("\\*+?{^.$|()[", i) != 0) x += ctype_meta;
|
||||
*p++ = x;
|
||||
}
|
||||
|
||||
return yield;
|
||||
}
|
||||
|
||||
/* End of pcre_maketables.c */
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 internal functions for testing newlines when more than
|
||||
one kind of newline is to be recognized. When a newline is found, its length is
|
||||
returned. In principle, we could implement several newline "types", each
|
||||
referring to a different set of newline characters. At present, PCRE supports
|
||||
only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF,
|
||||
and NLTYPE_ANY. The full list of Unicode newline characters is taken from
|
||||
http://unicode.org/unicode/reports/tr18/. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Check for newline at given position *
|
||||
*************************************************/
|
||||
|
||||
/* It is guaranteed that the initial value of ptr is less than the end of the
|
||||
string that is being processed.
|
||||
|
||||
Arguments:
|
||||
ptr pointer to possible newline
|
||||
type the newline type
|
||||
endptr pointer to the end of the string
|
||||
lenptr where to return the length
|
||||
utf TRUE if in utf mode
|
||||
|
||||
Returns: TRUE or FALSE
|
||||
*/
|
||||
|
||||
BOOL
|
||||
PRIV(is_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR endptr, int *lenptr,
|
||||
BOOL utf)
|
||||
{
|
||||
pcre_uint32 c;
|
||||
(void)utf;
|
||||
#ifdef SUPPORT_UTF
|
||||
if (utf)
|
||||
{
|
||||
GETCHAR(c, ptr);
|
||||
}
|
||||
else
|
||||
#endif /* SUPPORT_UTF */
|
||||
c = *ptr;
|
||||
|
||||
/* Note that this function is called only for ANY or ANYCRLF. */
|
||||
|
||||
if (type == NLTYPE_ANYCRLF) switch(c)
|
||||
{
|
||||
case CHAR_LF: *lenptr = 1; return TRUE;
|
||||
case CHAR_CR: *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
|
||||
return TRUE;
|
||||
default: return FALSE;
|
||||
}
|
||||
|
||||
/* NLTYPE_ANY */
|
||||
|
||||
else switch(c)
|
||||
{
|
||||
#ifdef EBCDIC
|
||||
case CHAR_NEL:
|
||||
#endif
|
||||
case CHAR_LF:
|
||||
case CHAR_VT:
|
||||
case CHAR_FF: *lenptr = 1; return TRUE;
|
||||
|
||||
case CHAR_CR:
|
||||
*lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
|
||||
return TRUE;
|
||||
|
||||
#ifndef EBCDIC
|
||||
#ifdef COMPILE_PCRE8
|
||||
case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE;
|
||||
case 0x2028: /* LS */
|
||||
case 0x2029: *lenptr = 3; return TRUE; /* PS */
|
||||
#else /* COMPILE_PCRE16 || COMPILE_PCRE32 */
|
||||
case CHAR_NEL:
|
||||
case 0x2028: /* LS */
|
||||
case 0x2029: *lenptr = 1; return TRUE; /* PS */
|
||||
#endif /* COMPILE_PCRE8 */
|
||||
#endif /* Not EBCDIC */
|
||||
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Check for newline at previous position *
|
||||
*************************************************/
|
||||
|
||||
/* It is guaranteed that the initial value of ptr is greater than the start of
|
||||
the string that is being processed.
|
||||
|
||||
Arguments:
|
||||
ptr pointer to possible newline
|
||||
type the newline type
|
||||
startptr pointer to the start of the string
|
||||
lenptr where to return the length
|
||||
utf TRUE if in utf mode
|
||||
|
||||
Returns: TRUE or FALSE
|
||||
*/
|
||||
|
||||
BOOL
|
||||
PRIV(was_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR startptr, int *lenptr,
|
||||
BOOL utf)
|
||||
{
|
||||
pcre_uint32 c;
|
||||
(void)utf;
|
||||
ptr--;
|
||||
#ifdef SUPPORT_UTF
|
||||
if (utf)
|
||||
{
|
||||
BACKCHAR(ptr);
|
||||
GETCHAR(c, ptr);
|
||||
}
|
||||
else
|
||||
#endif /* SUPPORT_UTF */
|
||||
c = *ptr;
|
||||
|
||||
/* Note that this function is called only for ANY or ANYCRLF. */
|
||||
|
||||
if (type == NLTYPE_ANYCRLF) switch(c)
|
||||
{
|
||||
case CHAR_LF:
|
||||
*lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1;
|
||||
return TRUE;
|
||||
|
||||
case CHAR_CR: *lenptr = 1; return TRUE;
|
||||
default: return FALSE;
|
||||
}
|
||||
|
||||
/* NLTYPE_ANY */
|
||||
|
||||
else switch(c)
|
||||
{
|
||||
case CHAR_LF:
|
||||
*lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1;
|
||||
return TRUE;
|
||||
|
||||
#ifdef EBCDIC
|
||||
case CHAR_NEL:
|
||||
#endif
|
||||
case CHAR_VT:
|
||||
case CHAR_FF:
|
||||
case CHAR_CR: *lenptr = 1; return TRUE;
|
||||
|
||||
#ifndef EBCDIC
|
||||
#ifdef COMPILE_PCRE8
|
||||
case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE;
|
||||
case 0x2028: /* LS */
|
||||
case 0x2029: *lenptr = 3; return TRUE; /* PS */
|
||||
#else /* COMPILE_PCRE16 || COMPILE_PCRE32 */
|
||||
case CHAR_NEL:
|
||||
case 0x2028: /* LS */
|
||||
case 0x2029: *lenptr = 1; return TRUE; /* PS */
|
||||
#endif /* COMPILE_PCRE8 */
|
||||
#endif /* NotEBCDIC */
|
||||
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* End of pcre_newline.c */
|
||||
@@ -0,0 +1,92 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 file contains a private PCRE function that converts an ordinal
|
||||
character value into a UTF8 string. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define COMPILE_PCRE8
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
/*************************************************
|
||||
* Convert character value to UTF-8 *
|
||||
*************************************************/
|
||||
|
||||
/* This function takes an integer value in the range 0 - 0x10ffff
|
||||
and encodes it as a UTF-8 character in 1 to 4 pcre_uchars.
|
||||
|
||||
Arguments:
|
||||
cvalue the character value
|
||||
buffer pointer to buffer for result - at least 6 pcre_uchars long
|
||||
|
||||
Returns: number of characters placed in the buffer
|
||||
*/
|
||||
|
||||
unsigned
|
||||
int
|
||||
PRIV(ord2utf)(pcre_uint32 cvalue, pcre_uchar *buffer)
|
||||
{
|
||||
#ifdef SUPPORT_UTF
|
||||
|
||||
register int i, j;
|
||||
|
||||
for (i = 0; i < PRIV(utf8_table1_size); i++)
|
||||
if ((int)cvalue <= PRIV(utf8_table1)[i]) break;
|
||||
buffer += i;
|
||||
for (j = i; j > 0; j--)
|
||||
{
|
||||
*buffer-- = 0x80 | (cvalue & 0x3f);
|
||||
cvalue >>= 6;
|
||||
}
|
||||
*buffer = PRIV(utf8_table2)[i] | cvalue;
|
||||
return i + 1;
|
||||
|
||||
#else
|
||||
|
||||
(void)(cvalue); /* Keep compiler happy; this function won't ever be */
|
||||
(void)(buffer); /* called when SUPPORT_UTF is not defined. */
|
||||
return 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* End of pcre_ord2utf8.c */
|
||||
@@ -0,0 +1,90 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 the external function pcre_refcount(), which is an
|
||||
auxiliary function that can be used to maintain a reference count in a compiled
|
||||
pattern data block. This might be helpful in applications where the block is
|
||||
shared by different users. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Maintain reference count *
|
||||
*************************************************/
|
||||
|
||||
/* The reference count is a 16-bit field, initialized to zero. It is not
|
||||
possible to transfer a non-zero count from one host to a different host that
|
||||
has a different byte order - though I can't see why anyone in their right mind
|
||||
would ever want to do that!
|
||||
|
||||
Arguments:
|
||||
argument_re points to compiled code
|
||||
adjust value to add to the count
|
||||
|
||||
Returns: the (possibly updated) count value (a non-negative number), or
|
||||
a negative error number
|
||||
*/
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre_refcount(pcre *argument_re, int adjust)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre16_refcount(pcre16 *argument_re, int adjust)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
|
||||
pcre32_refcount(pcre32 *argument_re, int adjust)
|
||||
#endif
|
||||
{
|
||||
REAL_PCRE *re = (REAL_PCRE *)argument_re;
|
||||
if (re == NULL) return PCRE_ERROR_NULL;
|
||||
if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
|
||||
if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
|
||||
re->ref_count = (-adjust > re->ref_count)? 0 :
|
||||
(adjust + re->ref_count > 65535)? 65535 :
|
||||
re->ref_count + adjust;
|
||||
return re->ref_count;
|
||||
}
|
||||
|
||||
/* End of pcre_refcount.c */
|
||||
@@ -0,0 +1,209 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2014 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 internal functions for comparing and finding the length
|
||||
of strings for different data item sizes. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
#ifndef COMPILE_PCRE8
|
||||
|
||||
/*************************************************
|
||||
* Compare string utilities *
|
||||
*************************************************/
|
||||
|
||||
/* The following two functions compares two strings. Basically a strcmp
|
||||
for non 8 bit characters.
|
||||
|
||||
Arguments:
|
||||
str1 first string
|
||||
str2 second string
|
||||
|
||||
Returns: 0 if both string are equal (like strcmp), 1 otherwise
|
||||
*/
|
||||
|
||||
int
|
||||
PRIV(strcmp_uc_uc)(const pcre_uchar *str1, const pcre_uchar *str2)
|
||||
{
|
||||
pcre_uchar c1;
|
||||
pcre_uchar c2;
|
||||
|
||||
while (*str1 != '\0' || *str2 != '\0')
|
||||
{
|
||||
c1 = *str1++;
|
||||
c2 = *str2++;
|
||||
if (c1 != c2)
|
||||
return ((c1 > c2) << 1) - 1;
|
||||
}
|
||||
/* Both length and characters must be equal. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef COMPILE_PCRE32
|
||||
|
||||
int
|
||||
PRIV(strcmp_uc_uc_utf)(const pcre_uchar *str1, const pcre_uchar *str2)
|
||||
{
|
||||
pcre_uchar c1;
|
||||
pcre_uchar c2;
|
||||
|
||||
while (*str1 != '\0' || *str2 != '\0')
|
||||
{
|
||||
c1 = UCHAR21INC(str1);
|
||||
c2 = UCHAR21INC(str2);
|
||||
if (c1 != c2)
|
||||
return ((c1 > c2) << 1) - 1;
|
||||
}
|
||||
/* Both length and characters must be equal. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* COMPILE_PCRE32 */
|
||||
|
||||
int
|
||||
PRIV(strcmp_uc_c8)(const pcre_uchar *str1, const char *str2)
|
||||
{
|
||||
const pcre_uint8 *ustr2 = (pcre_uint8 *)str2;
|
||||
pcre_uchar c1;
|
||||
pcre_uchar c2;
|
||||
|
||||
while (*str1 != '\0' || *ustr2 != '\0')
|
||||
{
|
||||
c1 = *str1++;
|
||||
c2 = (pcre_uchar)*ustr2++;
|
||||
if (c1 != c2)
|
||||
return ((c1 > c2) << 1) - 1;
|
||||
}
|
||||
/* Both length and characters must be equal. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef COMPILE_PCRE32
|
||||
|
||||
int
|
||||
PRIV(strcmp_uc_c8_utf)(const pcre_uchar *str1, const char *str2)
|
||||
{
|
||||
const pcre_uint8 *ustr2 = (pcre_uint8 *)str2;
|
||||
pcre_uchar c1;
|
||||
pcre_uchar c2;
|
||||
|
||||
while (*str1 != '\0' || *ustr2 != '\0')
|
||||
{
|
||||
c1 = UCHAR21INC(str1);
|
||||
c2 = (pcre_uchar)*ustr2++;
|
||||
if (c1 != c2)
|
||||
return ((c1 > c2) << 1) - 1;
|
||||
}
|
||||
/* Both length and characters must be equal. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* COMPILE_PCRE32 */
|
||||
|
||||
/* The following two functions compares two, fixed length
|
||||
strings. Basically an strncmp for non 8 bit characters.
|
||||
|
||||
Arguments:
|
||||
str1 first string
|
||||
str2 second string
|
||||
num size of the string
|
||||
|
||||
Returns: 0 if both string are equal (like strcmp), 1 otherwise
|
||||
*/
|
||||
|
||||
int
|
||||
PRIV(strncmp_uc_uc)(const pcre_uchar *str1, const pcre_uchar *str2, unsigned int num)
|
||||
{
|
||||
pcre_uchar c1;
|
||||
pcre_uchar c2;
|
||||
|
||||
while (num-- > 0)
|
||||
{
|
||||
c1 = *str1++;
|
||||
c2 = *str2++;
|
||||
if (c1 != c2)
|
||||
return ((c1 > c2) << 1) - 1;
|
||||
}
|
||||
/* Both length and characters must be equal. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PRIV(strncmp_uc_c8)(const pcre_uchar *str1, const char *str2, unsigned int num)
|
||||
{
|
||||
const pcre_uint8 *ustr2 = (pcre_uint8 *)str2;
|
||||
pcre_uchar c1;
|
||||
pcre_uchar c2;
|
||||
|
||||
while (num-- > 0)
|
||||
{
|
||||
c1 = *str1++;
|
||||
c2 = (pcre_uchar)*ustr2++;
|
||||
if (c1 != c2)
|
||||
return ((c1 > c2) << 1) - 1;
|
||||
}
|
||||
/* Both length and characters must be equal. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The following function returns with the length of
|
||||
a zero terminated string. Basically an strlen for non 8 bit characters.
|
||||
|
||||
Arguments:
|
||||
str string
|
||||
|
||||
Returns: length of the string
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
PRIV(strlen_uc)(const pcre_uchar *str)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
while (*str++ != 0)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif /* !COMPILE_PCRE8 */
|
||||
|
||||
/* End of pcre_string_utils.c */
|
||||
+1684
File diff suppressed because it is too large
Load Diff
+725
@@ -0,0 +1,725 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2017 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef PCRE_INCLUDED
|
||||
|
||||
/* This module contains some fixed tables that are used by more than one of the
|
||||
PCRE code modules. The tables are also #included by the pcretest program, which
|
||||
uses macros to change their names from _pcre_xxx to xxxx, thereby avoiding name
|
||||
clashes with the library. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
#endif /* PCRE_INCLUDED */
|
||||
|
||||
/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
|
||||
the definition is next to the definition of the opcodes in pcre_internal.h. */
|
||||
|
||||
const pcre_uint8 PRIV(OP_lengths)[] = { OP_LENGTHS };
|
||||
|
||||
/* Tables of horizontal and vertical whitespace characters, suitable for
|
||||
adding to classes. */
|
||||
|
||||
const pcre_uint32 PRIV(hspace_list)[] = { HSPACE_LIST };
|
||||
const pcre_uint32 PRIV(vspace_list)[] = { VSPACE_LIST };
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Tables for UTF-8 support *
|
||||
*************************************************/
|
||||
|
||||
/* These are the breakpoints for different numbers of bytes in a UTF-8
|
||||
character. */
|
||||
|
||||
#if (defined SUPPORT_UTF && defined COMPILE_PCRE8) \
|
||||
|| (defined PCRE_INCLUDED && (defined SUPPORT_PCRE16 || defined SUPPORT_PCRE32))
|
||||
|
||||
/* These tables are also required by pcretest in 16- or 32-bit mode. */
|
||||
|
||||
const int PRIV(utf8_table1)[] =
|
||||
{ 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
|
||||
|
||||
const int PRIV(utf8_table1_size) = sizeof(PRIV(utf8_table1)) / sizeof(int);
|
||||
|
||||
/* 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 PRIV(utf8_table2)[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
|
||||
const int PRIV(utf8_table3)[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
|
||||
|
||||
/* Table of the number of extra bytes, indexed by the first byte masked with
|
||||
0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */
|
||||
|
||||
const pcre_uint8 PRIV(utf8_table4)[] = {
|
||||
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 };
|
||||
|
||||
#endif /* (SUPPORT_UTF && COMPILE_PCRE8) || (PCRE_INCLUDED && SUPPORT_PCRE[16|32])*/
|
||||
|
||||
#ifdef SUPPORT_UTF
|
||||
|
||||
/* Table to translate from particular type value to the general value. */
|
||||
|
||||
const pcre_uint32 PRIV(ucp_gentype)[] = {
|
||||
ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */
|
||||
ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */
|
||||
ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */
|
||||
ucp_N, ucp_N, ucp_N, /* Nd, Nl, No */
|
||||
ucp_P, ucp_P, ucp_P, ucp_P, ucp_P, /* Pc, Pd, Pe, Pf, Pi */
|
||||
ucp_P, ucp_P, /* Ps, Po */
|
||||
ucp_S, ucp_S, ucp_S, ucp_S, /* Sc, Sk, Sm, So */
|
||||
ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */
|
||||
};
|
||||
|
||||
/* This table encodes the rules for finding the end of an extended grapheme
|
||||
cluster. Every code point has a grapheme break property which is one of the
|
||||
ucp_gbXX values defined in ucp.h. The 2-dimensional table is indexed by the
|
||||
properties of two adjacent code points. The left property selects a word from
|
||||
the table, and the right property selects a bit from that word like this:
|
||||
|
||||
ucp_gbtable[left-property] & (1 << right-property)
|
||||
|
||||
The value is non-zero if a grapheme break is NOT permitted between the relevant
|
||||
two code points. The breaking rules are as follows:
|
||||
|
||||
1. Break at the start and end of text (pretty obviously).
|
||||
|
||||
2. Do not break between a CR and LF; otherwise, break before and after
|
||||
controls.
|
||||
|
||||
3. Do not break Hangul syllable sequences, the rules for which are:
|
||||
|
||||
L may be followed by L, V, LV or LVT
|
||||
LV or V may be followed by V or T
|
||||
LVT or T may be followed by T
|
||||
|
||||
4. Do not break before extending characters.
|
||||
|
||||
The next two rules are only for extended grapheme clusters (but that's what we
|
||||
are implementing).
|
||||
|
||||
5. Do not break before SpacingMarks.
|
||||
|
||||
6. Do not break after Prepend characters.
|
||||
|
||||
7. Otherwise, break everywhere.
|
||||
*/
|
||||
|
||||
const pcre_uint32 PRIV(ucp_gbtable[]) = {
|
||||
(1<<ucp_gbLF), /* 0 CR */
|
||||
0, /* 1 LF */
|
||||
0, /* 2 Control */
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark), /* 3 Extend */
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbPrepend)| /* 4 Prepend */
|
||||
(1<<ucp_gbSpacingMark)|(1<<ucp_gbL)|
|
||||
(1<<ucp_gbV)|(1<<ucp_gbT)|(1<<ucp_gbLV)|
|
||||
(1<<ucp_gbLVT)|(1<<ucp_gbOther),
|
||||
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark), /* 5 SpacingMark */
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbL)| /* 6 L */
|
||||
(1<<ucp_gbV)|(1<<ucp_gbLV)|(1<<ucp_gbLVT),
|
||||
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbV)| /* 7 V */
|
||||
(1<<ucp_gbT),
|
||||
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbT), /* 8 T */
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbV)| /* 9 LV */
|
||||
(1<<ucp_gbT),
|
||||
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbT), /* 10 LVT */
|
||||
(1<<ucp_gbRegionalIndicator), /* 11 RegionalIndicator */
|
||||
(1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark) /* 12 Other */
|
||||
};
|
||||
|
||||
#ifdef SUPPORT_JIT
|
||||
/* This table reverses PRIV(ucp_gentype). We can save the cost
|
||||
of a memory load. */
|
||||
|
||||
const int PRIV(ucp_typerange)[] = {
|
||||
ucp_Cc, ucp_Cs,
|
||||
ucp_Ll, ucp_Lu,
|
||||
ucp_Mc, ucp_Mn,
|
||||
ucp_Nd, ucp_No,
|
||||
ucp_Pc, ucp_Ps,
|
||||
ucp_Sc, ucp_So,
|
||||
ucp_Zl, ucp_Zs,
|
||||
};
|
||||
#endif /* SUPPORT_JIT */
|
||||
|
||||
/* The pcre_utt[] table below translates Unicode property names into type and
|
||||
code values. It is searched by binary chop, so must be in collating sequence of
|
||||
name. Originally, the table contained pointers to the name strings in the first
|
||||
field of each entry. However, that leads to a large number of relocations when
|
||||
a shared library is dynamically loaded. A significant reduction is made by
|
||||
putting all the names into a single, large string and then using offsets in the
|
||||
table itself. Maintenance is more error-prone, but frequent changes to this
|
||||
data are unlikely.
|
||||
|
||||
July 2008: There is now a script called maint/GenerateUtt.py that can be used
|
||||
to generate this data automatically instead of maintaining it by hand.
|
||||
|
||||
The script was updated in March 2009 to generate a new EBCDIC-compliant
|
||||
version. Like all other character and string literals that are compared against
|
||||
the regular expression pattern, we must use STR_ macros instead of literal
|
||||
strings to make sure that UTF-8 support works on EBCDIC platforms. */
|
||||
|
||||
#define STRING_Any0 STR_A STR_n STR_y "\0"
|
||||
#define STRING_Arabic0 STR_A STR_r STR_a STR_b STR_i STR_c "\0"
|
||||
#define STRING_Armenian0 STR_A STR_r STR_m STR_e STR_n STR_i STR_a STR_n "\0"
|
||||
#define STRING_Avestan0 STR_A STR_v STR_e STR_s STR_t STR_a STR_n "\0"
|
||||
#define STRING_Balinese0 STR_B STR_a STR_l STR_i STR_n STR_e STR_s STR_e "\0"
|
||||
#define STRING_Bamum0 STR_B STR_a STR_m STR_u STR_m "\0"
|
||||
#define STRING_Bassa_Vah0 STR_B STR_a STR_s STR_s STR_a STR_UNDERSCORE STR_V STR_a STR_h "\0"
|
||||
#define STRING_Batak0 STR_B STR_a STR_t STR_a STR_k "\0"
|
||||
#define STRING_Bengali0 STR_B STR_e STR_n STR_g STR_a STR_l STR_i "\0"
|
||||
#define STRING_Bopomofo0 STR_B STR_o STR_p STR_o STR_m STR_o STR_f STR_o "\0"
|
||||
#define STRING_Brahmi0 STR_B STR_r STR_a STR_h STR_m STR_i "\0"
|
||||
#define STRING_Braille0 STR_B STR_r STR_a STR_i STR_l STR_l STR_e "\0"
|
||||
#define STRING_Buginese0 STR_B STR_u STR_g STR_i STR_n STR_e STR_s STR_e "\0"
|
||||
#define STRING_Buhid0 STR_B STR_u STR_h STR_i STR_d "\0"
|
||||
#define STRING_C0 STR_C "\0"
|
||||
#define STRING_Canadian_Aboriginal0 STR_C STR_a STR_n STR_a STR_d STR_i STR_a STR_n STR_UNDERSCORE STR_A STR_b STR_o STR_r STR_i STR_g STR_i STR_n STR_a STR_l "\0"
|
||||
#define STRING_Carian0 STR_C STR_a STR_r STR_i STR_a STR_n "\0"
|
||||
#define STRING_Caucasian_Albanian0 STR_C STR_a STR_u STR_c STR_a STR_s STR_i STR_a STR_n STR_UNDERSCORE STR_A STR_l STR_b STR_a STR_n STR_i STR_a STR_n "\0"
|
||||
#define STRING_Cc0 STR_C STR_c "\0"
|
||||
#define STRING_Cf0 STR_C STR_f "\0"
|
||||
#define STRING_Chakma0 STR_C STR_h STR_a STR_k STR_m STR_a "\0"
|
||||
#define STRING_Cham0 STR_C STR_h STR_a STR_m "\0"
|
||||
#define STRING_Cherokee0 STR_C STR_h STR_e STR_r STR_o STR_k STR_e STR_e "\0"
|
||||
#define STRING_Cn0 STR_C STR_n "\0"
|
||||
#define STRING_Co0 STR_C STR_o "\0"
|
||||
#define STRING_Common0 STR_C STR_o STR_m STR_m STR_o STR_n "\0"
|
||||
#define STRING_Coptic0 STR_C STR_o STR_p STR_t STR_i STR_c "\0"
|
||||
#define STRING_Cs0 STR_C STR_s "\0"
|
||||
#define STRING_Cuneiform0 STR_C STR_u STR_n STR_e STR_i STR_f STR_o STR_r STR_m "\0"
|
||||
#define STRING_Cypriot0 STR_C STR_y STR_p STR_r STR_i STR_o STR_t "\0"
|
||||
#define STRING_Cyrillic0 STR_C STR_y STR_r STR_i STR_l STR_l STR_i STR_c "\0"
|
||||
#define STRING_Deseret0 STR_D STR_e STR_s STR_e STR_r STR_e STR_t "\0"
|
||||
#define STRING_Devanagari0 STR_D STR_e STR_v STR_a STR_n STR_a STR_g STR_a STR_r STR_i "\0"
|
||||
#define STRING_Duployan0 STR_D STR_u STR_p STR_l STR_o STR_y STR_a STR_n "\0"
|
||||
#define STRING_Egyptian_Hieroglyphs0 STR_E STR_g STR_y STR_p STR_t STR_i STR_a STR_n STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
|
||||
#define STRING_Elbasan0 STR_E STR_l STR_b STR_a STR_s STR_a STR_n "\0"
|
||||
#define STRING_Ethiopic0 STR_E STR_t STR_h STR_i STR_o STR_p STR_i STR_c "\0"
|
||||
#define STRING_Georgian0 STR_G STR_e STR_o STR_r STR_g STR_i STR_a STR_n "\0"
|
||||
#define STRING_Glagolitic0 STR_G STR_l STR_a STR_g STR_o STR_l STR_i STR_t STR_i STR_c "\0"
|
||||
#define STRING_Gothic0 STR_G STR_o STR_t STR_h STR_i STR_c "\0"
|
||||
#define STRING_Grantha0 STR_G STR_r STR_a STR_n STR_t STR_h STR_a "\0"
|
||||
#define STRING_Greek0 STR_G STR_r STR_e STR_e STR_k "\0"
|
||||
#define STRING_Gujarati0 STR_G STR_u STR_j STR_a STR_r STR_a STR_t STR_i "\0"
|
||||
#define STRING_Gurmukhi0 STR_G STR_u STR_r STR_m STR_u STR_k STR_h STR_i "\0"
|
||||
#define STRING_Han0 STR_H STR_a STR_n "\0"
|
||||
#define STRING_Hangul0 STR_H STR_a STR_n STR_g STR_u STR_l "\0"
|
||||
#define STRING_Hanunoo0 STR_H STR_a STR_n STR_u STR_n STR_o STR_o "\0"
|
||||
#define STRING_Hebrew0 STR_H STR_e STR_b STR_r STR_e STR_w "\0"
|
||||
#define STRING_Hiragana0 STR_H STR_i STR_r STR_a STR_g STR_a STR_n STR_a "\0"
|
||||
#define STRING_Imperial_Aramaic0 STR_I STR_m STR_p STR_e STR_r STR_i STR_a STR_l STR_UNDERSCORE STR_A STR_r STR_a STR_m STR_a STR_i STR_c "\0"
|
||||
#define STRING_Inherited0 STR_I STR_n STR_h STR_e STR_r STR_i STR_t STR_e STR_d "\0"
|
||||
#define STRING_Inscriptional_Pahlavi0 STR_I STR_n STR_s STR_c STR_r STR_i STR_p STR_t STR_i STR_o STR_n STR_a STR_l STR_UNDERSCORE STR_P STR_a STR_h STR_l STR_a STR_v STR_i "\0"
|
||||
#define STRING_Inscriptional_Parthian0 STR_I STR_n STR_s STR_c STR_r STR_i STR_p STR_t STR_i STR_o STR_n STR_a STR_l STR_UNDERSCORE STR_P STR_a STR_r STR_t STR_h STR_i STR_a STR_n "\0"
|
||||
#define STRING_Javanese0 STR_J STR_a STR_v STR_a STR_n STR_e STR_s STR_e "\0"
|
||||
#define STRING_Kaithi0 STR_K STR_a STR_i STR_t STR_h STR_i "\0"
|
||||
#define STRING_Kannada0 STR_K STR_a STR_n STR_n STR_a STR_d STR_a "\0"
|
||||
#define STRING_Katakana0 STR_K STR_a STR_t STR_a STR_k STR_a STR_n STR_a "\0"
|
||||
#define STRING_Kayah_Li0 STR_K STR_a STR_y STR_a STR_h STR_UNDERSCORE STR_L STR_i "\0"
|
||||
#define STRING_Kharoshthi0 STR_K STR_h STR_a STR_r STR_o STR_s STR_h STR_t STR_h STR_i "\0"
|
||||
#define STRING_Khmer0 STR_K STR_h STR_m STR_e STR_r "\0"
|
||||
#define STRING_Khojki0 STR_K STR_h STR_o STR_j STR_k STR_i "\0"
|
||||
#define STRING_Khudawadi0 STR_K STR_h STR_u STR_d STR_a STR_w STR_a STR_d STR_i "\0"
|
||||
#define STRING_L0 STR_L "\0"
|
||||
#define STRING_L_AMPERSAND0 STR_L STR_AMPERSAND "\0"
|
||||
#define STRING_Lao0 STR_L STR_a STR_o "\0"
|
||||
#define STRING_Latin0 STR_L STR_a STR_t STR_i STR_n "\0"
|
||||
#define STRING_Lepcha0 STR_L STR_e STR_p STR_c STR_h STR_a "\0"
|
||||
#define STRING_Limbu0 STR_L STR_i STR_m STR_b STR_u "\0"
|
||||
#define STRING_Linear_A0 STR_L STR_i STR_n STR_e STR_a STR_r STR_UNDERSCORE STR_A "\0"
|
||||
#define STRING_Linear_B0 STR_L STR_i STR_n STR_e STR_a STR_r STR_UNDERSCORE STR_B "\0"
|
||||
#define STRING_Lisu0 STR_L STR_i STR_s STR_u "\0"
|
||||
#define STRING_Ll0 STR_L STR_l "\0"
|
||||
#define STRING_Lm0 STR_L STR_m "\0"
|
||||
#define STRING_Lo0 STR_L STR_o "\0"
|
||||
#define STRING_Lt0 STR_L STR_t "\0"
|
||||
#define STRING_Lu0 STR_L STR_u "\0"
|
||||
#define STRING_Lycian0 STR_L STR_y STR_c STR_i STR_a STR_n "\0"
|
||||
#define STRING_Lydian0 STR_L STR_y STR_d STR_i STR_a STR_n "\0"
|
||||
#define STRING_M0 STR_M "\0"
|
||||
#define STRING_Mahajani0 STR_M STR_a STR_h STR_a STR_j STR_a STR_n STR_i "\0"
|
||||
#define STRING_Malayalam0 STR_M STR_a STR_l STR_a STR_y STR_a STR_l STR_a STR_m "\0"
|
||||
#define STRING_Mandaic0 STR_M STR_a STR_n STR_d STR_a STR_i STR_c "\0"
|
||||
#define STRING_Manichaean0 STR_M STR_a STR_n STR_i STR_c STR_h STR_a STR_e STR_a STR_n "\0"
|
||||
#define STRING_Mc0 STR_M STR_c "\0"
|
||||
#define STRING_Me0 STR_M STR_e "\0"
|
||||
#define STRING_Meetei_Mayek0 STR_M STR_e STR_e STR_t STR_e STR_i STR_UNDERSCORE STR_M STR_a STR_y STR_e STR_k "\0"
|
||||
#define STRING_Mende_Kikakui0 STR_M STR_e STR_n STR_d STR_e STR_UNDERSCORE STR_K STR_i STR_k STR_a STR_k STR_u STR_i "\0"
|
||||
#define STRING_Meroitic_Cursive0 STR_M STR_e STR_r STR_o STR_i STR_t STR_i STR_c STR_UNDERSCORE STR_C STR_u STR_r STR_s STR_i STR_v STR_e "\0"
|
||||
#define STRING_Meroitic_Hieroglyphs0 STR_M STR_e STR_r STR_o STR_i STR_t STR_i STR_c STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
|
||||
#define STRING_Miao0 STR_M STR_i STR_a STR_o "\0"
|
||||
#define STRING_Mn0 STR_M STR_n "\0"
|
||||
#define STRING_Modi0 STR_M STR_o STR_d STR_i "\0"
|
||||
#define STRING_Mongolian0 STR_M STR_o STR_n STR_g STR_o STR_l STR_i STR_a STR_n "\0"
|
||||
#define STRING_Mro0 STR_M STR_r STR_o "\0"
|
||||
#define STRING_Myanmar0 STR_M STR_y STR_a STR_n STR_m STR_a STR_r "\0"
|
||||
#define STRING_N0 STR_N "\0"
|
||||
#define STRING_Nabataean0 STR_N STR_a STR_b STR_a STR_t STR_a STR_e STR_a STR_n "\0"
|
||||
#define STRING_Nd0 STR_N STR_d "\0"
|
||||
#define STRING_New_Tai_Lue0 STR_N STR_e STR_w STR_UNDERSCORE STR_T STR_a STR_i STR_UNDERSCORE STR_L STR_u STR_e "\0"
|
||||
#define STRING_Nko0 STR_N STR_k STR_o "\0"
|
||||
#define STRING_Nl0 STR_N STR_l "\0"
|
||||
#define STRING_No0 STR_N STR_o "\0"
|
||||
#define STRING_Ogham0 STR_O STR_g STR_h STR_a STR_m "\0"
|
||||
#define STRING_Ol_Chiki0 STR_O STR_l STR_UNDERSCORE STR_C STR_h STR_i STR_k STR_i "\0"
|
||||
#define STRING_Old_Italic0 STR_O STR_l STR_d STR_UNDERSCORE STR_I STR_t STR_a STR_l STR_i STR_c "\0"
|
||||
#define STRING_Old_North_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_N STR_o STR_r STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
|
||||
#define STRING_Old_Permic0 STR_O STR_l STR_d STR_UNDERSCORE STR_P STR_e STR_r STR_m STR_i STR_c "\0"
|
||||
#define STRING_Old_Persian0 STR_O STR_l STR_d STR_UNDERSCORE STR_P STR_e STR_r STR_s STR_i STR_a STR_n "\0"
|
||||
#define STRING_Old_South_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_u STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
|
||||
#define STRING_Old_Turkic0 STR_O STR_l STR_d STR_UNDERSCORE STR_T STR_u STR_r STR_k STR_i STR_c "\0"
|
||||
#define STRING_Oriya0 STR_O STR_r STR_i STR_y STR_a "\0"
|
||||
#define STRING_Osmanya0 STR_O STR_s STR_m STR_a STR_n STR_y STR_a "\0"
|
||||
#define STRING_P0 STR_P "\0"
|
||||
#define STRING_Pahawh_Hmong0 STR_P STR_a STR_h STR_a STR_w STR_h STR_UNDERSCORE STR_H STR_m STR_o STR_n STR_g "\0"
|
||||
#define STRING_Palmyrene0 STR_P STR_a STR_l STR_m STR_y STR_r STR_e STR_n STR_e "\0"
|
||||
#define STRING_Pau_Cin_Hau0 STR_P STR_a STR_u STR_UNDERSCORE STR_C STR_i STR_n STR_UNDERSCORE STR_H STR_a STR_u "\0"
|
||||
#define STRING_Pc0 STR_P STR_c "\0"
|
||||
#define STRING_Pd0 STR_P STR_d "\0"
|
||||
#define STRING_Pe0 STR_P STR_e "\0"
|
||||
#define STRING_Pf0 STR_P STR_f "\0"
|
||||
#define STRING_Phags_Pa0 STR_P STR_h STR_a STR_g STR_s STR_UNDERSCORE STR_P STR_a "\0"
|
||||
#define STRING_Phoenician0 STR_P STR_h STR_o STR_e STR_n STR_i STR_c STR_i STR_a STR_n "\0"
|
||||
#define STRING_Pi0 STR_P STR_i "\0"
|
||||
#define STRING_Po0 STR_P STR_o "\0"
|
||||
#define STRING_Ps0 STR_P STR_s "\0"
|
||||
#define STRING_Psalter_Pahlavi0 STR_P STR_s STR_a STR_l STR_t STR_e STR_r STR_UNDERSCORE STR_P STR_a STR_h STR_l STR_a STR_v STR_i "\0"
|
||||
#define STRING_Rejang0 STR_R STR_e STR_j STR_a STR_n STR_g "\0"
|
||||
#define STRING_Runic0 STR_R STR_u STR_n STR_i STR_c "\0"
|
||||
#define STRING_S0 STR_S "\0"
|
||||
#define STRING_Samaritan0 STR_S STR_a STR_m STR_a STR_r STR_i STR_t STR_a STR_n "\0"
|
||||
#define STRING_Saurashtra0 STR_S STR_a STR_u STR_r STR_a STR_s STR_h STR_t STR_r STR_a "\0"
|
||||
#define STRING_Sc0 STR_S STR_c "\0"
|
||||
#define STRING_Sharada0 STR_S STR_h STR_a STR_r STR_a STR_d STR_a "\0"
|
||||
#define STRING_Shavian0 STR_S STR_h STR_a STR_v STR_i STR_a STR_n "\0"
|
||||
#define STRING_Siddham0 STR_S STR_i STR_d STR_d STR_h STR_a STR_m "\0"
|
||||
#define STRING_Sinhala0 STR_S STR_i STR_n STR_h STR_a STR_l STR_a "\0"
|
||||
#define STRING_Sk0 STR_S STR_k "\0"
|
||||
#define STRING_Sm0 STR_S STR_m "\0"
|
||||
#define STRING_So0 STR_S STR_o "\0"
|
||||
#define STRING_Sora_Sompeng0 STR_S STR_o STR_r STR_a STR_UNDERSCORE STR_S STR_o STR_m STR_p STR_e STR_n STR_g "\0"
|
||||
#define STRING_Sundanese0 STR_S STR_u STR_n STR_d STR_a STR_n STR_e STR_s STR_e "\0"
|
||||
#define STRING_Syloti_Nagri0 STR_S STR_y STR_l STR_o STR_t STR_i STR_UNDERSCORE STR_N STR_a STR_g STR_r STR_i "\0"
|
||||
#define STRING_Syriac0 STR_S STR_y STR_r STR_i STR_a STR_c "\0"
|
||||
#define STRING_Tagalog0 STR_T STR_a STR_g STR_a STR_l STR_o STR_g "\0"
|
||||
#define STRING_Tagbanwa0 STR_T STR_a STR_g STR_b STR_a STR_n STR_w STR_a "\0"
|
||||
#define STRING_Tai_Le0 STR_T STR_a STR_i STR_UNDERSCORE STR_L STR_e "\0"
|
||||
#define STRING_Tai_Tham0 STR_T STR_a STR_i STR_UNDERSCORE STR_T STR_h STR_a STR_m "\0"
|
||||
#define STRING_Tai_Viet0 STR_T STR_a STR_i STR_UNDERSCORE STR_V STR_i STR_e STR_t "\0"
|
||||
#define STRING_Takri0 STR_T STR_a STR_k STR_r STR_i "\0"
|
||||
#define STRING_Tamil0 STR_T STR_a STR_m STR_i STR_l "\0"
|
||||
#define STRING_Telugu0 STR_T STR_e STR_l STR_u STR_g STR_u "\0"
|
||||
#define STRING_Thaana0 STR_T STR_h STR_a STR_a STR_n STR_a "\0"
|
||||
#define STRING_Thai0 STR_T STR_h STR_a STR_i "\0"
|
||||
#define STRING_Tibetan0 STR_T STR_i STR_b STR_e STR_t STR_a STR_n "\0"
|
||||
#define STRING_Tifinagh0 STR_T STR_i STR_f STR_i STR_n STR_a STR_g STR_h "\0"
|
||||
#define STRING_Tirhuta0 STR_T STR_i STR_r STR_h STR_u STR_t STR_a "\0"
|
||||
#define STRING_Ugaritic0 STR_U STR_g STR_a STR_r STR_i STR_t STR_i STR_c "\0"
|
||||
#define STRING_Vai0 STR_V STR_a STR_i "\0"
|
||||
#define STRING_Warang_Citi0 STR_W STR_a STR_r STR_a STR_n STR_g STR_UNDERSCORE STR_C STR_i STR_t STR_i "\0"
|
||||
#define STRING_Xan0 STR_X STR_a STR_n "\0"
|
||||
#define STRING_Xps0 STR_X STR_p STR_s "\0"
|
||||
#define STRING_Xsp0 STR_X STR_s STR_p "\0"
|
||||
#define STRING_Xuc0 STR_X STR_u STR_c "\0"
|
||||
#define STRING_Xwd0 STR_X STR_w STR_d "\0"
|
||||
#define STRING_Yi0 STR_Y STR_i "\0"
|
||||
#define STRING_Z0 STR_Z "\0"
|
||||
#define STRING_Zl0 STR_Z STR_l "\0"
|
||||
#define STRING_Zp0 STR_Z STR_p "\0"
|
||||
#define STRING_Zs0 STR_Z STR_s "\0"
|
||||
|
||||
const char PRIV(utt_names)[] =
|
||||
STRING_Any0
|
||||
STRING_Arabic0
|
||||
STRING_Armenian0
|
||||
STRING_Avestan0
|
||||
STRING_Balinese0
|
||||
STRING_Bamum0
|
||||
STRING_Bassa_Vah0
|
||||
STRING_Batak0
|
||||
STRING_Bengali0
|
||||
STRING_Bopomofo0
|
||||
STRING_Brahmi0
|
||||
STRING_Braille0
|
||||
STRING_Buginese0
|
||||
STRING_Buhid0
|
||||
STRING_C0
|
||||
STRING_Canadian_Aboriginal0
|
||||
STRING_Carian0
|
||||
STRING_Caucasian_Albanian0
|
||||
STRING_Cc0
|
||||
STRING_Cf0
|
||||
STRING_Chakma0
|
||||
STRING_Cham0
|
||||
STRING_Cherokee0
|
||||
STRING_Cn0
|
||||
STRING_Co0
|
||||
STRING_Common0
|
||||
STRING_Coptic0
|
||||
STRING_Cs0
|
||||
STRING_Cuneiform0
|
||||
STRING_Cypriot0
|
||||
STRING_Cyrillic0
|
||||
STRING_Deseret0
|
||||
STRING_Devanagari0
|
||||
STRING_Duployan0
|
||||
STRING_Egyptian_Hieroglyphs0
|
||||
STRING_Elbasan0
|
||||
STRING_Ethiopic0
|
||||
STRING_Georgian0
|
||||
STRING_Glagolitic0
|
||||
STRING_Gothic0
|
||||
STRING_Grantha0
|
||||
STRING_Greek0
|
||||
STRING_Gujarati0
|
||||
STRING_Gurmukhi0
|
||||
STRING_Han0
|
||||
STRING_Hangul0
|
||||
STRING_Hanunoo0
|
||||
STRING_Hebrew0
|
||||
STRING_Hiragana0
|
||||
STRING_Imperial_Aramaic0
|
||||
STRING_Inherited0
|
||||
STRING_Inscriptional_Pahlavi0
|
||||
STRING_Inscriptional_Parthian0
|
||||
STRING_Javanese0
|
||||
STRING_Kaithi0
|
||||
STRING_Kannada0
|
||||
STRING_Katakana0
|
||||
STRING_Kayah_Li0
|
||||
STRING_Kharoshthi0
|
||||
STRING_Khmer0
|
||||
STRING_Khojki0
|
||||
STRING_Khudawadi0
|
||||
STRING_L0
|
||||
STRING_L_AMPERSAND0
|
||||
STRING_Lao0
|
||||
STRING_Latin0
|
||||
STRING_Lepcha0
|
||||
STRING_Limbu0
|
||||
STRING_Linear_A0
|
||||
STRING_Linear_B0
|
||||
STRING_Lisu0
|
||||
STRING_Ll0
|
||||
STRING_Lm0
|
||||
STRING_Lo0
|
||||
STRING_Lt0
|
||||
STRING_Lu0
|
||||
STRING_Lycian0
|
||||
STRING_Lydian0
|
||||
STRING_M0
|
||||
STRING_Mahajani0
|
||||
STRING_Malayalam0
|
||||
STRING_Mandaic0
|
||||
STRING_Manichaean0
|
||||
STRING_Mc0
|
||||
STRING_Me0
|
||||
STRING_Meetei_Mayek0
|
||||
STRING_Mende_Kikakui0
|
||||
STRING_Meroitic_Cursive0
|
||||
STRING_Meroitic_Hieroglyphs0
|
||||
STRING_Miao0
|
||||
STRING_Mn0
|
||||
STRING_Modi0
|
||||
STRING_Mongolian0
|
||||
STRING_Mro0
|
||||
STRING_Myanmar0
|
||||
STRING_N0
|
||||
STRING_Nabataean0
|
||||
STRING_Nd0
|
||||
STRING_New_Tai_Lue0
|
||||
STRING_Nko0
|
||||
STRING_Nl0
|
||||
STRING_No0
|
||||
STRING_Ogham0
|
||||
STRING_Ol_Chiki0
|
||||
STRING_Old_Italic0
|
||||
STRING_Old_North_Arabian0
|
||||
STRING_Old_Permic0
|
||||
STRING_Old_Persian0
|
||||
STRING_Old_South_Arabian0
|
||||
STRING_Old_Turkic0
|
||||
STRING_Oriya0
|
||||
STRING_Osmanya0
|
||||
STRING_P0
|
||||
STRING_Pahawh_Hmong0
|
||||
STRING_Palmyrene0
|
||||
STRING_Pau_Cin_Hau0
|
||||
STRING_Pc0
|
||||
STRING_Pd0
|
||||
STRING_Pe0
|
||||
STRING_Pf0
|
||||
STRING_Phags_Pa0
|
||||
STRING_Phoenician0
|
||||
STRING_Pi0
|
||||
STRING_Po0
|
||||
STRING_Ps0
|
||||
STRING_Psalter_Pahlavi0
|
||||
STRING_Rejang0
|
||||
STRING_Runic0
|
||||
STRING_S0
|
||||
STRING_Samaritan0
|
||||
STRING_Saurashtra0
|
||||
STRING_Sc0
|
||||
STRING_Sharada0
|
||||
STRING_Shavian0
|
||||
STRING_Siddham0
|
||||
STRING_Sinhala0
|
||||
STRING_Sk0
|
||||
STRING_Sm0
|
||||
STRING_So0
|
||||
STRING_Sora_Sompeng0
|
||||
STRING_Sundanese0
|
||||
STRING_Syloti_Nagri0
|
||||
STRING_Syriac0
|
||||
STRING_Tagalog0
|
||||
STRING_Tagbanwa0
|
||||
STRING_Tai_Le0
|
||||
STRING_Tai_Tham0
|
||||
STRING_Tai_Viet0
|
||||
STRING_Takri0
|
||||
STRING_Tamil0
|
||||
STRING_Telugu0
|
||||
STRING_Thaana0
|
||||
STRING_Thai0
|
||||
STRING_Tibetan0
|
||||
STRING_Tifinagh0
|
||||
STRING_Tirhuta0
|
||||
STRING_Ugaritic0
|
||||
STRING_Vai0
|
||||
STRING_Warang_Citi0
|
||||
STRING_Xan0
|
||||
STRING_Xps0
|
||||
STRING_Xsp0
|
||||
STRING_Xuc0
|
||||
STRING_Xwd0
|
||||
STRING_Yi0
|
||||
STRING_Z0
|
||||
STRING_Zl0
|
||||
STRING_Zp0
|
||||
STRING_Zs0;
|
||||
|
||||
const ucp_type_table PRIV(utt)[] = {
|
||||
{ 0, PT_ANY, 0 },
|
||||
{ 4, PT_SC, ucp_Arabic },
|
||||
{ 11, PT_SC, ucp_Armenian },
|
||||
{ 20, PT_SC, ucp_Avestan },
|
||||
{ 28, PT_SC, ucp_Balinese },
|
||||
{ 37, PT_SC, ucp_Bamum },
|
||||
{ 43, PT_SC, ucp_Bassa_Vah },
|
||||
{ 53, PT_SC, ucp_Batak },
|
||||
{ 59, PT_SC, ucp_Bengali },
|
||||
{ 67, PT_SC, ucp_Bopomofo },
|
||||
{ 76, PT_SC, ucp_Brahmi },
|
||||
{ 83, PT_SC, ucp_Braille },
|
||||
{ 91, PT_SC, ucp_Buginese },
|
||||
{ 100, PT_SC, ucp_Buhid },
|
||||
{ 106, PT_GC, ucp_C },
|
||||
{ 108, PT_SC, ucp_Canadian_Aboriginal },
|
||||
{ 128, PT_SC, ucp_Carian },
|
||||
{ 135, PT_SC, ucp_Caucasian_Albanian },
|
||||
{ 154, PT_PC, ucp_Cc },
|
||||
{ 157, PT_PC, ucp_Cf },
|
||||
{ 160, PT_SC, ucp_Chakma },
|
||||
{ 167, PT_SC, ucp_Cham },
|
||||
{ 172, PT_SC, ucp_Cherokee },
|
||||
{ 181, PT_PC, ucp_Cn },
|
||||
{ 184, PT_PC, ucp_Co },
|
||||
{ 187, PT_SC, ucp_Common },
|
||||
{ 194, PT_SC, ucp_Coptic },
|
||||
{ 201, PT_PC, ucp_Cs },
|
||||
{ 204, PT_SC, ucp_Cuneiform },
|
||||
{ 214, PT_SC, ucp_Cypriot },
|
||||
{ 222, PT_SC, ucp_Cyrillic },
|
||||
{ 231, PT_SC, ucp_Deseret },
|
||||
{ 239, PT_SC, ucp_Devanagari },
|
||||
{ 250, PT_SC, ucp_Duployan },
|
||||
{ 259, PT_SC, ucp_Egyptian_Hieroglyphs },
|
||||
{ 280, PT_SC, ucp_Elbasan },
|
||||
{ 288, PT_SC, ucp_Ethiopic },
|
||||
{ 297, PT_SC, ucp_Georgian },
|
||||
{ 306, PT_SC, ucp_Glagolitic },
|
||||
{ 317, PT_SC, ucp_Gothic },
|
||||
{ 324, PT_SC, ucp_Grantha },
|
||||
{ 332, PT_SC, ucp_Greek },
|
||||
{ 338, PT_SC, ucp_Gujarati },
|
||||
{ 347, PT_SC, ucp_Gurmukhi },
|
||||
{ 356, PT_SC, ucp_Han },
|
||||
{ 360, PT_SC, ucp_Hangul },
|
||||
{ 367, PT_SC, ucp_Hanunoo },
|
||||
{ 375, PT_SC, ucp_Hebrew },
|
||||
{ 382, PT_SC, ucp_Hiragana },
|
||||
{ 391, PT_SC, ucp_Imperial_Aramaic },
|
||||
{ 408, PT_SC, ucp_Inherited },
|
||||
{ 418, PT_SC, ucp_Inscriptional_Pahlavi },
|
||||
{ 440, PT_SC, ucp_Inscriptional_Parthian },
|
||||
{ 463, PT_SC, ucp_Javanese },
|
||||
{ 472, PT_SC, ucp_Kaithi },
|
||||
{ 479, PT_SC, ucp_Kannada },
|
||||
{ 487, PT_SC, ucp_Katakana },
|
||||
{ 496, PT_SC, ucp_Kayah_Li },
|
||||
{ 505, PT_SC, ucp_Kharoshthi },
|
||||
{ 516, PT_SC, ucp_Khmer },
|
||||
{ 522, PT_SC, ucp_Khojki },
|
||||
{ 529, PT_SC, ucp_Khudawadi },
|
||||
{ 539, PT_GC, ucp_L },
|
||||
{ 541, PT_LAMP, 0 },
|
||||
{ 544, PT_SC, ucp_Lao },
|
||||
{ 548, PT_SC, ucp_Latin },
|
||||
{ 554, PT_SC, ucp_Lepcha },
|
||||
{ 561, PT_SC, ucp_Limbu },
|
||||
{ 567, PT_SC, ucp_Linear_A },
|
||||
{ 576, PT_SC, ucp_Linear_B },
|
||||
{ 585, PT_SC, ucp_Lisu },
|
||||
{ 590, PT_PC, ucp_Ll },
|
||||
{ 593, PT_PC, ucp_Lm },
|
||||
{ 596, PT_PC, ucp_Lo },
|
||||
{ 599, PT_PC, ucp_Lt },
|
||||
{ 602, PT_PC, ucp_Lu },
|
||||
{ 605, PT_SC, ucp_Lycian },
|
||||
{ 612, PT_SC, ucp_Lydian },
|
||||
{ 619, PT_GC, ucp_M },
|
||||
{ 621, PT_SC, ucp_Mahajani },
|
||||
{ 630, PT_SC, ucp_Malayalam },
|
||||
{ 640, PT_SC, ucp_Mandaic },
|
||||
{ 648, PT_SC, ucp_Manichaean },
|
||||
{ 659, PT_PC, ucp_Mc },
|
||||
{ 662, PT_PC, ucp_Me },
|
||||
{ 665, PT_SC, ucp_Meetei_Mayek },
|
||||
{ 678, PT_SC, ucp_Mende_Kikakui },
|
||||
{ 692, PT_SC, ucp_Meroitic_Cursive },
|
||||
{ 709, PT_SC, ucp_Meroitic_Hieroglyphs },
|
||||
{ 730, PT_SC, ucp_Miao },
|
||||
{ 735, PT_PC, ucp_Mn },
|
||||
{ 738, PT_SC, ucp_Modi },
|
||||
{ 743, PT_SC, ucp_Mongolian },
|
||||
{ 753, PT_SC, ucp_Mro },
|
||||
{ 757, PT_SC, ucp_Myanmar },
|
||||
{ 765, PT_GC, ucp_N },
|
||||
{ 767, PT_SC, ucp_Nabataean },
|
||||
{ 777, PT_PC, ucp_Nd },
|
||||
{ 780, PT_SC, ucp_New_Tai_Lue },
|
||||
{ 792, PT_SC, ucp_Nko },
|
||||
{ 796, PT_PC, ucp_Nl },
|
||||
{ 799, PT_PC, ucp_No },
|
||||
{ 802, PT_SC, ucp_Ogham },
|
||||
{ 808, PT_SC, ucp_Ol_Chiki },
|
||||
{ 817, PT_SC, ucp_Old_Italic },
|
||||
{ 828, PT_SC, ucp_Old_North_Arabian },
|
||||
{ 846, PT_SC, ucp_Old_Permic },
|
||||
{ 857, PT_SC, ucp_Old_Persian },
|
||||
{ 869, PT_SC, ucp_Old_South_Arabian },
|
||||
{ 887, PT_SC, ucp_Old_Turkic },
|
||||
{ 898, PT_SC, ucp_Oriya },
|
||||
{ 904, PT_SC, ucp_Osmanya },
|
||||
{ 912, PT_GC, ucp_P },
|
||||
{ 914, PT_SC, ucp_Pahawh_Hmong },
|
||||
{ 927, PT_SC, ucp_Palmyrene },
|
||||
{ 937, PT_SC, ucp_Pau_Cin_Hau },
|
||||
{ 949, PT_PC, ucp_Pc },
|
||||
{ 952, PT_PC, ucp_Pd },
|
||||
{ 955, PT_PC, ucp_Pe },
|
||||
{ 958, PT_PC, ucp_Pf },
|
||||
{ 961, PT_SC, ucp_Phags_Pa },
|
||||
{ 970, PT_SC, ucp_Phoenician },
|
||||
{ 981, PT_PC, ucp_Pi },
|
||||
{ 984, PT_PC, ucp_Po },
|
||||
{ 987, PT_PC, ucp_Ps },
|
||||
{ 990, PT_SC, ucp_Psalter_Pahlavi },
|
||||
{ 1006, PT_SC, ucp_Rejang },
|
||||
{ 1013, PT_SC, ucp_Runic },
|
||||
{ 1019, PT_GC, ucp_S },
|
||||
{ 1021, PT_SC, ucp_Samaritan },
|
||||
{ 1031, PT_SC, ucp_Saurashtra },
|
||||
{ 1042, PT_PC, ucp_Sc },
|
||||
{ 1045, PT_SC, ucp_Sharada },
|
||||
{ 1053, PT_SC, ucp_Shavian },
|
||||
{ 1061, PT_SC, ucp_Siddham },
|
||||
{ 1069, PT_SC, ucp_Sinhala },
|
||||
{ 1077, PT_PC, ucp_Sk },
|
||||
{ 1080, PT_PC, ucp_Sm },
|
||||
{ 1083, PT_PC, ucp_So },
|
||||
{ 1086, PT_SC, ucp_Sora_Sompeng },
|
||||
{ 1099, PT_SC, ucp_Sundanese },
|
||||
{ 1109, PT_SC, ucp_Syloti_Nagri },
|
||||
{ 1122, PT_SC, ucp_Syriac },
|
||||
{ 1129, PT_SC, ucp_Tagalog },
|
||||
{ 1137, PT_SC, ucp_Tagbanwa },
|
||||
{ 1146, PT_SC, ucp_Tai_Le },
|
||||
{ 1153, PT_SC, ucp_Tai_Tham },
|
||||
{ 1162, PT_SC, ucp_Tai_Viet },
|
||||
{ 1171, PT_SC, ucp_Takri },
|
||||
{ 1177, PT_SC, ucp_Tamil },
|
||||
{ 1183, PT_SC, ucp_Telugu },
|
||||
{ 1190, PT_SC, ucp_Thaana },
|
||||
{ 1197, PT_SC, ucp_Thai },
|
||||
{ 1202, PT_SC, ucp_Tibetan },
|
||||
{ 1210, PT_SC, ucp_Tifinagh },
|
||||
{ 1219, PT_SC, ucp_Tirhuta },
|
||||
{ 1227, PT_SC, ucp_Ugaritic },
|
||||
{ 1236, PT_SC, ucp_Vai },
|
||||
{ 1240, PT_SC, ucp_Warang_Citi },
|
||||
{ 1252, PT_ALNUM, 0 },
|
||||
{ 1256, PT_PXSPACE, 0 },
|
||||
{ 1260, PT_SPACE, 0 },
|
||||
{ 1264, PT_UCNC, 0 },
|
||||
{ 1268, PT_WORD, 0 },
|
||||
{ 1272, PT_SC, ucp_Yi },
|
||||
{ 1275, PT_GC, ucp_Z },
|
||||
{ 1277, PT_PC, ucp_Zl },
|
||||
{ 1280, PT_PC, ucp_Zp },
|
||||
{ 1283, PT_PC, ucp_Zs }
|
||||
};
|
||||
|
||||
const int PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
|
||||
|
||||
#endif /* SUPPORT_UTF */
|
||||
|
||||
/* End of pcre_tables.c */
|
||||
+358
@@ -0,0 +1,358 @@
|
||||
// Copyright (C) 2011 Florian Weimer <fw@deneb.enyo.de>
|
||||
|
||||
package pcre
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompile(t *testing.T) {
|
||||
var check = func(p string, groups int) {
|
||||
re, err := Compile(p, 0)
|
||||
if err != nil {
|
||||
t.Error(p, err)
|
||||
}
|
||||
if g := re.Groups(); g != groups {
|
||||
t.Error(p, g)
|
||||
}
|
||||
}
|
||||
check("", 0)
|
||||
check("^", 0)
|
||||
check("^$", 0)
|
||||
check("()", 1)
|
||||
check("(())", 2)
|
||||
check("((?:))", 1)
|
||||
}
|
||||
|
||||
func TestCompileFail(t *testing.T) {
|
||||
var check = func(p, msg string, off int) {
|
||||
_, err := Compile(p, 0)
|
||||
if err == nil {
|
||||
t.Error(p)
|
||||
} else {
|
||||
cerr := err.(*CompileError)
|
||||
switch {
|
||||
case cerr.Message != msg:
|
||||
t.Error(p, "Message", cerr.Message)
|
||||
case cerr.Offset != off:
|
||||
t.Error(p, "Offset", cerr.Offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
check("(", "missing )", 1)
|
||||
check("\\", "\\ at end of pattern", 1)
|
||||
check("abc\\", "\\ at end of pattern", 4)
|
||||
check("abc\000", "NUL byte in pattern", 3)
|
||||
check("a\000bc", "NUL byte in pattern", 1)
|
||||
}
|
||||
|
||||
func strings(b [][]byte) (r []string) {
|
||||
r = make([]string, len(b))
|
||||
for i, v := range b {
|
||||
r[i] = string(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func equal(l, r []string) bool {
|
||||
if len(l) != len(r) {
|
||||
return false
|
||||
}
|
||||
for i, lv := range l {
|
||||
if lv != r[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkmatch1(t *testing.T, dostring bool, m *Matcher,
|
||||
pattern, subject string, args ...interface{}) {
|
||||
re := MustCompile(pattern, 0)
|
||||
var prefix string
|
||||
if dostring {
|
||||
if m == nil {
|
||||
m = re.MatcherString(subject, 0)
|
||||
} else {
|
||||
m.ResetString(re, subject, 0)
|
||||
}
|
||||
prefix = "string"
|
||||
} else {
|
||||
if m == nil {
|
||||
m = re.Matcher([]byte(subject), 0)
|
||||
} else {
|
||||
m.Reset(re, []byte(subject), 0)
|
||||
}
|
||||
prefix = "[]byte"
|
||||
}
|
||||
if len(args) == 0 {
|
||||
if m.Matches() {
|
||||
t.Error(prefix, pattern, subject, "!Matches")
|
||||
}
|
||||
} else {
|
||||
if !m.Matches() {
|
||||
t.Error(prefix, pattern, subject, "Matches")
|
||||
return
|
||||
}
|
||||
if m.Groups() != len(args)-1 {
|
||||
t.Error(prefix, pattern, subject, "Groups", m.Groups())
|
||||
return
|
||||
}
|
||||
for i, arg := range args {
|
||||
if s, ok := arg.(string); ok {
|
||||
if !m.Present(i) {
|
||||
t.Error(prefix, pattern, subject,
|
||||
"Present", i)
|
||||
|
||||
}
|
||||
if g := string(m.Group(i)); g != s {
|
||||
t.Error(prefix, pattern, subject,
|
||||
"Group", i, g, "!=", s)
|
||||
}
|
||||
if g := m.GroupString(i); g != s {
|
||||
t.Error(prefix, pattern, subject,
|
||||
"GroupString", i, g, "!=", s)
|
||||
}
|
||||
} else {
|
||||
if m.Present(i) {
|
||||
t.Error(prefix, pattern, subject,
|
||||
"!Present", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatcher(t *testing.T) {
|
||||
var m Matcher
|
||||
check := func(pattern, subject string, args ...interface{}) {
|
||||
checkmatch1(t, false, nil, pattern, subject, args...)
|
||||
checkmatch1(t, true, nil, pattern, subject, args...)
|
||||
checkmatch1(t, false, &m, pattern, subject, args...)
|
||||
checkmatch1(t, true, &m, pattern, subject, args...)
|
||||
}
|
||||
|
||||
check(`^$`, "", "")
|
||||
check(`^abc$`, "abc", "abc")
|
||||
check(`^(X)*ab(c)$`, "abc", "abc", nil, "c")
|
||||
check(`^(X)*ab()c$`, "abc", "abc", nil, "")
|
||||
check(`^.*$`, "abc", "abc")
|
||||
check(`^.*$`, "a\000c", "a\000c")
|
||||
check(`^(.*)$`, "a\000c", "a\000c", "a\000c")
|
||||
check(`def`, "abcdefghi", "def")
|
||||
}
|
||||
|
||||
func TestPartial(t *testing.T) {
|
||||
re := MustCompile(`^abc`, 0)
|
||||
defer re.FreeRegexp()
|
||||
// Check we get a partial match when we should
|
||||
m := re.MatcherString("ab", PARTIAL_SOFT)
|
||||
if !m.Matches() {
|
||||
t.Error("Failed to find any matches")
|
||||
} else if !m.Partial() {
|
||||
t.Error("The match was not partial")
|
||||
}
|
||||
|
||||
// Check we get an exact match when we should
|
||||
m = re.MatcherString("abc", PARTIAL_SOFT)
|
||||
if !m.Matches() {
|
||||
t.Error("Failed to find any matches")
|
||||
} else if m.Partial() {
|
||||
t.Error("Match was partial but should have been exact")
|
||||
}
|
||||
|
||||
m = re.Matcher([]byte("ab"), PARTIAL_SOFT)
|
||||
if !m.Matches() {
|
||||
t.Error("Failed to find any matches")
|
||||
} else if !m.Partial() {
|
||||
t.Error("The match was not partial")
|
||||
}
|
||||
|
||||
m = re.Matcher([]byte("abc"), PARTIAL_SOFT)
|
||||
if !m.Matches() {
|
||||
t.Error("Failed to find any matches")
|
||||
} else if m.Partial() {
|
||||
t.Error("Match was partial but should have been exact")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCaseless(t *testing.T) {
|
||||
re := MustCompile("abc", CASELESS)
|
||||
defer re.FreeRegexp()
|
||||
m := re.MatcherString("...Abc...", 0)
|
||||
if !m.Matches() {
|
||||
t.Error("CASELESS")
|
||||
}
|
||||
re2 := MustCompile("abc", 0)
|
||||
defer re2.FreeRegexp()
|
||||
m = re2.MatcherString("Abc", 0)
|
||||
if m.Matches() {
|
||||
t.Error("!CASELESS")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamed(t *testing.T) {
|
||||
pattern := "(?<L>a)(?<M>X)*bc(?<DIGITS>\\d*)"
|
||||
re := MustCompile(pattern, 0)
|
||||
defer re.FreeRegexp()
|
||||
m := re.MatcherString("abc12", 0)
|
||||
if !m.Matches() {
|
||||
t.Error("Matches")
|
||||
}
|
||||
if ok, err := m.NamedPresent("L"); !ok || err != nil {
|
||||
t.Errorf("NamedPresent(\"L\"): %v", err)
|
||||
}
|
||||
if ok, err := m.NamedPresent("M"); ok || err != nil {
|
||||
t.Errorf("NamedPresent(\"M\"): %v", err)
|
||||
}
|
||||
if ok, err := m.NamedPresent("DIGITS"); !ok || err != nil {
|
||||
t.Errorf("NamedPresent(\"DIGITS\"): %v", err)
|
||||
}
|
||||
if str, err := m.NamedString("DIGITS"); str != "12" || err != nil {
|
||||
t.Errorf("NamedString(\"DIGITS\"): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatcherIndex(t *testing.T) {
|
||||
re := MustCompile("bcd", 0)
|
||||
defer re.FreeRegexp()
|
||||
m := re.Matcher([]byte("abcdef"), 0)
|
||||
i := m.Index()
|
||||
if i[0] != 1 {
|
||||
t.Error("FindIndex start", i[0])
|
||||
}
|
||||
if i[1] != 4 {
|
||||
t.Error("FindIndex end", i[1])
|
||||
}
|
||||
re2 := MustCompile("xyz", 0)
|
||||
defer re2.FreeRegexp()
|
||||
m = re2.Matcher([]byte("abcdef"), 0)
|
||||
i = m.Index()
|
||||
if i != nil {
|
||||
t.Error("Index returned for non-match", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindIndex(t *testing.T) {
|
||||
re := MustCompile("bcd", 0)
|
||||
defer re.FreeRegexp()
|
||||
i := re.FindIndex([]byte("abcdef"), 0)
|
||||
if i[0] != 1 {
|
||||
t.Error("FindIndex start", i[0])
|
||||
}
|
||||
if i[1] != 4 {
|
||||
t.Error("FindIndex end", i[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtract(t *testing.T) {
|
||||
re := MustCompile("b(c)(d)", 0)
|
||||
defer re.FreeRegexp()
|
||||
m := re.MatcherString("abcdef", 0)
|
||||
i := m.ExtractString()
|
||||
if i[0] != "abcdef" {
|
||||
t.Error("Full line unavailable: ", i[0])
|
||||
}
|
||||
if i[1] != "c" {
|
||||
t.Error("First match group no as expected: ", i[1])
|
||||
}
|
||||
if i[2] != "d" {
|
||||
t.Error("Second match group no as expected: ", i[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceAll(t *testing.T) {
|
||||
re := MustCompile("foo", 0)
|
||||
var result []byte
|
||||
var err error
|
||||
defer re.FreeRegexp()
|
||||
// Don't change at ends.
|
||||
if result, err = re.ReplaceAll(
|
||||
[]byte("I like foods."),
|
||||
[]byte("car"),
|
||||
0,
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(result) != "I like cards." {
|
||||
t.Error("ReplaceAll", result)
|
||||
}
|
||||
// Change at ends.
|
||||
if result, err = re.ReplaceAll(
|
||||
[]byte("food fight fools foo"),
|
||||
[]byte("car"),
|
||||
0,
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(result) != "card fight carls car" {
|
||||
t.Error("ReplaceAll2", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFreeRegexp(t *testing.T) {
|
||||
re := MustCompileJIT("\\d{3}", 0, STUDY_JIT_COMPILE)
|
||||
data := []string{"15asd213", "sadi32fjoi"}
|
||||
expected := []bool{true, false}
|
||||
for i := 0; i < len(data); i++ {
|
||||
m := re.MatcherString(data[i], 0)
|
||||
if m.Matches() != expected[i] {
|
||||
t.Error("Unexpected match for ", data[i])
|
||||
}
|
||||
}
|
||||
re.FreeRegexp()
|
||||
|
||||
// Test double free.
|
||||
re.FreeRegexp()
|
||||
}
|
||||
|
||||
func TestFindAll(t *testing.T) {
|
||||
re := MustCompile("\\d{2}x", 0)
|
||||
var matches []Match
|
||||
var err error
|
||||
defer re.FreeRegexp()
|
||||
data := "12x 12332xf 43bx62x"
|
||||
expected := []Match{
|
||||
Match{"12x", []int{0, 3}},
|
||||
Match{"32x", []int{7, 10}},
|
||||
Match{"62x", []int{16, 19}},
|
||||
}
|
||||
if matches, err = re.FindAll(data, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyMatches(t, expected, matches)
|
||||
|
||||
if matches, err = re.FindAll("", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(matches) != 0 {
|
||||
t.Error("Expected no results, got: ", matches)
|
||||
}
|
||||
|
||||
// Test zero-length matches.
|
||||
re2 := MustCompile("\\w*", 0)
|
||||
defer re2.FreeRegexp()
|
||||
data = "cat dog"
|
||||
expected = []Match{
|
||||
Match{"cat", []int{0, 3}},
|
||||
Match{"", []int{3, 3}},
|
||||
Match{"dog", []int{4, 7}},
|
||||
}
|
||||
matches, err = re2.FindAll(data, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyMatches(t, expected, matches)
|
||||
}
|
||||
|
||||
func verifyMatches(t *testing.T, expected []Match, matches []Match) {
|
||||
if len(matches) != len(expected) {
|
||||
t.Errorf("Expected %d matches, got: %d", len(expected), len(matches))
|
||||
}
|
||||
for i := 0; i < len(expected); i++ {
|
||||
if !reflect.DeepEqual(matches[i], expected[i]) {
|
||||
t.Errorf("Expected match: %v, got: %v", expected[i], matches[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
+3642
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,299 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2013 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 for validating UTF-8 character
|
||||
strings. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Validate a UTF-8 string *
|
||||
*************************************************/
|
||||
|
||||
/* This function is called (optionally) at the start of compile or match, to
|
||||
check that a supposed UTF-8 string is actually valid. The early check means
|
||||
that subsequent code can assume it is dealing with a valid string. The check
|
||||
can be turned off for maximum performance, but the consequences of supplying an
|
||||
invalid string are then undefined.
|
||||
|
||||
Originally, this function checked according to RFC 2279, allowing for values in
|
||||
the range 0 to 0x7fffffff, up to 6 bytes long, but ensuring that they were in
|
||||
the canonical format. Once somebody had pointed out RFC 3629 to me (it
|
||||
obsoletes 2279), additional restrictions were applied. The values are now
|
||||
limited to be between 0 and 0x0010ffff, no more than 4 bytes long, and the
|
||||
subrange 0xd000 to 0xdfff is excluded. However, the format of 5-byte and 6-byte
|
||||
characters is still checked.
|
||||
|
||||
From release 8.13 more information about the details of the error are passed
|
||||
back in the returned value:
|
||||
|
||||
PCRE_UTF8_ERR0 No error
|
||||
PCRE_UTF8_ERR1 Missing 1 byte at the end of the string
|
||||
PCRE_UTF8_ERR2 Missing 2 bytes at the end of the string
|
||||
PCRE_UTF8_ERR3 Missing 3 bytes at the end of the string
|
||||
PCRE_UTF8_ERR4 Missing 4 bytes at the end of the string
|
||||
PCRE_UTF8_ERR5 Missing 5 bytes at the end of the string
|
||||
PCRE_UTF8_ERR6 2nd-byte's two top bits are not 0x80
|
||||
PCRE_UTF8_ERR7 3rd-byte's two top bits are not 0x80
|
||||
PCRE_UTF8_ERR8 4th-byte's two top bits are not 0x80
|
||||
PCRE_UTF8_ERR9 5th-byte's two top bits are not 0x80
|
||||
PCRE_UTF8_ERR10 6th-byte's two top bits are not 0x80
|
||||
PCRE_UTF8_ERR11 5-byte character is not permitted by RFC 3629
|
||||
PCRE_UTF8_ERR12 6-byte character is not permitted by RFC 3629
|
||||
PCRE_UTF8_ERR13 4-byte character with value > 0x10ffff is not permitted
|
||||
PCRE_UTF8_ERR14 3-byte character with value 0xd000-0xdfff is not permitted
|
||||
PCRE_UTF8_ERR15 Overlong 2-byte sequence
|
||||
PCRE_UTF8_ERR16 Overlong 3-byte sequence
|
||||
PCRE_UTF8_ERR17 Overlong 4-byte sequence
|
||||
PCRE_UTF8_ERR18 Overlong 5-byte sequence (won't ever occur)
|
||||
PCRE_UTF8_ERR19 Overlong 6-byte sequence (won't ever occur)
|
||||
PCRE_UTF8_ERR20 Isolated 0x80 byte (not within UTF-8 character)
|
||||
PCRE_UTF8_ERR21 Byte with the illegal value 0xfe or 0xff
|
||||
PCRE_UTF8_ERR22 Unused (was non-character)
|
||||
|
||||
Arguments:
|
||||
string points to the string
|
||||
length length of string, or -1 if the string is zero-terminated
|
||||
errp pointer to an error position offset variable
|
||||
|
||||
Returns: = 0 if the string is a valid UTF-8 string
|
||||
> 0 otherwise, setting the offset of the bad character
|
||||
*/
|
||||
|
||||
int
|
||||
PRIV(valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset)
|
||||
{
|
||||
#ifdef SUPPORT_UTF
|
||||
register PCRE_PUCHAR p;
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
for (p = string; *p != 0; p++);
|
||||
length = (int)(p - string);
|
||||
}
|
||||
|
||||
for (p = string; length-- > 0; p++)
|
||||
{
|
||||
register pcre_uchar ab, c, d;
|
||||
|
||||
c = *p;
|
||||
if (c < 128) continue; /* ASCII character */
|
||||
|
||||
if (c < 0xc0) /* Isolated 10xx xxxx byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string);
|
||||
return PCRE_UTF8_ERR20;
|
||||
}
|
||||
|
||||
if (c >= 0xfe) /* Invalid 0xfe or 0xff bytes */
|
||||
{
|
||||
*erroroffset = (int)(p - string);
|
||||
return PCRE_UTF8_ERR21;
|
||||
}
|
||||
|
||||
ab = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes */
|
||||
if (length < ab)
|
||||
{
|
||||
*erroroffset = (int)(p - string); /* Missing bytes */
|
||||
return ab - length; /* Codes ERR1 to ERR5 */
|
||||
}
|
||||
length -= ab; /* Length remaining */
|
||||
|
||||
/* Check top bits in the second byte */
|
||||
|
||||
if (((d = *(++p)) & 0xc0) != 0x80)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 1;
|
||||
return PCRE_UTF8_ERR6;
|
||||
}
|
||||
|
||||
/* For each length, check that the remaining bytes start with the 0x80 bit
|
||||
set and not the 0x40 bit. Then check for an overlong sequence, and for the
|
||||
excluded range 0xd800 to 0xdfff. */
|
||||
|
||||
switch (ab)
|
||||
{
|
||||
/* 2-byte character. No further bytes to check for 0x80. Check first byte
|
||||
for for xx00 000x (overlong sequence). */
|
||||
|
||||
case 1: if ((c & 0x3e) == 0)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 1;
|
||||
return PCRE_UTF8_ERR15;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 3-byte character. Check third byte for 0x80. Then check first 2 bytes
|
||||
for 1110 0000, xx0x xxxx (overlong sequence) or
|
||||
1110 1101, 1010 xxxx (0xd800 - 0xdfff) */
|
||||
|
||||
case 2:
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 2;
|
||||
return PCRE_UTF8_ERR7;
|
||||
}
|
||||
if (c == 0xe0 && (d & 0x20) == 0)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 2;
|
||||
return PCRE_UTF8_ERR16;
|
||||
}
|
||||
if (c == 0xed && d >= 0xa0)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 2;
|
||||
return PCRE_UTF8_ERR14;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 4-byte character. Check 3rd and 4th bytes for 0x80. Then check first 2
|
||||
bytes for for 1111 0000, xx00 xxxx (overlong sequence), then check for a
|
||||
character greater than 0x0010ffff (f4 8f bf bf) */
|
||||
|
||||
case 3:
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 2;
|
||||
return PCRE_UTF8_ERR7;
|
||||
}
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 3;
|
||||
return PCRE_UTF8_ERR8;
|
||||
}
|
||||
if (c == 0xf0 && (d & 0x30) == 0)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 3;
|
||||
return PCRE_UTF8_ERR17;
|
||||
}
|
||||
if (c > 0xf4 || (c == 0xf4 && d > 0x8f))
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 3;
|
||||
return PCRE_UTF8_ERR13;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 5-byte and 6-byte characters are not allowed by RFC 3629, and will be
|
||||
rejected by the length test below. However, we do the appropriate tests
|
||||
here so that overlong sequences get diagnosed, and also in case there is
|
||||
ever an option for handling these larger code points. */
|
||||
|
||||
/* 5-byte character. Check 3rd, 4th, and 5th bytes for 0x80. Then check for
|
||||
1111 1000, xx00 0xxx */
|
||||
|
||||
case 4:
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 2;
|
||||
return PCRE_UTF8_ERR7;
|
||||
}
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 3;
|
||||
return PCRE_UTF8_ERR8;
|
||||
}
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 4;
|
||||
return PCRE_UTF8_ERR9;
|
||||
}
|
||||
if (c == 0xf8 && (d & 0x38) == 0)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 4;
|
||||
return PCRE_UTF8_ERR18;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 6-byte character. Check 3rd-6th bytes for 0x80. Then check for
|
||||
1111 1100, xx00 00xx. */
|
||||
|
||||
case 5:
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 2;
|
||||
return PCRE_UTF8_ERR7;
|
||||
}
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 3;
|
||||
return PCRE_UTF8_ERR8;
|
||||
}
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 4;
|
||||
return PCRE_UTF8_ERR9;
|
||||
}
|
||||
if ((*(++p) & 0xc0) != 0x80) /* Sixth byte */
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 5;
|
||||
return PCRE_UTF8_ERR10;
|
||||
}
|
||||
if (c == 0xfc && (d & 0x3c) == 0)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - 5;
|
||||
return PCRE_UTF8_ERR19;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Character is valid under RFC 2279, but 4-byte and 5-byte characters are
|
||||
excluded by RFC 3629. The pointer p is currently at the last byte of the
|
||||
character. */
|
||||
|
||||
if (ab > 3)
|
||||
{
|
||||
*erroroffset = (int)(p - string) - ab;
|
||||
return (ab == 4)? PCRE_UTF8_ERR11 : PCRE_UTF8_ERR12;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* Not SUPPORT_UTF */
|
||||
(void)(string); /* Keep picky compilers happy */
|
||||
(void)(length);
|
||||
(void)(erroroffset);
|
||||
#endif
|
||||
|
||||
return PCRE_UTF8_ERR0; /* This indicates success */
|
||||
}
|
||||
|
||||
/* End of pcre_valid_utf8.c */
|
||||
@@ -0,0 +1,96 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2012 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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 the external function pcre_version(), which returns a
|
||||
string that identifies the PCRE version that is in use. */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pcre_internal.h"
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Return version string *
|
||||
*************************************************/
|
||||
|
||||
/* These macros are the standard way of turning unquoted text into C strings.
|
||||
They allow macros like PCRE_MAJOR to be defined without quotes, which is
|
||||
convenient for user programs that want to test its value. */
|
||||
|
||||
#define STRING(a) # a
|
||||
#define XSTRING(s) STRING(s)
|
||||
|
||||
/* A problem turned up with PCRE_PRERELEASE, which is defined empty for
|
||||
production releases. Originally, it was used naively in this code:
|
||||
|
||||
return XSTRING(PCRE_MAJOR)
|
||||
"." XSTRING(PCRE_MINOR)
|
||||
XSTRING(PCRE_PRERELEASE)
|
||||
" " XSTRING(PCRE_DATE);
|
||||
|
||||
However, when PCRE_PRERELEASE is empty, this leads to an attempted expansion of
|
||||
STRING(). The C standard states: "If (before argument substitution) any
|
||||
argument consists of no preprocessing tokens, the behavior is undefined." It
|
||||
turns out the gcc treats this case as a single empty string - which is what we
|
||||
really want - but Visual C grumbles about the lack of an argument for the
|
||||
macro. Unfortunately, both are within their rights. To cope with both ways of
|
||||
handling this, I had resort to some messy hackery that does a test at run time.
|
||||
I could find no way of detecting that a macro is defined as an empty string at
|
||||
pre-processor time. This hack uses a standard trick for avoiding calling
|
||||
the STRING macro with an empty argument when doing the test. */
|
||||
|
||||
#if defined COMPILE_PCRE8
|
||||
PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION
|
||||
pcre_version(void)
|
||||
#elif defined COMPILE_PCRE16
|
||||
PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION
|
||||
pcre16_version(void)
|
||||
#elif defined COMPILE_PCRE32
|
||||
PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION
|
||||
pcre32_version(void)
|
||||
#endif
|
||||
{
|
||||
return (XSTRING(Z PCRE_PRERELEASE)[1] == 0)?
|
||||
XSTRING(PCRE_MAJOR.PCRE_MINOR PCRE_DATE) :
|
||||
XSTRING(PCRE_MAJOR.PCRE_MINOR) XSTRING(PCRE_PRERELEASE PCRE_DATE);
|
||||
}
|
||||
|
||||
/* End of pcre_version.c */
|
||||
@@ -0,0 +1,4 @@
|
||||
package pcre
|
||||
|
||||
// #define HAVE_WINDOWS_H 1
|
||||
import "C"
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
/*************************************************
|
||||
* Perl-Compatible Regular Expressions *
|
||||
*************************************************/
|
||||
|
||||
/* 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.
|
||||
|
||||
Written by Philip Hazel
|
||||
Copyright (c) 1997-2013 University of Cambridge
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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. It is used by both pcre_exec() and pcre_def_exec(). */
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#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 and/or Unicode properties.
|
||||
|
||||
Arguments:
|
||||
c the character
|
||||
data points to the flag byte of the XCLASS data
|
||||
|
||||
Returns: TRUE if character matches, else FALSE
|
||||
*/
|
||||
|
||||
BOOL
|
||||
PRIV(xclass)(pcre_uint32 c, const pcre_uchar *data, BOOL utf)
|
||||
{
|
||||
pcre_uchar t;
|
||||
BOOL negated = (*data & XCL_NOT) != 0;
|
||||
|
||||
(void)utf;
|
||||
#ifdef COMPILE_PCRE8
|
||||
/* In 8 bit mode, this must always be TRUE. Help the compiler to know that. */
|
||||
utf = TRUE;
|
||||
#endif
|
||||
|
||||
/* 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_HASPROP) == 0)
|
||||
{
|
||||
if ((*data & XCL_MAP) == 0) return negated;
|
||||
return (((pcre_uint8 *)(data + 1))[c/8] & (1 << (c&7))) != 0;
|
||||
}
|
||||
if ((*data & XCL_MAP) != 0 &&
|
||||
(((pcre_uint8 *)(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 / sizeof(pcre_uchar);
|
||||
|
||||
while ((t = *data++) != XCL_END)
|
||||
{
|
||||
pcre_uint32 x, y;
|
||||
if (t == XCL_SINGLE)
|
||||
{
|
||||
#ifdef SUPPORT_UTF
|
||||
if (utf)
|
||||
{
|
||||
GETCHARINC(x, data); /* macro generates multiple statements */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
x = *data++;
|
||||
if (c == x) return !negated;
|
||||
}
|
||||
else if (t == XCL_RANGE)
|
||||
{
|
||||
#ifdef SUPPORT_UTF
|
||||
if (utf)
|
||||
{
|
||||
GETCHARINC(x, data); /* macro generates multiple statements */
|
||||
GETCHARINC(y, data); /* macro generates multiple statements */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
x = *data++;
|
||||
y = *data++;
|
||||
}
|
||||
if (c >= x && c <= y) return !negated;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_UCP
|
||||
else /* XCL_PROP & XCL_NOTPROP */
|
||||
{
|
||||
const ucd_record *prop = GET_UCD(c);
|
||||
BOOL isprop = t == XCL_PROP;
|
||||
|
||||
switch(*data)
|
||||
{
|
||||
case PT_ANY:
|
||||
if (isprop) return !negated;
|
||||
break;
|
||||
|
||||
case PT_LAMP:
|
||||
if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
|
||||
prop->chartype == ucp_Lt) == isprop) return !negated;
|
||||
break;
|
||||
|
||||
case PT_GC:
|
||||
if ((data[1] == PRIV(ucp_gentype)[prop->chartype]) == isprop)
|
||||
return !negated;
|
||||
break;
|
||||
|
||||
case PT_PC:
|
||||
if ((data[1] == prop->chartype) == isprop) return !negated;
|
||||
break;
|
||||
|
||||
case PT_SC:
|
||||
if ((data[1] == prop->script) == isprop) return !negated;
|
||||
break;
|
||||
|
||||
case PT_ALNUM:
|
||||
if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
|
||||
PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop)
|
||||
return !negated;
|
||||
break;
|
||||
|
||||
/* Perl space used to exclude VT, but from Perl 5.18 it is included,
|
||||
which means that Perl space and POSIX space are now identical. PCRE
|
||||
was changed at release 8.34. */
|
||||
|
||||
case PT_SPACE: /* Perl space */
|
||||
case PT_PXSPACE: /* POSIX space */
|
||||
switch(c)
|
||||
{
|
||||
HSPACE_CASES:
|
||||
VSPACE_CASES:
|
||||
if (isprop) return !negated;
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == isprop)
|
||||
return !negated;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PT_WORD:
|
||||
if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
|
||||
PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE)
|
||||
== isprop)
|
||||
return !negated;
|
||||
break;
|
||||
|
||||
case PT_UCNC:
|
||||
if (c < 0xa0)
|
||||
{
|
||||
if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
|
||||
c == CHAR_GRAVE_ACCENT) == isprop)
|
||||
return !negated;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((c < 0xd800 || c > 0xdfff) == isprop)
|
||||
return !negated;
|
||||
}
|
||||
break;
|
||||
|
||||
/* The following three properties can occur only in an XCLASS, as there
|
||||
is no \p or \P coding for them. */
|
||||
|
||||
/* Graphic character. Implement this as not Z (space or separator) and
|
||||
not C (other), except for Cf (format) with a few exceptions. This seems
|
||||
to be what Perl does. The exceptional characters are:
|
||||
|
||||
U+061C Arabic Letter Mark
|
||||
U+180E Mongolian Vowel Separator
|
||||
U+2066 - U+2069 Various "isolate"s
|
||||
*/
|
||||
|
||||
case PT_PXGRAPH:
|
||||
if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z &&
|
||||
(PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
|
||||
(prop->chartype == ucp_Cf &&
|
||||
c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069))
|
||||
)) == isprop)
|
||||
return !negated;
|
||||
break;
|
||||
|
||||
/* Printable character: same as graphic, with the addition of Zs, i.e.
|
||||
not Zl and not Zp, and U+180E. */
|
||||
|
||||
case PT_PXPRINT:
|
||||
if ((prop->chartype != ucp_Zl &&
|
||||
prop->chartype != ucp_Zp &&
|
||||
(PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
|
||||
(prop->chartype == ucp_Cf &&
|
||||
c != 0x061c && (c < 0x2066 || c > 0x2069))
|
||||
)) == isprop)
|
||||
return !negated;
|
||||
break;
|
||||
|
||||
/* Punctuation: all Unicode punctuation, plus ASCII characters that
|
||||
Unicode treats as symbols rather than punctuation, for Perl
|
||||
compatibility (these are $+<=>^`|~). */
|
||||
|
||||
case PT_PXPUNCT:
|
||||
if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P ||
|
||||
(c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop)
|
||||
return !negated;
|
||||
break;
|
||||
|
||||
/* This should never occur, but compilers may mutter if there is no
|
||||
default. */
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data += 2;
|
||||
}
|
||||
#endif /* SUPPORT_UCP */
|
||||
}
|
||||
|
||||
return negated; /* char did not match */
|
||||
}
|
||||
|
||||
/* End of pcre_xclass.c */
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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 _SLJIT_CONFIG_H_
|
||||
#define _SLJIT_CONFIG_H_
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Custom defines */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Put your custom defines here. This empty section will never change
|
||||
which helps maintaining patches (with diff / patch utilities). */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Architecture */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Architecture selection. */
|
||||
/* #define SLJIT_CONFIG_X86_32 1 */
|
||||
/* #define SLJIT_CONFIG_X86_64 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_V5 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_V7 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_64 1 */
|
||||
/* #define SLJIT_CONFIG_PPC_32 1 */
|
||||
/* #define SLJIT_CONFIG_PPC_64 1 */
|
||||
/* #define SLJIT_CONFIG_MIPS_32 1 */
|
||||
/* #define SLJIT_CONFIG_MIPS_64 1 */
|
||||
/* #define SLJIT_CONFIG_SPARC_32 1 */
|
||||
/* #define SLJIT_CONFIG_TILEGX 1 */
|
||||
|
||||
/* #define SLJIT_CONFIG_AUTO 1 */
|
||||
/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Utilities */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Useful for thread-safe compiling of global functions. */
|
||||
#ifndef SLJIT_UTIL_GLOBAL_LOCK
|
||||
/* Enabled by default */
|
||||
#define SLJIT_UTIL_GLOBAL_LOCK 1
|
||||
#endif
|
||||
|
||||
/* Implements a stack like data structure (by using mmap / VirtualAlloc). */
|
||||
#ifndef SLJIT_UTIL_STACK
|
||||
/* Enabled by default */
|
||||
#define SLJIT_UTIL_STACK 1
|
||||
#endif
|
||||
|
||||
/* Single threaded application. Does not require any locks. */
|
||||
#ifndef SLJIT_SINGLE_THREADED
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_SINGLE_THREADED 0
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Configuration */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should
|
||||
define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */
|
||||
#ifndef SLJIT_STD_MACROS_DEFINED
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_STD_MACROS_DEFINED 0
|
||||
#endif
|
||||
|
||||
/* Executable code allocation:
|
||||
If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
|
||||
define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
|
||||
#ifndef SLJIT_EXECUTABLE_ALLOCATOR
|
||||
/* Enabled by default. */
|
||||
#define SLJIT_EXECUTABLE_ALLOCATOR 1
|
||||
|
||||
/* When SLJIT_PROT_EXECUTABLE_ALLOCATOR is enabled SLJIT uses
|
||||
an allocator which does not set writable and executable
|
||||
permission flags at the same time. The trade-of is increased
|
||||
memory consumption and disabled dynamic code modifications. */
|
||||
#ifndef SLJIT_PROT_EXECUTABLE_ALLOCATOR
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_PROT_EXECUTABLE_ALLOCATOR 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Force cdecl calling convention even if a better calling
|
||||
convention (e.g. fastcall) is supported by the C compiler.
|
||||
If this option is disabled (this is the default), functions
|
||||
called from JIT should be defined with SLJIT_FUNC attribute.
|
||||
Standard C functions can still be called by using the
|
||||
SLJIT_CALL_CDECL jump type. */
|
||||
#ifndef SLJIT_USE_CDECL_CALLING_CONVENTION
|
||||
/* Disabled by default */
|
||||
#define SLJIT_USE_CDECL_CALLING_CONVENTION 0
|
||||
#endif
|
||||
|
||||
/* Return with error when an invalid argument is passed. */
|
||||
#ifndef SLJIT_ARGUMENT_CHECKS
|
||||
/* Disabled by default */
|
||||
#define SLJIT_ARGUMENT_CHECKS 0
|
||||
#endif
|
||||
|
||||
/* Debug checks (assertions, etc.). */
|
||||
#ifndef SLJIT_DEBUG
|
||||
/* Enabled by default */
|
||||
#define SLJIT_DEBUG 1
|
||||
#endif
|
||||
|
||||
/* Verbose operations. */
|
||||
#ifndef SLJIT_VERBOSE
|
||||
/* Enabled by default */
|
||||
#define SLJIT_VERBOSE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
SLJIT_IS_FPU_AVAILABLE
|
||||
The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE.
|
||||
zero value - FPU is NOT present.
|
||||
nonzero value - FPU is present.
|
||||
*/
|
||||
|
||||
/* For further configurations, see the beginning of sljitConfigInternal.h */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,745 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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 _SLJIT_CONFIG_INTERNAL_H_
|
||||
#define _SLJIT_CONFIG_INTERNAL_H_
|
||||
|
||||
/*
|
||||
SLJIT defines the following architecture dependent types and macros:
|
||||
|
||||
Types:
|
||||
sljit_s8, sljit_u8 : signed and unsigned 8 bit integer type
|
||||
sljit_s16, sljit_u16 : signed and unsigned 16 bit integer type
|
||||
sljit_s32, sljit_u32 : signed and unsigned 32 bit integer type
|
||||
sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer
|
||||
sljit_p : unsgined pointer value (usually the same as sljit_uw, but
|
||||
some 64 bit ABIs may use 32 bit pointers)
|
||||
sljit_f32 : 32 bit single precision floating point value
|
||||
sljit_f64 : 64 bit double precision floating point value
|
||||
|
||||
Macros for feature detection (boolean):
|
||||
SLJIT_32BIT_ARCHITECTURE : 32 bit architecture
|
||||
SLJIT_64BIT_ARCHITECTURE : 64 bit architecture
|
||||
SLJIT_LITTLE_ENDIAN : little endian architecture
|
||||
SLJIT_BIG_ENDIAN : big endian architecture
|
||||
SLJIT_UNALIGNED : allows unaligned memory accesses for non-fpu operations (only!)
|
||||
SLJIT_INDIRECT_CALL : see SLJIT_FUNC_OFFSET() for more information
|
||||
|
||||
Constants:
|
||||
SLJIT_NUMBER_OF_REGISTERS : number of available registers
|
||||
SLJIT_NUMBER_OF_SCRATCH_REGISTERS : number of available scratch registers
|
||||
SLJIT_NUMBER_OF_SAVED_REGISTERS : number of available saved registers
|
||||
SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers
|
||||
SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
|
||||
SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
|
||||
SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
|
||||
SLJIT_F32_SHIFT : the shift required to apply when accessing
|
||||
a single precision floating point array by index
|
||||
SLJIT_F64_SHIFT : the shift required to apply when accessing
|
||||
a double precision floating point array by index
|
||||
SLJIT_PREF_SHIFT_REG : x86 systems prefers ecx for shifting by register
|
||||
the scratch register index of ecx is stored in this variable
|
||||
SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
|
||||
SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
|
||||
|
||||
Other macros:
|
||||
SLJIT_FUNC : calling convention attribute for both calling JIT from C and C calling back from JIT
|
||||
SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (compiler independent helper)
|
||||
*/
|
||||
|
||||
/*****************/
|
||||
/* Sanity check. */
|
||||
/*****************/
|
||||
|
||||
#if !((defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
|| (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
|
||||
|| (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
|
||||
|| (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
|
||||
|| (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED))
|
||||
#error "An architecture must be selected"
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
+ (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
+ (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
|
||||
+ (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
+ (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
+ (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
+ (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
+ (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
+ (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
|
||||
+ (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
+ (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
+ (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
|
||||
+ (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
|
||||
+ (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
|
||||
#error "Multiple architectures are selected"
|
||||
#endif
|
||||
|
||||
/********************************************************/
|
||||
/* Automatic CPU detection (requires compiler support). */
|
||||
/********************************************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#if defined(__i386__) || defined(__i386)
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#elif defined(__x86_64__)
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#elif defined(__arm__) || defined(__ARM__)
|
||||
#ifdef __thumb2__
|
||||
#define SLJIT_CONFIG_ARM_THUMB2 1
|
||||
#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
|
||||
#define SLJIT_CONFIG_ARM_V7 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#endif
|
||||
#elif defined (__aarch64__)
|
||||
#define SLJIT_CONFIG_ARM_64 1
|
||||
#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) || (defined(_POWER) && defined(__64BIT__))
|
||||
#define SLJIT_CONFIG_PPC_64 1
|
||||
#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
|
||||
#define SLJIT_CONFIG_PPC_32 1
|
||||
#elif defined(__mips__) && !defined(_LP64)
|
||||
#define SLJIT_CONFIG_MIPS_32 1
|
||||
#elif defined(__mips64)
|
||||
#define SLJIT_CONFIG_MIPS_64 1
|
||||
#elif defined(__sparc__) || defined(__sparc)
|
||||
#define SLJIT_CONFIG_SPARC_32 1
|
||||
#elif defined(__tilegx__)
|
||||
#define SLJIT_CONFIG_TILEGX 1
|
||||
#else
|
||||
/* Unsupported architecture */
|
||||
#define SLJIT_CONFIG_UNSUPPORTED 1
|
||||
#endif
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__)
|
||||
#define SLJIT_CONFIG_ARM_THUMB2 1
|
||||
#elif (defined(_M_ARM) && _M_ARM >= 7)
|
||||
#define SLJIT_CONFIG_ARM_V7 1
|
||||
#elif defined(_ARM_)
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#elif defined(_M_ARM64) || defined(__aarch64__)
|
||||
#define SLJIT_CONFIG_ARM_64 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#endif
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
#endif /* SLJIT_CONFIG_AUTO */
|
||||
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
#undef SLJIT_EXECUTABLE_ALLOCATOR
|
||||
#endif
|
||||
|
||||
/******************************/
|
||||
/* CPU family type detection. */
|
||||
/******************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
#define SLJIT_CONFIG_ARM_32 1
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
#define SLJIT_CONFIG_X86 1
|
||||
#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
#define SLJIT_CONFIG_ARM 1
|
||||
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
#define SLJIT_CONFIG_PPC 1
|
||||
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
#define SLJIT_CONFIG_MIPS 1
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) || (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
|
||||
#define SLJIT_CONFIG_SPARC 1
|
||||
#endif
|
||||
|
||||
/**********************************/
|
||||
/* External function definitions. */
|
||||
/**********************************/
|
||||
|
||||
/* General macros:
|
||||
Note: SLJIT is designed to be independent from them as possible.
|
||||
|
||||
In release mode (SLJIT_DEBUG is not defined) only the following
|
||||
external functions are needed:
|
||||
*/
|
||||
|
||||
#ifndef SLJIT_MALLOC
|
||||
#define SLJIT_MALLOC(size, allocator_data) malloc(size)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_FREE
|
||||
#define SLJIT_FREE(ptr, allocator_data) free(ptr)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_MEMCPY
|
||||
#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_MEMMOVE
|
||||
#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_ZEROMEM
|
||||
#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len)
|
||||
#endif
|
||||
|
||||
/***************************/
|
||||
/* Compiler helper macros. */
|
||||
/***************************/
|
||||
|
||||
#if !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY)
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
#define SLJIT_LIKELY(x) __builtin_expect((x), 1)
|
||||
#define SLJIT_UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#else
|
||||
#define SLJIT_LIKELY(x) (x)
|
||||
#define SLJIT_UNLIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) */
|
||||
|
||||
#ifndef SLJIT_INLINE
|
||||
/* Inline functions. Some old compilers do not support them. */
|
||||
#if defined(__SUNPRO_C) && __SUNPRO_C <= 0x510
|
||||
#define SLJIT_INLINE
|
||||
#else
|
||||
#define SLJIT_INLINE __inline
|
||||
#endif
|
||||
#endif /* !SLJIT_INLINE */
|
||||
|
||||
#ifndef SLJIT_NOINLINE
|
||||
/* Not inline functions. */
|
||||
#if defined(__GNUC__)
|
||||
#define SLJIT_NOINLINE __attribute__ ((noinline))
|
||||
#else
|
||||
#define SLJIT_NOINLINE
|
||||
#endif
|
||||
#endif /* !SLJIT_INLINE */
|
||||
|
||||
#ifndef SLJIT_UNUSED_ARG
|
||||
/* Unused arguments. */
|
||||
#define SLJIT_UNUSED_ARG(arg) (void)arg
|
||||
#endif
|
||||
|
||||
/*********************************/
|
||||
/* Type of public API functions. */
|
||||
/*********************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC)
|
||||
/* Static ABI functions. For all-in-one programs. */
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/* Disable unused warnings in gcc. */
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE static __attribute__((unused))
|
||||
#else
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE static
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE
|
||||
#endif /* (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) */
|
||||
|
||||
/****************************/
|
||||
/* Instruction cache flush. */
|
||||
/****************************/
|
||||
|
||||
#if (!defined SLJIT_CACHE_FLUSH && defined __has_builtin)
|
||||
#if __has_builtin(__builtin___clear_cache)
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__builtin___clear_cache((char*)from, (char*)to)
|
||||
|
||||
#endif /* __has_builtin(__builtin___clear_cache) */
|
||||
#endif /* (!defined SLJIT_CACHE_FLUSH && defined __has_builtin) */
|
||||
|
||||
#ifndef SLJIT_CACHE_FLUSH
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
|
||||
/* Not required to implement on archs with unified caches. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to)
|
||||
|
||||
#elif defined __APPLE__
|
||||
|
||||
/* Supported by all macs since Mac OS 10.5.
|
||||
However, it does not work on non-jailbroken iOS devices,
|
||||
although the compilation is successful. */
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from))
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
ppc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif (defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__builtin___clear_cache((char*)from, (char*)to)
|
||||
|
||||
#elif defined __ANDROID__
|
||||
|
||||
/* Android lacks __clear_cache; instead, cacheflush should be used. */
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
cacheflush((long)(from), (long)(to), 0)
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
sparc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif defined _WIN32
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
FlushInstructionCache(GetCurrentProcess(), (char*)(from), (char*)(to) - (char*)(from))
|
||||
|
||||
#else
|
||||
|
||||
/* Calls __ARM_NR_cacheflush on ARM-Linux. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__clear_cache((char*)(from), (char*)(to))
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_CACHE_FLUSH */
|
||||
|
||||
/******************************************************/
|
||||
/* Integer and floating point type definitions. */
|
||||
/******************************************************/
|
||||
|
||||
/* 8 bit byte type. */
|
||||
typedef unsigned char sljit_u8;
|
||||
typedef signed char sljit_s8;
|
||||
|
||||
/* 16 bit half-word type. */
|
||||
typedef unsigned short int sljit_u16;
|
||||
typedef signed short int sljit_s16;
|
||||
|
||||
/* 32 bit integer type. */
|
||||
typedef unsigned int sljit_u32;
|
||||
typedef signed int sljit_s32;
|
||||
|
||||
/* Machine word type. Enough for storing a pointer.
|
||||
32 bit for 32 bit machines.
|
||||
64 bit for 64 bit machines. */
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
/* Just to have something. */
|
||||
#define SLJIT_WORD_SHIFT 0
|
||||
typedef unsigned long int sljit_uw;
|
||||
typedef long int sljit_sw;
|
||||
#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
&& !(defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
|
||||
#define SLJIT_32BIT_ARCHITECTURE 1
|
||||
#define SLJIT_WORD_SHIFT 2
|
||||
typedef unsigned int sljit_uw;
|
||||
typedef int sljit_sw;
|
||||
#else
|
||||
#define SLJIT_64BIT_ARCHITECTURE 1
|
||||
#define SLJIT_WORD_SHIFT 3
|
||||
#ifdef _WIN32
|
||||
#ifdef __GNUC__
|
||||
/* These types do not require windows.h */
|
||||
typedef unsigned long long sljit_uw;
|
||||
typedef long long sljit_sw;
|
||||
#else
|
||||
typedef unsigned __int64 sljit_uw;
|
||||
typedef __int64 sljit_sw;
|
||||
#endif
|
||||
#else /* !_WIN32 */
|
||||
typedef unsigned long int sljit_uw;
|
||||
typedef long int sljit_sw;
|
||||
#endif /* _WIN32 */
|
||||
#endif
|
||||
|
||||
typedef sljit_uw sljit_p;
|
||||
|
||||
/* Floating point types. */
|
||||
typedef float sljit_f32;
|
||||
typedef double sljit_f64;
|
||||
|
||||
/* Shift for pointer sized data. */
|
||||
#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT
|
||||
|
||||
/* Shift for double precision sized data. */
|
||||
#define SLJIT_F32_SHIFT 2
|
||||
#define SLJIT_F64_SHIFT 3
|
||||
|
||||
#ifndef SLJIT_W
|
||||
|
||||
/* Defining long constants. */
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
#define SLJIT_W(w) (w##l)
|
||||
#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
|
||||
#define SLJIT_W(w) (w##ll)
|
||||
#else
|
||||
#define SLJIT_W(w) (w)
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_W */
|
||||
|
||||
/*************************/
|
||||
/* Endianness detection. */
|
||||
/*************************/
|
||||
|
||||
#if !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN)
|
||||
|
||||
/* These macros are mostly useful for the applications. */
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
|
||||
#ifdef __MIPSEL__
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
|
||||
#else
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) */
|
||||
|
||||
/* Sanity check. */
|
||||
#if (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
|
||||
#error "Exactly one endianness must be selected"
|
||||
#endif
|
||||
|
||||
#if !(defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && !(defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
|
||||
#error "Exactly one endianness must be selected"
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_UNALIGNED
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
#define SLJIT_UNALIGNED 1
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_UNALIGNED */
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
/* Auto detect SSE2 support using CPUID.
|
||||
On 64 bit x86 cpus, sse2 must be present. */
|
||||
#define SLJIT_DETECT_SSE2 1
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************/
|
||||
/* Calling convention of functions generated by SLJIT or called from the generated code. */
|
||||
/*****************************************************************************************/
|
||||
|
||||
#ifndef SLJIT_FUNC
|
||||
|
||||
#if (defined SLJIT_USE_CDECL_CALLING_CONVENTION && SLJIT_USE_CDECL_CALLING_CONVENTION)
|
||||
|
||||
/* Force cdecl. */
|
||||
#define SLJIT_FUNC
|
||||
|
||||
#elif (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
|
||||
#if defined(__GNUC__) && !defined(__APPLE__)
|
||||
|
||||
#define SLJIT_FUNC __attribute__ ((fastcall))
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#define SLJIT_FUNC __fastcall
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#elif defined(__BORLANDC__)
|
||||
|
||||
#define SLJIT_FUNC __msfastcall
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#else /* Unknown compiler. */
|
||||
|
||||
/* The cdecl attribute is the default. */
|
||||
#define SLJIT_FUNC
|
||||
|
||||
#endif
|
||||
|
||||
#else /* Non x86-32 architectures. */
|
||||
|
||||
#define SLJIT_FUNC
|
||||
|
||||
#endif /* SLJIT_CONFIG_X86_32 */
|
||||
|
||||
#endif /* !SLJIT_FUNC */
|
||||
|
||||
#ifndef SLJIT_INDIRECT_CALL
|
||||
#if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (!defined _CALL_ELF || _CALL_ELF == 1)) \
|
||||
|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
|
||||
/* It seems certain ppc compilers use an indirect addressing for functions
|
||||
which makes things complicated. */
|
||||
#define SLJIT_INDIRECT_CALL 1
|
||||
#endif
|
||||
#endif /* SLJIT_INDIRECT_CALL */
|
||||
|
||||
/* The offset which needs to be substracted from the return address to
|
||||
determine the next executed instruction after return. */
|
||||
#ifndef SLJIT_RETURN_ADDRESS_OFFSET
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
#define SLJIT_RETURN_ADDRESS_OFFSET 8
|
||||
#else
|
||||
#define SLJIT_RETURN_ADDRESS_OFFSET 0
|
||||
#endif
|
||||
#endif /* SLJIT_RETURN_ADDRESS_OFFSET */
|
||||
|
||||
/***************************************************/
|
||||
/* Functions of the built-in executable allocator. */
|
||||
/***************************************************/
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
|
||||
#define SLJIT_MALLOC_EXEC(size) sljit_malloc_exec(size)
|
||||
#define SLJIT_FREE_EXEC(ptr) sljit_free_exec(ptr)
|
||||
|
||||
#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
|
||||
#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
|
||||
#else
|
||||
#define SLJIT_EXEC_OFFSET(ptr) 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************/
|
||||
/* Registers and locals offset determination. */
|
||||
/**********************************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 9
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#define SLJIT_PREF_SHIFT_REG SLJIT_R2
|
||||
|
||||
#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 13
|
||||
#ifndef _WIN64
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#else /* _WIN64 */
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#endif /* !_WIN64 */
|
||||
#define SLJIT_PREF_SHIFT_REG SLJIT_R3
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 26
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 23
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 17
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * sizeof(sljit_sw))
|
||||
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
/* Add +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1) * sizeof(sljit_sw))
|
||||
#else
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (3 * sizeof(sljit_sw))
|
||||
#endif /* SLJIT_CONFIG_PPC_64 || _AIX */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 21
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (4 * sizeof(sljit_sw))
|
||||
#else
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 18
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 14
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
/* saved registers (16), return struct pointer (1), space for 6 argument words (1),
|
||||
4th double arg (2), double alignment (1). */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((16 + 1 + 6 + 2 + 1) * sizeof(sljit_sw))
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 10
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 5
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 0
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#endif
|
||||
|
||||
#define SLJIT_LOCALS_OFFSET (SLJIT_LOCALS_OFFSET_BASE)
|
||||
|
||||
#define SLJIT_NUMBER_OF_SCRATCH_REGISTERS \
|
||||
(SLJIT_NUMBER_OF_REGISTERS - SLJIT_NUMBER_OF_SAVED_REGISTERS)
|
||||
|
||||
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 6
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined _WIN64)
|
||||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 1
|
||||
#else
|
||||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
|
||||
#endif
|
||||
|
||||
#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
|
||||
(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
|
||||
|
||||
/*************************************/
|
||||
/* Debug and verbose related macros. */
|
||||
/*************************************/
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
|
||||
|
||||
#if !defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE)
|
||||
|
||||
/* SLJIT_HALT_PROCESS must halt the process. */
|
||||
#ifndef SLJIT_HALT_PROCESS
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SLJIT_HALT_PROCESS() \
|
||||
abort();
|
||||
#endif /* !SLJIT_HALT_PROCESS */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#endif /* !SLJIT_ASSERT || !SLJIT_UNREACHABLE */
|
||||
|
||||
/* Feel free to redefine these two macros. */
|
||||
#ifndef SLJIT_ASSERT
|
||||
|
||||
#define SLJIT_ASSERT(x) \
|
||||
do { \
|
||||
if (SLJIT_UNLIKELY(!(x))) { \
|
||||
printf("Assertion failed at " __FILE__ ":%d\n", __LINE__); \
|
||||
SLJIT_HALT_PROCESS(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SLJIT_ASSERT */
|
||||
|
||||
#ifndef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { \
|
||||
printf("Should never been reached " __FILE__ ":%d\n", __LINE__); \
|
||||
SLJIT_HALT_PROCESS(); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SLJIT_UNREACHABLE */
|
||||
|
||||
#else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
/* Forcing empty, but valid statements. */
|
||||
#undef SLJIT_ASSERT
|
||||
#undef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_ASSERT(x) \
|
||||
do { } while (0)
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { } while (0)
|
||||
|
||||
#endif /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
#ifndef SLJIT_COMPILE_ASSERT
|
||||
|
||||
#define SLJIT_COMPILE_ASSERT(x, description) \
|
||||
switch(0) { case 0: case ((x) ? 1 : 0): break; }
|
||||
|
||||
#endif /* !SLJIT_COMPILE_ASSERT */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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 file contains a simple executable memory allocator
|
||||
|
||||
It is assumed, that executable code blocks are usually medium (or sometimes
|
||||
large) memory blocks, and the allocator is not too frequently called (less
|
||||
optimized than other allocators). Thus, using it as a generic allocator is
|
||||
not suggested.
|
||||
|
||||
How does it work:
|
||||
Memory is allocated in continuous memory areas called chunks by alloc_chunk()
|
||||
Chunk format:
|
||||
[ block ][ block ] ... [ block ][ block terminator ]
|
||||
|
||||
All blocks and the block terminator is started with block_header. The block
|
||||
header contains the size of the previous and the next block. These sizes
|
||||
can also contain special values.
|
||||
Block size:
|
||||
0 - The block is a free_block, with a different size member.
|
||||
1 - The block is a block terminator.
|
||||
n - The block is used at the moment, and the value contains its size.
|
||||
Previous block size:
|
||||
0 - This is the first block of the memory chunk.
|
||||
n - The size of the previous block.
|
||||
|
||||
Using these size values we can go forward or backward on the block chain.
|
||||
The unused blocks are stored in a chain list pointed by free_blocks. This
|
||||
list is useful if we need to find a suitable memory area when the allocator
|
||||
is called.
|
||||
|
||||
When a block is freed, the new free block is connected to its adjacent free
|
||||
blocks if possible.
|
||||
|
||||
[ free block ][ used block ][ free block ]
|
||||
and "used block" is freed, the three blocks are connected together:
|
||||
[ one big free block ]
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* System (OS) functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* 64 KByte. */
|
||||
#define CHUNK_SIZE 0x10000
|
||||
|
||||
/*
|
||||
alloc_chunk / free_chunk :
|
||||
* allocate executable system memory chunks
|
||||
* the size is always divisible by CHUNK_SIZE
|
||||
allocator_grab_lock / allocator_release_lock :
|
||||
* make the allocator thread safe
|
||||
* can be empty if the OS (or the application) does not support threading
|
||||
* only the allocator requires this lock, sljit is fully thread safe
|
||||
as it only uses local variables
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(size);
|
||||
VirtualFree(chunk, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* Configures TARGET_OS_OSX when appropriate */
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_OSX && defined(MAP_JIT)
|
||||
#include <sys/utsname.h>
|
||||
#endif /* TARGET_OS_OSX && MAP_JIT */
|
||||
|
||||
#ifdef MAP_JIT
|
||||
|
||||
static SLJIT_INLINE int get_map_jit_flag()
|
||||
{
|
||||
#if TARGET_OS_OSX
|
||||
/* On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a version
|
||||
of macOS where it's OK to have more than one JIT block. On non-macOS systems, returns
|
||||
MAP_JIT if it is defined. */
|
||||
static int map_jit_flag = -1;
|
||||
|
||||
/* The following code is thread safe because multiple initialization
|
||||
sets map_jit_flag to the same value and the code has no side-effects.
|
||||
Changing the kernel version witout system restart is (very) unlikely. */
|
||||
if (map_jit_flag == -1) {
|
||||
struct utsname name;
|
||||
|
||||
map_jit_flag = 0;
|
||||
uname(&name);
|
||||
|
||||
/* Kernel version for 10.14.0 (Mojave) */
|
||||
if (atoi(name.release) >= 18) {
|
||||
/* Only use MAP_JIT if a hardened runtime is used, because MAP_JIT is incompatible with fork(). */
|
||||
void *ptr = mmap(NULL, getpagesize(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (ptr == MAP_FAILED) {
|
||||
map_jit_flag = MAP_JIT;
|
||||
} else {
|
||||
munmap(ptr, getpagesize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map_jit_flag;
|
||||
#else /* !TARGET_OS_OSX */
|
||||
return MAP_JIT;
|
||||
#endif /* TARGET_OS_OSX */
|
||||
}
|
||||
|
||||
#endif /* MAP_JIT */
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
void *retval;
|
||||
const int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
|
||||
#ifdef MAP_ANON
|
||||
|
||||
int flags = MAP_PRIVATE | MAP_ANON;
|
||||
|
||||
#ifdef MAP_JIT
|
||||
flags |= get_map_jit_flag();
|
||||
#endif
|
||||
|
||||
retval = mmap(NULL, size, prot, flags, -1, 0);
|
||||
#else /* !MAP_ANON */
|
||||
if (dev_zero < 0) {
|
||||
if (open_dev_zero())
|
||||
return NULL;
|
||||
}
|
||||
retval = mmap(NULL, size, prot, MAP_PRIVATE, dev_zero, 0);
|
||||
#endif /* MAP_ANON */
|
||||
|
||||
if (retval == MAP_FAILED)
|
||||
retval = NULL;
|
||||
else {
|
||||
if (mprotect(retval, size, prot) < 0) {
|
||||
munmap(retval, size);
|
||||
retval = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
munmap(chunk, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Common functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define CHUNK_MASK (~(CHUNK_SIZE - 1))
|
||||
|
||||
struct block_header {
|
||||
sljit_uw size;
|
||||
sljit_uw prev_size;
|
||||
};
|
||||
|
||||
struct free_block {
|
||||
struct block_header header;
|
||||
struct free_block *next;
|
||||
struct free_block *prev;
|
||||
sljit_uw size;
|
||||
};
|
||||
|
||||
#define AS_BLOCK_HEADER(base, offset) \
|
||||
((struct block_header*)(((sljit_u8*)base) + offset))
|
||||
#define AS_FREE_BLOCK(base, offset) \
|
||||
((struct free_block*)(((sljit_u8*)base) + offset))
|
||||
#define MEM_START(base) ((void*)(((sljit_u8*)base) + sizeof(struct block_header)))
|
||||
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
|
||||
|
||||
static struct free_block* free_blocks;
|
||||
static sljit_uw allocated_size;
|
||||
static sljit_uw total_size;
|
||||
|
||||
static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
|
||||
{
|
||||
free_block->header.size = 0;
|
||||
free_block->size = size;
|
||||
|
||||
free_block->next = free_blocks;
|
||||
free_block->prev = NULL;
|
||||
if (free_blocks)
|
||||
free_blocks->prev = free_block;
|
||||
free_blocks = free_block;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
|
||||
{
|
||||
if (free_block->next)
|
||||
free_block->next->prev = free_block->prev;
|
||||
|
||||
if (free_block->prev)
|
||||
free_block->prev->next = free_block->next;
|
||||
else {
|
||||
SLJIT_ASSERT(free_blocks == free_block);
|
||||
free_blocks = free_block->next;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct block_header *next_header;
|
||||
struct free_block *free_block;
|
||||
sljit_uw chunk_size;
|
||||
|
||||
allocator_grab_lock();
|
||||
if (size < (64 - sizeof(struct block_header)))
|
||||
size = (64 - sizeof(struct block_header));
|
||||
size = ALIGN_SIZE(size);
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
if (free_block->size >= size) {
|
||||
chunk_size = free_block->size;
|
||||
if (chunk_size > size + 64) {
|
||||
/* We just cut a block from the end of the free block. */
|
||||
chunk_size -= size;
|
||||
free_block->size = chunk_size;
|
||||
header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
header->prev_size = chunk_size;
|
||||
AS_BLOCK_HEADER(header, size)->prev_size = size;
|
||||
}
|
||||
else {
|
||||
sljit_remove_free_block(free_block);
|
||||
header = (struct block_header*)free_block;
|
||||
size = chunk_size;
|
||||
}
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
free_block = free_block->next;
|
||||
}
|
||||
|
||||
chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
|
||||
header = (struct block_header*)alloc_chunk(chunk_size);
|
||||
if (!header) {
|
||||
allocator_release_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunk_size -= sizeof(struct block_header);
|
||||
total_size += chunk_size;
|
||||
|
||||
header->prev_size = 0;
|
||||
if (chunk_size > size + 64) {
|
||||
/* Cut the allocated space into a free and a used block. */
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
chunk_size -= size;
|
||||
|
||||
free_block = AS_FREE_BLOCK(header, size);
|
||||
free_block->header.prev_size = size;
|
||||
sljit_insert_free_block(free_block, chunk_size);
|
||||
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
}
|
||||
else {
|
||||
/* All space belongs to this allocation. */
|
||||
allocated_size += chunk_size;
|
||||
header->size = chunk_size;
|
||||
next_header = AS_BLOCK_HEADER(header, chunk_size);
|
||||
}
|
||||
next_header->size = 1;
|
||||
next_header->prev_size = chunk_size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct free_block* free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
|
||||
allocated_size -= header->size;
|
||||
|
||||
/* Connecting free blocks together if possible. */
|
||||
|
||||
/* If header->prev_size == 0, free_block will equal to header.
|
||||
In this case, free_block->header.size will be > 0. */
|
||||
free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
|
||||
if (SLJIT_UNLIKELY(!free_block->header.size)) {
|
||||
free_block->size += header->size;
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
else {
|
||||
free_block = (struct free_block*)header;
|
||||
sljit_insert_free_block(free_block, header->size);
|
||||
}
|
||||
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
if (SLJIT_UNLIKELY(!header->size)) {
|
||||
free_block->size += ((struct free_block*)header)->size;
|
||||
sljit_remove_free_block((struct free_block*)header);
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
|
||||
/* The whole chunk is free. */
|
||||
if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
|
||||
/* If this block is freed, we still have (allocated_size / 2) free space. */
|
||||
if (total_size - free_block->size > (allocated_size * 3 / 2)) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
}
|
||||
|
||||
allocator_release_lock();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
|
||||
{
|
||||
struct free_block* free_block;
|
||||
struct free_block* next_free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
next_free_block = free_block->next;
|
||||
if (!free_block->header.prev_size &&
|
||||
AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
free_block = next_free_block;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
|
||||
allocator_release_lock();
|
||||
}
|
||||
+2667
File diff suppressed because it is too large
Load Diff
+1493
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
/* mips 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
|
||||
{
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm < 0 && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
#define EMIT_SHIFT(op_imm, op_v) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
|
||||
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst));
|
||||
#endif
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst));
|
||||
#endif
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
|
||||
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
|
||||
}
|
||||
/* Nearly all instructions are unmovable in the following sequence. */
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
/* Check zero. */
|
||||
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst) | IMM(-1), DR(dst)));
|
||||
/* Loop for searching the highest bit. */
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1) || (defined SLJIT_MIPS_R6 && SLJIT_MIPS_R6)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
#else /* !SLJIT_MIPS_R1 && !SLJIT_MIPS_R6 */
|
||||
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#endif /* SLJIT_MIPS_R1 || SLJIT_MIPS_R6 */
|
||||
}
|
||||
#if (defined SLJIT_MIPS_R6 && SLJIT_MIPS_R6)
|
||||
FAIL_IF(push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, MUH | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
#else /* !SLJIT_MIPS_R6 */
|
||||
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
#endif /* SLJIT_MIPS_R6 */
|
||||
FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SUBU | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_OR:
|
||||
EMIT_LOGICAL(ORI, OR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_XOR:
|
||||
EMIT_LOGICAL(XORI, XOR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_SHL:
|
||||
EMIT_SHIFT(SLL, SLLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_LSHR:
|
||||
EMIT_SHIFT(SRL, SRLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ASHR:
|
||||
EMIT_SHIFT(SRA, SRAV);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr)
|
||||
{
|
||||
sljit_s32 stack_offset = 0;
|
||||
sljit_s32 arg_count = 0;
|
||||
sljit_s32 float_arg_count = 0;
|
||||
sljit_s32 word_arg_count = 0;
|
||||
sljit_s32 types = 0;
|
||||
sljit_s32 arg_count_save, types_save;
|
||||
sljit_ins prev_ins = NOP;
|
||||
sljit_ins ins = NOP;
|
||||
sljit_u8 offsets[4];
|
||||
|
||||
SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
|
||||
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
offsets[arg_count] = (sljit_u8)stack_offset;
|
||||
|
||||
if (word_arg_count == 0 && arg_count <= 1)
|
||||
offsets[arg_count] = 254 + arg_count;
|
||||
|
||||
stack_offset += sizeof(sljit_f32);
|
||||
arg_count++;
|
||||
float_arg_count++;
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
if (stack_offset & 0x7)
|
||||
stack_offset += sizeof(sljit_sw);
|
||||
offsets[arg_count] = (sljit_u8)stack_offset;
|
||||
|
||||
if (word_arg_count == 0 && arg_count <= 1)
|
||||
offsets[arg_count] = 254 + arg_count;
|
||||
|
||||
stack_offset += sizeof(sljit_f64);
|
||||
arg_count++;
|
||||
float_arg_count++;
|
||||
break;
|
||||
default:
|
||||
offsets[arg_count] = (sljit_u8)stack_offset;
|
||||
stack_offset += sizeof(sljit_sw);
|
||||
arg_count++;
|
||||
word_arg_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
/* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
|
||||
if (stack_offset > 16)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-16), DR(SLJIT_SP)));
|
||||
|
||||
types_save = types;
|
||||
arg_count_save = arg_count;
|
||||
|
||||
while (types) {
|
||||
switch (types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
arg_count--;
|
||||
if (offsets[arg_count] < 254)
|
||||
ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(offsets[arg_count]);
|
||||
float_arg_count--;
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
arg_count--;
|
||||
if (offsets[arg_count] < 254)
|
||||
ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(offsets[arg_count]);
|
||||
float_arg_count--;
|
||||
break;
|
||||
default:
|
||||
if (offsets[arg_count - 1] >= 16)
|
||||
ins = SW | S(SLJIT_SP) | T(word_arg_count) | IMM(offsets[arg_count - 1]);
|
||||
else if (arg_count != word_arg_count)
|
||||
ins = ADDU | S(word_arg_count) | TA(0) | DA(4 + (offsets[arg_count - 1] >> 2));
|
||||
else if (arg_count == 1)
|
||||
ins = ADDU | S(SLJIT_R0) | TA(0) | DA(4);
|
||||
|
||||
arg_count--;
|
||||
word_arg_count--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ins != NOP) {
|
||||
if (prev_ins != NOP)
|
||||
FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
|
||||
prev_ins = ins;
|
||||
ins = NOP;
|
||||
}
|
||||
|
||||
types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
types = types_save;
|
||||
arg_count = arg_count_save;
|
||||
|
||||
while (types) {
|
||||
switch (types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
arg_count--;
|
||||
if (offsets[arg_count] == 254)
|
||||
ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
|
||||
else if (offsets[arg_count] < 16)
|
||||
ins = LW | S(SLJIT_SP) | TA(4 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count]);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
arg_count--;
|
||||
if (offsets[arg_count] == 254)
|
||||
ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
|
||||
else if (offsets[arg_count] < 16) {
|
||||
if (prev_ins != NOP)
|
||||
FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
|
||||
prev_ins = LW | S(SLJIT_SP) | TA(4 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count]);
|
||||
ins = LW | S(SLJIT_SP) | TA(5 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count] + sizeof(sljit_sw));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
arg_count--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ins != NOP) {
|
||||
if (prev_ins != NOP)
|
||||
FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
|
||||
prev_ins = ins;
|
||||
ins = NOP;
|
||||
}
|
||||
|
||||
types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
*ins_ptr = prev_ins;
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_s32 post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
|
||||
{
|
||||
sljit_s32 stack_offset = 0;
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
stack_offset += sizeof(sljit_f32);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
if (stack_offset & 0x7)
|
||||
stack_offset += sizeof(sljit_sw);
|
||||
stack_offset += sizeof(sljit_f64);
|
||||
break;
|
||||
default:
|
||||
stack_offset += sizeof(sljit_sw);
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
/* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
|
||||
if (stack_offset > 16)
|
||||
return push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(16), DR(SLJIT_SP));
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_ins ins;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
|
||||
type &= 0xff;
|
||||
|
||||
PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins));
|
||||
|
||||
SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
|
||||
|
||||
PTR_FAIL_IF(emit_const(compiler, PIC_ADDR_REG, 0));
|
||||
|
||||
jump->flags |= IS_JAL | IS_CALL;
|
||||
PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
|
||||
jump->addr = compiler->size;
|
||||
PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
|
||||
|
||||
PTR_FAIL_IF(post_call_with_args(compiler, arg_types));
|
||||
|
||||
return jump;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_ins ins;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
|
||||
|
||||
SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
|
||||
|
||||
if (src & SLJIT_IMM)
|
||||
FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
|
||||
else if (FAST_IS_REG(src))
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
|
||||
else if (src & SLJIT_MEM) {
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));
|
||||
}
|
||||
|
||||
FAIL_IF(call_with_args(compiler, arg_types, &ins));
|
||||
|
||||
/* Register input. */
|
||||
FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
|
||||
return post_call_with_args(compiler, arg_types);
|
||||
}
|
||||
@@ -0,0 +1,675 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
/* mips 64-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
|
||||
{
|
||||
sljit_s32 shift = 32;
|
||||
sljit_s32 shift2;
|
||||
sljit_s32 inv = 0;
|
||||
sljit_ins ins;
|
||||
sljit_uw uimm;
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm < 0 && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Zero extended number. */
|
||||
uimm = imm;
|
||||
if (imm < 0) {
|
||||
uimm = ~imm;
|
||||
inv = 1;
|
||||
}
|
||||
|
||||
while (!(uimm & 0xff00000000000000l)) {
|
||||
shift -= 8;
|
||||
uimm <<= 8;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xf000000000000000l)) {
|
||||
shift -= 4;
|
||||
uimm <<= 4;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xc000000000000000l)) {
|
||||
shift -= 2;
|
||||
uimm <<= 2;
|
||||
}
|
||||
|
||||
if ((sljit_sw)uimm < 0) {
|
||||
uimm >>= 1;
|
||||
shift += 1;
|
||||
}
|
||||
SLJIT_ASSERT(((uimm & 0xc000000000000000l) == 0x4000000000000000l) && (shift > 0) && (shift <= 32));
|
||||
|
||||
if (inv)
|
||||
uimm = ~uimm;
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
|
||||
if (uimm & 0x0000ffff00000000l)
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 32), dst_ar));
|
||||
|
||||
imm &= (1l << shift) - 1;
|
||||
if (!(imm & ~0xffff)) {
|
||||
ins = (shift == 32) ? DSLL32 : DSLL;
|
||||
if (shift < 32)
|
||||
ins |= SH_IMM(shift);
|
||||
FAIL_IF(push_inst(compiler, ins | TA(dst_ar) | DA(dst_ar), dst_ar));
|
||||
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
}
|
||||
|
||||
/* Double shifts needs to be performed. */
|
||||
uimm <<= 32;
|
||||
shift2 = shift - 16;
|
||||
|
||||
while (!(uimm & 0xf000000000000000l)) {
|
||||
shift2 -= 4;
|
||||
uimm <<= 4;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xc000000000000000l)) {
|
||||
shift2 -= 2;
|
||||
uimm <<= 2;
|
||||
}
|
||||
|
||||
if (!(uimm & 0x8000000000000000l)) {
|
||||
shift2--;
|
||||
uimm <<= 1;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((uimm & 0x8000000000000000l) && (shift2 > 0) && (shift2 <= 16));
|
||||
|
||||
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift - shift2), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift2), dst_ar));
|
||||
|
||||
imm &= (1l << shift2) - 1;
|
||||
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
}
|
||||
|
||||
#define SELECT_OP(a, b) \
|
||||
(!(op & SLJIT_I32_OP) ? a : b)
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
#define EMIT_SHIFT(op_dimm, op_dimm32, op_imm, op_dv, op_v) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (src2 >= 32) { \
|
||||
SLJIT_ASSERT(!(op & SLJIT_I32_OP)); \
|
||||
ins = op_dimm32; \
|
||||
src2 -= 32; \
|
||||
} \
|
||||
else \
|
||||
ins = (op & SLJIT_I32_OP) ? op_imm : op_dimm; \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
ins = (op & SLJIT_I32_OP) ? op_v : op_dv; \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_ins ins;
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8) {
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
|
||||
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16) {
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U32:
|
||||
SLJIT_ASSERT(!(op & SLJIT_I32_OP));
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
|
||||
return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
|
||||
|
||||
case SLJIT_MOV_S32:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst));
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
|
||||
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
|
||||
}
|
||||
/* Nearly all instructions are unmovable in the following sequence. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
/* Check zero. */
|
||||
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_I32_OP) ? 32 : 64), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(dst) | IMM(-1), DR(dst)));
|
||||
/* Loop for searching the highest bit. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL, SLL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R6 && SLJIT_MIPS_R6)
|
||||
return push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
#elif (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_I32_OP)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#else /* !SLJIT_MIPS_R6 && !SLJIT_MIPS_R1 */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#endif /* SLJIT_MIPS_R6 */
|
||||
}
|
||||
#if (defined SLJIT_MIPS_R6 && SLJIT_MIPS_R6)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMUH, MUH) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
#else /* !SLJIT_MIPS_R6 */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
#endif /* SLJIT_MIPS_R6 */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_OR:
|
||||
EMIT_LOGICAL(ORI, OR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_XOR:
|
||||
EMIT_LOGICAL(XORI, XOR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_SHL:
|
||||
EMIT_SHIFT(DSLL, DSLL32, SLL, DSLLV, SLLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_LSHR:
|
||||
EMIT_SHIFT(DSRL, DSRL32, SRL, DSRLV, SRLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ASHR:
|
||||
EMIT_SHIFT(DSRA, DSRA32, SRA, DSRAV, SRAV);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 16), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
|
||||
static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr)
|
||||
{
|
||||
sljit_s32 arg_count = 0;
|
||||
sljit_s32 word_arg_count = 0;
|
||||
sljit_s32 float_arg_count = 0;
|
||||
sljit_s32 types = 0;
|
||||
sljit_ins prev_ins = NOP;
|
||||
sljit_ins ins = NOP;
|
||||
|
||||
SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
|
||||
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
arg_count++;
|
||||
float_arg_count++;
|
||||
break;
|
||||
default:
|
||||
arg_count++;
|
||||
word_arg_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
while (types) {
|
||||
switch (types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
if (arg_count != float_arg_count)
|
||||
ins = MOV_S | FMT_S | FS(float_arg_count) | FD(arg_count);
|
||||
else if (arg_count == 1)
|
||||
ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
|
||||
arg_count--;
|
||||
float_arg_count--;
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
if (arg_count != float_arg_count)
|
||||
ins = MOV_S | FMT_D | FS(float_arg_count) | FD(arg_count);
|
||||
else if (arg_count == 1)
|
||||
ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
|
||||
arg_count--;
|
||||
float_arg_count--;
|
||||
break;
|
||||
default:
|
||||
if (arg_count != word_arg_count)
|
||||
ins = DADDU | S(word_arg_count) | TA(0) | D(arg_count);
|
||||
else if (arg_count == 1)
|
||||
ins = DADDU | S(SLJIT_R0) | TA(0) | DA(4);
|
||||
arg_count--;
|
||||
word_arg_count--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ins != NOP) {
|
||||
if (prev_ins != NOP)
|
||||
FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
|
||||
prev_ins = ins;
|
||||
ins = NOP;
|
||||
}
|
||||
|
||||
types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
*ins_ptr = prev_ins;
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_ins ins;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
|
||||
type &= 0xff;
|
||||
|
||||
PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins));
|
||||
|
||||
SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
|
||||
|
||||
PTR_FAIL_IF(emit_const(compiler, PIC_ADDR_REG, 0));
|
||||
|
||||
jump->flags |= IS_JAL | IS_CALL;
|
||||
PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
|
||||
jump->addr = compiler->size;
|
||||
PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
|
||||
|
||||
return jump;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_ins ins;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
|
||||
|
||||
SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
|
||||
|
||||
if (src & SLJIT_IMM)
|
||||
FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
|
||||
else if (FAST_IS_REG(src))
|
||||
FAIL_IF(push_inst(compiler, DADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
|
||||
else if (src & SLJIT_MEM) {
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));
|
||||
}
|
||||
|
||||
FAIL_IF(call_with_args(compiler, arg_types, &ins));
|
||||
|
||||
/* Register input. */
|
||||
FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
|
||||
return push_inst(compiler, ins, UNMOVABLE_INS);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
/* ppc 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
|
||||
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define INS_CLEAR_LEFT(dst, src, from) \
|
||||
(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
|
||||
{
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
|
||||
}
|
||||
else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16)
|
||||
return push_inst(compiler, EXTSH | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, NEG | OE((flags & ALT_FORM1) ? ALT_SET_FLAGS : 0) | RC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, CNTLZW | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
|
||||
if (flags & ALT_FORM3)
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1))));
|
||||
src1 = dst;
|
||||
}
|
||||
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
if (flags & ALT_FORM4)
|
||||
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
if (flags & ALT_FORM2) {
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0) | A(src1) | compiler->imm));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0) | A(src1) | B(src2)));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM3) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
if (flags & ALT_FORM5) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2));
|
||||
}
|
||||
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
if (flags & ALT_FORM5)
|
||||
return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, SUBF | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_MUL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_OR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_XOR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_SHL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
|
||||
}
|
||||
return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_LSHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
|
||||
}
|
||||
return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDIS && (inst[1] & 0xfc000000) == ORI);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDIS && (inst[1] & 0xfc000000) == ORI);
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
/* ppc 64-bit arch dependent functions. */
|
||||
|
||||
#if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
|
||||
#define ASM_SLJIT_CLZ(src, dst) \
|
||||
__asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) )
|
||||
#elif defined(__xlc__)
|
||||
#error "Please enable GCC syntax for inline assembly statements"
|
||||
#else
|
||||
#error "Must implement count leading zeroes"
|
||||
#endif
|
||||
|
||||
#define PUSH_RLDICR(reg, shift) \
|
||||
push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
sljit_uw tmp;
|
||||
sljit_uw shift;
|
||||
sljit_uw tmp2;
|
||||
sljit_uw shift2;
|
||||
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
|
||||
|
||||
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Count leading zeroes. */
|
||||
tmp = (imm >= 0) ? imm : ~imm;
|
||||
ASM_SLJIT_CLZ(tmp, shift);
|
||||
SLJIT_ASSERT(shift > 0);
|
||||
shift--;
|
||||
tmp = (imm << shift);
|
||||
|
||||
if ((tmp & ~0xffff000000000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
shift += 15;
|
||||
return PUSH_RLDICR(reg, shift);
|
||||
}
|
||||
|
||||
if ((tmp & ~0xffffffff00000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp >> 32)));
|
||||
shift += 31;
|
||||
return PUSH_RLDICR(reg, shift);
|
||||
}
|
||||
|
||||
/* Cut out the 16 bit from immediate. */
|
||||
shift += 15;
|
||||
tmp2 = imm & ((1ul << (63 - shift)) - 1);
|
||||
|
||||
if (tmp2 <= 0xffff) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | tmp2);
|
||||
}
|
||||
|
||||
if (tmp2 <= 0xffffffff) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | (tmp2 >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp2)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
ASM_SLJIT_CLZ(tmp2, shift2);
|
||||
tmp2 <<= shift2;
|
||||
|
||||
if ((tmp2 & ~0xffff000000000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
shift2 += 15;
|
||||
shift += (63 - shift2);
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | (tmp2 >> 48)));
|
||||
return PUSH_RLDICR(reg, shift2);
|
||||
}
|
||||
|
||||
/* The general version. */
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm >> 32)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, 31));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(imm >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm));
|
||||
}
|
||||
|
||||
/* Simplified mnemonics: clrldi. */
|
||||
#define INS_CLEAR_LEFT(dst, src, from) \
|
||||
(RLDICL | S(src) | A(dst) | ((from) << 6) | (1 << 5))
|
||||
|
||||
/* Sign extension for integer operations. */
|
||||
#define UN_EXTS() \
|
||||
if ((flags & (ALT_SIGN_EXT | REG2_SOURCE)) == (ALT_SIGN_EXT | REG2_SOURCE)) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
|
||||
src2 = TMP_REG2; \
|
||||
}
|
||||
|
||||
#define BIN_EXTS() \
|
||||
if (flags & ALT_SIGN_EXT) { \
|
||||
if (flags & REG1_SOURCE) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
|
||||
src1 = TMP_REG1; \
|
||||
} \
|
||||
if (flags & REG2_SOURCE) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
|
||||
src2 = TMP_REG2; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define BIN_IMM_EXTS() \
|
||||
if ((flags & (ALT_SIGN_EXT | REG1_SOURCE)) == (ALT_SIGN_EXT | REG1_SOURCE)) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
|
||||
src1 = TMP_REG1; \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
|
||||
{
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S32)
|
||||
return push_inst(compiler, EXTSW | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
|
||||
}
|
||||
else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16)
|
||||
return push_inst(compiler, EXTSH | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
UN_EXTS();
|
||||
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
|
||||
if ((flags & (ALT_FORM1 | ALT_SIGN_EXT)) == (ALT_FORM1 | ALT_SIGN_EXT)) {
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
|
||||
FAIL_IF(push_inst(compiler, NEG | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(TMP_REG2)));
|
||||
return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
|
||||
}
|
||||
|
||||
UN_EXTS();
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
return push_inst(compiler, NEG | OE((flags & ALT_FORM1) ? ALT_SET_FLAGS : 0) | RC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (flags & ALT_FORM1)
|
||||
return push_inst(compiler, CNTLZW | S(src2) | A(dst));
|
||||
return push_inst(compiler, CNTLZD | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
if (flags & ALT_SIGN_EXT) {
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
|
||||
src1 = TMP_REG1;
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
|
||||
src2 = TMP_REG2;
|
||||
}
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
FAIL_IF(push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)));
|
||||
if (flags & ALT_SIGN_EXT)
|
||||
return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
|
||||
if (flags & ALT_FORM3)
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1))));
|
||||
src1 = dst;
|
||||
}
|
||||
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
BIN_IMM_EXTS();
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
BIN_EXTS();
|
||||
if (flags & ALT_FORM4)
|
||||
return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
if (flags & ALT_FORM2) {
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
|
||||
if (!(flags & ALT_FORM3))
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM2) {
|
||||
if (flags & ALT_SIGN_EXT) {
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
|
||||
src1 = TMP_REG1;
|
||||
FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
|
||||
src2 = TMP_REG2;
|
||||
}
|
||||
/* Setting XER SO is not enough, CR SO is also needed. */
|
||||
FAIL_IF(push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)));
|
||||
if (flags & ALT_SIGN_EXT)
|
||||
return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM3) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
|
||||
if (flags & ALT_FORM4) {
|
||||
if (flags & ALT_FORM5) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
|
||||
}
|
||||
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
BIN_EXTS();
|
||||
if (flags & ALT_FORM5)
|
||||
return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, SUBF | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_MUL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
BIN_EXTS();
|
||||
if (flags & ALT_FORM2)
|
||||
return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, MULLD | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_OR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_XOR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_SHL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_LSHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src)
|
||||
{
|
||||
sljit_s32 arg_count = 0;
|
||||
sljit_s32 word_arg_count = 0;
|
||||
sljit_s32 types = 0;
|
||||
sljit_s32 reg = 0;
|
||||
|
||||
if (src)
|
||||
reg = *src & REG_MASK;
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
|
||||
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
arg_count++;
|
||||
break;
|
||||
default:
|
||||
arg_count++;
|
||||
word_arg_count++;
|
||||
|
||||
if (arg_count != word_arg_count && arg_count == reg) {
|
||||
FAIL_IF(push_inst(compiler, OR | S(reg) | A(TMP_CALL_REG) | B(reg)));
|
||||
*src = TMP_CALL_REG;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
while (types) {
|
||||
switch (types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
arg_count--;
|
||||
break;
|
||||
default:
|
||||
if (arg_count != word_arg_count)
|
||||
FAIL_IF(push_inst(compiler, OR | S(word_arg_count) | A(arg_count) | B(word_arg_count)));
|
||||
|
||||
arg_count--;
|
||||
word_arg_count--;
|
||||
break;
|
||||
}
|
||||
|
||||
types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, 31));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(init_value >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw imm)
|
||||
{
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((imm >> 10) & 0x3fffff), DR(dst)));
|
||||
return (imm & 0x3ff) ? push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (imm & 0x3ff), DR(dst)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
SLJIT_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
|
||||
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_U8)
|
||||
return push_inst(compiler, AND | D(dst) | S1(src2) | IMM(0xff), DR(dst));
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(24), DR(dst)));
|
||||
return push_inst(compiler, SRA | D(dst) | S1(dst) | IMM(24), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(16), DR(dst)));
|
||||
return push_inst(compiler, (op == SLJIT_MOV_S16 ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
return push_inst(compiler, XNOR | (flags & SET_FLAGS) | D(dst) | S1(0) | S2(src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(src2) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2(src2), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0x1) | (7 & DISP_MASK), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(-1), DR(dst)));
|
||||
|
||||
/* Loop. */
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, SLL | D(TMP_REG1) | S1(TMP_REG1) | IMM(1), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0xe) | (-2 & DISP_MASK), UNMOVABLE_INS));
|
||||
return push_inst(compiler, ADD | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS);
|
||||
|
||||
case SLJIT_ADD:
|
||||
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SUB:
|
||||
return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_MUL:
|
||||
FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
if (!(flags & SET_FLAGS))
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(dst) | IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, RDY | D(TMP_LINK), DR(TMP_LINK)));
|
||||
return push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(TMP_LINK), MOVABLE_INS | SET_FLAGS);
|
||||
|
||||
case SLJIT_AND:
|
||||
return push_inst(compiler, AND | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_OR:
|
||||
return push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_XOR:
|
||||
return push_inst(compiler, XOR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SHL:
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
|
||||
case SLJIT_LSHR:
|
||||
FAIL_IF(push_inst(compiler, SRL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
|
||||
case SLJIT_ASHR:
|
||||
FAIL_IF(push_inst(compiler, SRA | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src)
|
||||
{
|
||||
sljit_s32 reg_index = 8;
|
||||
sljit_s32 word_reg_index = 8;
|
||||
sljit_s32 float_arg_index = 1;
|
||||
sljit_s32 double_arg_count = 0;
|
||||
sljit_s32 float_offset = (16 + 6) * sizeof(sljit_sw);
|
||||
sljit_s32 types = 0;
|
||||
sljit_s32 reg = 0;
|
||||
sljit_s32 move_to_tmp2 = 0;
|
||||
|
||||
if (src)
|
||||
reg = reg_map[*src & REG_MASK];
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
|
||||
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
float_arg_index++;
|
||||
if (reg_index == reg)
|
||||
move_to_tmp2 = 1;
|
||||
reg_index++;
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
float_arg_index++;
|
||||
double_arg_count++;
|
||||
if (reg_index == reg || reg_index + 1 == reg)
|
||||
move_to_tmp2 = 1;
|
||||
reg_index += 2;
|
||||
break;
|
||||
default:
|
||||
if (reg_index != word_reg_index && reg_index < 14 && reg_index == reg)
|
||||
move_to_tmp2 = 1;
|
||||
reg_index++;
|
||||
word_reg_index++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (move_to_tmp2) {
|
||||
move_to_tmp2 = 0;
|
||||
if (reg < 14)
|
||||
FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2A(reg), DR(TMP_REG1)));
|
||||
*src = TMP_REG1;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
arg_types = types;
|
||||
|
||||
while (arg_types) {
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
float_arg_index--;
|
||||
FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
|
||||
float_offset -= sizeof(sljit_f64);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
float_arg_index--;
|
||||
if (float_arg_index == 4 && double_arg_count == 4) {
|
||||
FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | S1(SLJIT_SP) | IMM((16 + 7) * sizeof(sljit_sw)), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | (1 << 25) | S1(SLJIT_SP) | IMM((16 + 8) * sizeof(sljit_sw)), MOVABLE_INS));
|
||||
}
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, STDF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
|
||||
float_offset -= sizeof(sljit_f64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
float_offset = (16 + 6) * sizeof(sljit_sw);
|
||||
|
||||
while (types) {
|
||||
switch (types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
reg_index--;
|
||||
if (reg_index < 14)
|
||||
FAIL_IF(push_inst(compiler, LDUW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
|
||||
float_offset -= sizeof(sljit_f64);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
reg_index -= 2;
|
||||
if (reg_index < 14) {
|
||||
if ((reg_index & 0x1) != 0) {
|
||||
FAIL_IF(push_inst(compiler, LDUW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
|
||||
if (reg_index < 13)
|
||||
FAIL_IF(push_inst(compiler, LDUW | DA(reg_index + 1) | S1(SLJIT_SP) | IMM(float_offset + sizeof(sljit_sw)), reg_index + 1));
|
||||
}
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, LDD | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
|
||||
}
|
||||
float_offset -= sizeof(sljit_f64);
|
||||
break;
|
||||
default:
|
||||
reg_index--;
|
||||
word_reg_index--;
|
||||
|
||||
if (reg_index != word_reg_index) {
|
||||
if (reg_index < 14)
|
||||
FAIL_IF(push_inst(compiler, OR | DA(reg_index) | S1(0) | S2A(word_reg_index), reg_index));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, STW | DA(word_reg_index) | S1(SLJIT_SP) | IMM(92), word_reg_index));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((init_value >> 10) & 0x3fffff), DR(dst)));
|
||||
return push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (init_value & 0x3ff), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
SLJIT_ASSERT(((inst[0] & 0xc1c00000) == 0x01000000) && ((inst[1] & 0xc1f82000) == 0x80102000));
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_target >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_target & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
SLJIT_ASSERT(((inst[0] & 0xc1c00000) == 0x01000000) && ((inst[1] & 0xc1f82000) == 0x80102000));
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_constant >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_constant & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,896 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
/* x86 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1 + sizeof(sljit_sw));
|
||||
*inst++ = opcode;
|
||||
sljit_unaligned_store_sw(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_s32 type = jump->flags >> TYPE_SHIFT;
|
||||
|
||||
if (type == SLJIT_JUMP) {
|
||||
*code_ptr++ = JMP_i32;
|
||||
jump->addr++;
|
||||
}
|
||||
else if (type >= SLJIT_FAST_CALL) {
|
||||
*code_ptr++ = CALL_i32;
|
||||
jump->addr++;
|
||||
}
|
||||
else {
|
||||
*code_ptr++ = GROUP_0F;
|
||||
*code_ptr++ = get_jump_code(type);
|
||||
jump->addr += 2;
|
||||
}
|
||||
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
jump->flags |= PATCH_MW;
|
||||
else
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset);
|
||||
code_ptr += 4;
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 args, size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
args = get_arg_count(arg_types);
|
||||
compiler->args = args;
|
||||
|
||||
/* [esp+0] for saving temporaries and function calls. */
|
||||
compiler->stack_tmp_size = 2 * sizeof(sljit_sw);
|
||||
|
||||
#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (scratches > 3)
|
||||
compiler->stack_tmp_size = 3 * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
compiler->saveds_offset = compiler->stack_tmp_size;
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
size = 1 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
size += (args > 0 ? (args * 2) : 0) + (args > 2 ? 2 : 0);
|
||||
#else
|
||||
size += (args > 0 ? (2 + args * 3) : 0);
|
||||
#endif
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
PUSH_REG(reg_map[TMP_REG1]);
|
||||
#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (args > 0) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[TMP_REG1] << 3) | 0x4 /* esp */;
|
||||
}
|
||||
#endif
|
||||
if (saveds > 2 || scratches > 9)
|
||||
PUSH_REG(reg_map[SLJIT_S2]);
|
||||
if (saveds > 1 || scratches > 10)
|
||||
PUSH_REG(reg_map[SLJIT_S1]);
|
||||
if (saveds > 0 || scratches > 11)
|
||||
PUSH_REG(reg_map[SLJIT_S0]);
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (args > 0) {
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = MOD_REG | (reg_map[SLJIT_S0] << 3) | reg_map[SLJIT_R2];
|
||||
inst += 2;
|
||||
}
|
||||
if (args > 1) {
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = MOD_REG | (reg_map[SLJIT_S1] << 3) | reg_map[SLJIT_R1];
|
||||
inst += 2;
|
||||
}
|
||||
if (args > 2) {
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | 0x4 /* esp */;
|
||||
inst[2] = 0x24;
|
||||
inst[3] = sizeof(sljit_sw) * (3 + 2); /* saveds >= 3 as well. */
|
||||
}
|
||||
#else
|
||||
if (args > 0) {
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = MOD_DISP8 | (reg_map[SLJIT_S0] << 3) | reg_map[TMP_REG1];
|
||||
inst[2] = sizeof(sljit_sw) * 2;
|
||||
inst += 3;
|
||||
}
|
||||
if (args > 1) {
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = MOD_DISP8 | (reg_map[SLJIT_S1] << 3) | reg_map[TMP_REG1];
|
||||
inst[2] = sizeof(sljit_sw) * 3;
|
||||
inst += 3;
|
||||
}
|
||||
if (args > 2) {
|
||||
inst[0] = MOV_r_rm;
|
||||
inst[1] = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | reg_map[TMP_REG1];
|
||||
inst[2] = sizeof(sljit_sw) * 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(SLJIT_LOCALS_OFFSET > 0);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Ignore pushed registers and SLJIT_LOCALS_OFFSET when computing the aligned local size. */
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
|
||||
compiler->local_size = local_size;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (local_size > 0) {
|
||||
if (local_size <= 4 * 4096) {
|
||||
if (local_size > 4096)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096);
|
||||
if (local_size > 2 * 4096)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 2);
|
||||
if (local_size > 3 * 4096)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 3);
|
||||
}
|
||||
else {
|
||||
EMIT_MOV(compiler, SLJIT_R0, 0, SLJIT_SP, 0);
|
||||
EMIT_MOV(compiler, SLJIT_R1, 0, SLJIT_IMM, (local_size - 1) >> 12);
|
||||
|
||||
SLJIT_ASSERT (reg_map[SLJIT_R0] == 0);
|
||||
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_R0), -4096);
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 4096));
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1));
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(2);
|
||||
inst[0] = JNE_i8;
|
||||
inst[1] = (sljit_s8) -16;
|
||||
}
|
||||
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -local_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(local_size > 0);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (options & SLJIT_F64_ALIGNMENT) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_SP, 0);
|
||||
|
||||
/* Some space might allocated during sljit_grow_stack() above on WIN32. */
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size + sizeof(sljit_sw)));
|
||||
|
||||
#if defined _WIN32 && !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->local_size > 1024)
|
||||
FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
|
||||
TMP_REG1, 0, TMP_REG1, 0, SLJIT_IMM, sizeof(sljit_sw)));
|
||||
#endif
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 6);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(6);
|
||||
inst[0] = GROUP_BINARY_81;
|
||||
inst[1] = MOD_REG | AND | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_sw(inst + 2, ~(sizeof(sljit_f64) - 1));
|
||||
|
||||
/* The real local size must be used. */
|
||||
return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), compiler->local_size, TMP_REG1, 0);
|
||||
}
|
||||
#endif
|
||||
return emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->args = get_arg_count(arg_types);
|
||||
|
||||
/* [esp+0] for saving temporaries and function calls. */
|
||||
compiler->stack_tmp_size = 2 * sizeof(sljit_sw);
|
||||
|
||||
#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (scratches > 3)
|
||||
compiler->stack_tmp_size = 3 * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
compiler->saveds_offset = compiler->stack_tmp_size;
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
compiler->local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
SLJIT_ASSERT(compiler->args >= 0);
|
||||
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
SLJIT_ASSERT(compiler->local_size > 0);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (compiler->options & SLJIT_F64_ALIGNMENT)
|
||||
EMIT_MOV(compiler, SLJIT_SP, 0, SLJIT_MEM1(SLJIT_SP), compiler->local_size)
|
||||
else
|
||||
FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#else
|
||||
FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#endif
|
||||
|
||||
size = 2 + (compiler->scratches > 7 ? (compiler->scratches - 7) : 0) +
|
||||
(compiler->saveds <= 3 ? compiler->saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->args > 2)
|
||||
size += 2;
|
||||
#else
|
||||
if (compiler->args > 0)
|
||||
size += 2;
|
||||
#endif
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
|
||||
if (compiler->saveds > 0 || compiler->scratches > 11)
|
||||
POP_REG(reg_map[SLJIT_S0]);
|
||||
if (compiler->saveds > 1 || compiler->scratches > 10)
|
||||
POP_REG(reg_map[SLJIT_S1]);
|
||||
if (compiler->saveds > 2 || compiler->scratches > 9)
|
||||
POP_REG(reg_map[SLJIT_S2]);
|
||||
POP_REG(reg_map[TMP_REG1]);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->args > 2)
|
||||
RET_I16(sizeof(sljit_sw));
|
||||
else
|
||||
RET();
|
||||
#else
|
||||
RET();
|
||||
#endif
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Size contains the flags as well. */
|
||||
static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
|
||||
/* The register or immediate operand. */
|
||||
sljit_s32 a, sljit_sw imma,
|
||||
/* The general operand (not immediate). */
|
||||
sljit_s32 b, sljit_sw immb)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_u8 *buf_ptr;
|
||||
sljit_s32 flags = size & ~0xf;
|
||||
sljit_s32 inst_size;
|
||||
|
||||
/* Both cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
|
||||
/* Size flags not allowed for typed instructions. */
|
||||
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
|
||||
/* Both size flags cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
|
||||
/* SSE2 and immediate is not possible. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
|
||||
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
|
||||
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
|
||||
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
|
||||
|
||||
size &= 0xf;
|
||||
inst_size = size;
|
||||
|
||||
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
|
||||
inst_size++;
|
||||
if (flags & EX86_PREF_66)
|
||||
inst_size++;
|
||||
|
||||
/* Calculate size of b. */
|
||||
inst_size += 1; /* mod r/m byte. */
|
||||
if (b & SLJIT_MEM) {
|
||||
if ((b & REG_MASK) == SLJIT_UNUSED)
|
||||
inst_size += sizeof(sljit_sw);
|
||||
else if (immb != 0 && !(b & OFFS_REG_MASK)) {
|
||||
/* Immediate operand. */
|
||||
if (immb <= 127 && immb >= -128)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else
|
||||
inst_size += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
if ((b & REG_MASK) == SLJIT_SP && !(b & OFFS_REG_MASK))
|
||||
b |= TO_OFFS_REG(SLJIT_SP);
|
||||
|
||||
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED)
|
||||
inst_size += 1; /* SIB byte. */
|
||||
}
|
||||
|
||||
/* Calculate size of a. */
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
}
|
||||
else if (flags & EX86_SHIFT_INS) {
|
||||
imma &= 0x1f;
|
||||
if (imma != 1) {
|
||||
inst_size ++;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
else
|
||||
inst_size += sizeof(sljit_sw);
|
||||
}
|
||||
else
|
||||
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
|
||||
PTR_FAIL_IF(!inst);
|
||||
|
||||
/* Encoding the byte. */
|
||||
INC_SIZE(inst_size);
|
||||
if (flags & EX86_PREF_F2)
|
||||
*inst++ = 0xf2;
|
||||
if (flags & EX86_PREF_F3)
|
||||
*inst++ = 0xf3;
|
||||
if (flags & EX86_PREF_66)
|
||||
*inst++ = 0x66;
|
||||
|
||||
buf_ptr = inst + size;
|
||||
|
||||
/* Encode mod/rm byte. */
|
||||
if (!(flags & EX86_SHIFT_INS)) {
|
||||
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
|
||||
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
|
||||
|
||||
if (a & SLJIT_IMM)
|
||||
*buf_ptr = 0;
|
||||
else if (!(flags & EX86_SSE2_OP1))
|
||||
*buf_ptr = reg_map[a] << 3;
|
||||
else
|
||||
*buf_ptr = a << 3;
|
||||
}
|
||||
else {
|
||||
if (a & SLJIT_IMM) {
|
||||
if (imma == 1)
|
||||
*inst = GROUP_SHIFT_1;
|
||||
else
|
||||
*inst = GROUP_SHIFT_N;
|
||||
} else
|
||||
*inst = GROUP_SHIFT_CL;
|
||||
*buf_ptr = 0;
|
||||
}
|
||||
|
||||
if (!(b & SLJIT_MEM))
|
||||
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_map[b] : b);
|
||||
else if ((b & REG_MASK) != SLJIT_UNUSED) {
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
|
||||
if (immb != 0) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr |= 0x40;
|
||||
else
|
||||
*buf_ptr |= 0x80;
|
||||
}
|
||||
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
|
||||
*buf_ptr++ |= reg_map[b & REG_MASK];
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3);
|
||||
}
|
||||
|
||||
if (immb != 0) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr++ = immb; /* 8 bit displacement. */
|
||||
else {
|
||||
sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3) | (immb << 6);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x05;
|
||||
sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BYTE_ARG)
|
||||
*buf_ptr = imma;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
sljit_unaligned_store_s16(buf_ptr, imma);
|
||||
else if (!(flags & EX86_SHIFT_INS))
|
||||
sljit_unaligned_store_sw(buf_ptr, imma);
|
||||
}
|
||||
|
||||
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Call / return instructions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
|
||||
static sljit_s32 c_fast_call_get_stack_size(sljit_s32 arg_types, sljit_s32 *word_arg_count_ptr)
|
||||
{
|
||||
sljit_s32 stack_size = 0;
|
||||
sljit_s32 word_arg_count = 0;
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
stack_size += sizeof(sljit_f32);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
stack_size += sizeof(sljit_f64);
|
||||
break;
|
||||
default:
|
||||
word_arg_count++;
|
||||
if (word_arg_count > 2)
|
||||
stack_size += sizeof(sljit_sw);
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
if (word_arg_count_ptr)
|
||||
*word_arg_count_ptr = word_arg_count;
|
||||
|
||||
return stack_size;
|
||||
}
|
||||
|
||||
static sljit_s32 c_fast_call_with_args(struct sljit_compiler *compiler,
|
||||
sljit_s32 arg_types, sljit_s32 stack_size, sljit_s32 word_arg_count, sljit_s32 swap_args)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_s32 float_arg_count;
|
||||
|
||||
if (stack_size == sizeof(sljit_sw) && word_arg_count == 3) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
PUSH_REG(reg_map[SLJIT_R2]);
|
||||
}
|
||||
else if (stack_size > 0) {
|
||||
if (word_arg_count >= 4)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), compiler->saveds_offset - sizeof(sljit_sw));
|
||||
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, stack_size));
|
||||
|
||||
stack_size = 0;
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
word_arg_count = 0;
|
||||
float_arg_count = 0;
|
||||
while (arg_types) {
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
float_arg_count++;
|
||||
FAIL_IF(emit_sse2_store(compiler, 1, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
|
||||
stack_size += sizeof(sljit_f32);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
float_arg_count++;
|
||||
FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
|
||||
stack_size += sizeof(sljit_f64);
|
||||
break;
|
||||
default:
|
||||
word_arg_count++;
|
||||
if (word_arg_count == 3) {
|
||||
EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), stack_size, SLJIT_R2, 0);
|
||||
stack_size += sizeof(sljit_sw);
|
||||
}
|
||||
else if (word_arg_count == 4) {
|
||||
EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), stack_size, TMP_REG1, 0);
|
||||
stack_size += sizeof(sljit_sw);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
if (word_arg_count > 0) {
|
||||
if (swap_args) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
|
||||
*inst++ = XCHG_EAX_r | reg_map[SLJIT_R2];
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(2);
|
||||
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_R2] << 3) | reg_map[SLJIT_R0];
|
||||
}
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static sljit_s32 cdecl_call_get_stack_size(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *word_arg_count_ptr)
|
||||
{
|
||||
sljit_s32 stack_size = 0;
|
||||
sljit_s32 word_arg_count = 0;
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
stack_size += sizeof(sljit_f32);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
stack_size += sizeof(sljit_f64);
|
||||
break;
|
||||
default:
|
||||
word_arg_count++;
|
||||
stack_size += sizeof(sljit_sw);
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
if (word_arg_count_ptr)
|
||||
*word_arg_count_ptr = word_arg_count;
|
||||
|
||||
if (stack_size <= compiler->stack_tmp_size)
|
||||
return 0;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
return ((stack_size - compiler->stack_tmp_size + 15) & ~15);
|
||||
#else
|
||||
return stack_size - compiler->stack_tmp_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
static sljit_s32 cdecl_call_with_args(struct sljit_compiler *compiler,
|
||||
sljit_s32 arg_types, sljit_s32 stack_size, sljit_s32 word_arg_count)
|
||||
{
|
||||
sljit_s32 float_arg_count = 0;
|
||||
|
||||
if (word_arg_count >= 4)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), compiler->saveds_offset - sizeof(sljit_sw));
|
||||
|
||||
if (stack_size > 0)
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, stack_size));
|
||||
|
||||
stack_size = 0;
|
||||
word_arg_count = 0;
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
float_arg_count++;
|
||||
FAIL_IF(emit_sse2_store(compiler, 1, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
|
||||
stack_size += sizeof(sljit_f32);
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
float_arg_count++;
|
||||
FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
|
||||
stack_size += sizeof(sljit_f64);
|
||||
break;
|
||||
default:
|
||||
word_arg_count++;
|
||||
EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), stack_size, (word_arg_count >= 4) ? TMP_REG1 : word_arg_count, 0);
|
||||
stack_size += sizeof(sljit_sw);
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_s32 post_call_with_args(struct sljit_compiler *compiler,
|
||||
sljit_s32 arg_types, sljit_s32 stack_size)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_s32 single;
|
||||
|
||||
if (stack_size > 0)
|
||||
FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, stack_size));
|
||||
|
||||
if ((arg_types & SLJIT_DEF_MASK) < SLJIT_ARG_TYPE_F32)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
single = ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F32);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(3);
|
||||
inst[0] = single ? FSTPS : FSTPD;
|
||||
inst[1] = (0x03 << 3) | 0x04;
|
||||
inst[2] = (0x04 << 3) | reg_map[SLJIT_SP];
|
||||
|
||||
return emit_sse2_load(compiler, single, SLJIT_FR0, SLJIT_MEM1(SLJIT_SP), 0);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_s32 stack_size = 0;
|
||||
sljit_s32 word_arg_count;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if ((type & 0xff) == SLJIT_CALL) {
|
||||
stack_size = c_fast_call_get_stack_size(arg_types, &word_arg_count);
|
||||
PTR_FAIL_IF(c_fast_call_with_args(compiler, arg_types, stack_size, word_arg_count, 0));
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
|
||||
jump = sljit_emit_jump(compiler, type);
|
||||
PTR_FAIL_IF(jump == NULL);
|
||||
|
||||
PTR_FAIL_IF(post_call_with_args(compiler, arg_types, 0));
|
||||
return jump;
|
||||
}
|
||||
#endif
|
||||
|
||||
stack_size = cdecl_call_get_stack_size(compiler, arg_types, &word_arg_count);
|
||||
PTR_FAIL_IF(cdecl_call_with_args(compiler, arg_types, stack_size, word_arg_count));
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
|
||||
jump = sljit_emit_jump(compiler, type);
|
||||
PTR_FAIL_IF(jump == NULL);
|
||||
|
||||
PTR_FAIL_IF(post_call_with_args(compiler, arg_types, stack_size));
|
||||
return jump;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 stack_size = 0;
|
||||
sljit_s32 word_arg_count;
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
sljit_s32 swap_args;
|
||||
#endif
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R0] == 0 && reg_map[SLJIT_R2] == 1 && SLJIT_R0 == 1 && SLJIT_R2 == 3);
|
||||
|
||||
if ((type & 0xff) == SLJIT_CALL) {
|
||||
stack_size = c_fast_call_get_stack_size(arg_types, &word_arg_count);
|
||||
swap_args = 0;
|
||||
|
||||
if (word_arg_count > 0) {
|
||||
if ((src & REG_MASK) == SLJIT_R2 || OFFS_REG(src) == SLJIT_R2) {
|
||||
swap_args = 1;
|
||||
if (((src & REG_MASK) | 0x2) == SLJIT_R2)
|
||||
src ^= 0x2;
|
||||
if ((OFFS_REG(src) | 0x2) == SLJIT_R2)
|
||||
src ^= TO_OFFS_REG(0x2);
|
||||
}
|
||||
}
|
||||
|
||||
FAIL_IF(c_fast_call_with_args(compiler, arg_types, stack_size, word_arg_count, swap_args));
|
||||
|
||||
compiler->saveds_offset += stack_size;
|
||||
compiler->locals_offset += stack_size;
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw));
|
||||
|
||||
compiler->saveds_offset -= stack_size;
|
||||
compiler->locals_offset -= stack_size;
|
||||
|
||||
return post_call_with_args(compiler, arg_types, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
stack_size = cdecl_call_get_stack_size(compiler, arg_types, &word_arg_count);
|
||||
FAIL_IF(cdecl_call_with_args(compiler, arg_types, stack_size, word_arg_count));
|
||||
|
||||
compiler->saveds_offset += stack_size;
|
||||
compiler->locals_offset += stack_size;
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw));
|
||||
|
||||
compiler->saveds_offset -= stack_size;
|
||||
compiler->locals_offset -= stack_size;
|
||||
|
||||
return post_call_with_args(compiler, arg_types, stack_size);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
CHECK_EXTRA_REGS(dst, dstw, (void)0);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
dst = TMP_REG1;
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
/* Unused dest is possible here. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1);
|
||||
POP_REG(reg_map[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Memory. */
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = POP_rm;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
CHECK_EXTRA_REGS(src, srcw, (void)0);
|
||||
|
||||
if (FAST_IS_REG(src)) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1 + 1);
|
||||
PUSH_REG(reg_map[src]);
|
||||
}
|
||||
else {
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = GROUP_FF;
|
||||
*inst |= PUSH_rm;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
}
|
||||
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,900 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
/* x86 64-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(2 + sizeof(sljit_sw));
|
||||
*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
|
||||
*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
|
||||
sljit_unaligned_store_sw(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr)
|
||||
{
|
||||
sljit_s32 type = jump->flags >> TYPE_SHIFT;
|
||||
|
||||
int short_addr = !(jump->flags & SLJIT_REWRITABLE_JUMP) && !(jump->flags & JUMP_LABEL) && (jump->u.target <= 0xffffffff);
|
||||
|
||||
/* The relative jump below specialized for this case. */
|
||||
SLJIT_ASSERT(reg_map[TMP_REG2] >= 8);
|
||||
|
||||
if (type < SLJIT_JUMP) {
|
||||
/* Invert type. */
|
||||
*code_ptr++ = get_jump_code(type ^ 0x1) - 0x10;
|
||||
*code_ptr++ = short_addr ? (6 + 3) : (10 + 3);
|
||||
}
|
||||
|
||||
*code_ptr++ = short_addr ? REX_B : (REX_W | REX_B);
|
||||
*code_ptr++ = MOV_r_i32 | reg_lmap[TMP_REG2];
|
||||
jump->addr = (sljit_uw)code_ptr;
|
||||
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
jump->flags |= PATCH_MD;
|
||||
else if (short_addr)
|
||||
sljit_unaligned_store_s32(code_ptr, (sljit_s32)jump->u.target);
|
||||
else
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target);
|
||||
|
||||
code_ptr += short_addr ? sizeof(sljit_s32) : sizeof(sljit_sw);
|
||||
|
||||
*code_ptr++ = REX_B;
|
||||
*code_ptr++ = GROUP_FF;
|
||||
*code_ptr++ = MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2];
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label)
|
||||
{
|
||||
if (max_label > HALFWORD_MAX) {
|
||||
put_label->addr -= put_label->flags;
|
||||
put_label->flags = PATCH_MD;
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
if (put_label->flags == 0) {
|
||||
/* Destination is register. */
|
||||
code_ptr = (sljit_u8*)put_label->addr - 2 - sizeof(sljit_uw);
|
||||
|
||||
SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
|
||||
SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32);
|
||||
|
||||
if ((code_ptr[0] & 0x07) != 0) {
|
||||
code_ptr[0] = (sljit_u8)(code_ptr[0] & ~0x08);
|
||||
code_ptr += 2 + sizeof(sljit_s32);
|
||||
}
|
||||
else {
|
||||
code_ptr[0] = code_ptr[1];
|
||||
code_ptr += 1 + sizeof(sljit_s32);
|
||||
}
|
||||
|
||||
put_label->addr = (sljit_uw)code_ptr;
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
code_ptr -= put_label->flags + (2 + sizeof(sljit_uw));
|
||||
SLJIT_MEMMOVE(code_ptr, code_ptr + (2 + sizeof(sljit_uw)), put_label->flags);
|
||||
|
||||
SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
|
||||
|
||||
if ((code_ptr[1] & 0xf8) == MOV_r_i32) {
|
||||
code_ptr += 2 + sizeof(sljit_uw);
|
||||
SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(code_ptr[1] == MOV_rm_r);
|
||||
|
||||
code_ptr[0] = (sljit_u8)(code_ptr[0] & ~0x4);
|
||||
code_ptr[1] = MOV_rm_i32;
|
||||
code_ptr[2] = (sljit_u8)(code_ptr[2] & ~(0x7 << 3));
|
||||
|
||||
code_ptr = (sljit_u8*)(put_label->addr - (2 + sizeof(sljit_uw)) + sizeof(sljit_s32));
|
||||
put_label->addr = (sljit_uw)code_ptr;
|
||||
put_label->flags = 0;
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 args, i, tmp, size, saved_register_size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->mode32 = 0;
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
|
||||
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
|
||||
for (i = SLJIT_S0; i >= tmp; i--) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
args = get_arg_count(arg_types);
|
||||
|
||||
if (args > 0) {
|
||||
size = args * 3;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
|
||||
#ifndef _WIN64
|
||||
if (args > 0) {
|
||||
inst[0] = REX_W;
|
||||
inst[1] = MOV_r_rm;
|
||||
inst[2] = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x7 /* rdi */;
|
||||
inst += 3;
|
||||
}
|
||||
if (args > 1) {
|
||||
inst[0] = REX_W | REX_R;
|
||||
inst[1] = MOV_r_rm;
|
||||
inst[2] = MOD_REG | (reg_lmap[SLJIT_S1] << 3) | 0x6 /* rsi */;
|
||||
inst += 3;
|
||||
}
|
||||
if (args > 2) {
|
||||
inst[0] = REX_W | REX_R;
|
||||
inst[1] = MOV_r_rm;
|
||||
inst[2] = MOD_REG | (reg_lmap[SLJIT_S2] << 3) | 0x2 /* rdx */;
|
||||
}
|
||||
#else
|
||||
if (args > 0) {
|
||||
inst[0] = REX_W;
|
||||
inst[1] = MOV_r_rm;
|
||||
inst[2] = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x1 /* rcx */;
|
||||
inst += 3;
|
||||
}
|
||||
if (args > 1) {
|
||||
inst[0] = REX_W;
|
||||
inst[1] = MOV_r_rm;
|
||||
inst[2] = MOD_REG | (reg_map[SLJIT_S1] << 3) | 0x2 /* rdx */;
|
||||
inst += 3;
|
||||
}
|
||||
if (args > 2) {
|
||||
inst[0] = REX_W | REX_B;
|
||||
inst[1] = MOV_r_rm;
|
||||
inst[2] = MOD_REG | (reg_map[SLJIT_S2] << 3) | 0x0 /* r8 */;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
|
||||
compiler->local_size = local_size;
|
||||
|
||||
#ifdef _WIN64
|
||||
if (local_size > 0) {
|
||||
if (local_size <= 4 * 4096) {
|
||||
if (local_size > 4096)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096);
|
||||
if (local_size > 2 * 4096)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 2);
|
||||
if (local_size > 3 * 4096)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 3);
|
||||
}
|
||||
else {
|
||||
EMIT_MOV(compiler, SLJIT_R0, 0, SLJIT_SP, 0);
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, (local_size - 1) >> 12);
|
||||
|
||||
SLJIT_ASSERT (reg_map[SLJIT_R0] == 0);
|
||||
|
||||
EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_MEM1(SLJIT_R0), -4096);
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 4096));
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
TMP_REG1, 0, TMP_REG1, 0, SLJIT_IMM, 1));
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(2);
|
||||
inst[0] = JNE_i8;
|
||||
inst[1] = (sljit_s8) -19;
|
||||
}
|
||||
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -local_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (local_size > 0) {
|
||||
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size));
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Save xmm6 register: movaps [rsp + 0x20], xmm6 */
|
||||
if (fscratches >= 6 || fsaveds >= 1) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(5);
|
||||
*inst++ = GROUP_0F;
|
||||
sljit_unaligned_store_s32(inst, 0x20247429);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 saved_register_size;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
compiler->local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 i, tmp, size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Restore xmm6 register: movaps xmm6, [rsp + 0x20] */
|
||||
if (compiler->fscratches >= 6 || compiler->fsaveds >= 1) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(5);
|
||||
*inst++ = GROUP_0F;
|
||||
sljit_unaligned_store_s32(inst, 0x20247428);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (compiler->local_size > 0) {
|
||||
if (compiler->local_size <= 127) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | ADD | 4;
|
||||
*inst = compiler->local_size;
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(7);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_81;
|
||||
*inst++ = MOD_REG | ADD | 4;
|
||||
sljit_unaligned_store_s32(inst, compiler->local_size);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = compiler->scratches;
|
||||
for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
|
||||
for (i = tmp; i <= SLJIT_S0; i++) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static sljit_s32 emit_do_imm32(struct sljit_compiler *compiler, sljit_u8 rex, sljit_u8 opcode, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_s32 length = 1 + (rex ? 1 : 0) + sizeof(sljit_s32);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + length);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(length);
|
||||
if (rex)
|
||||
*inst++ = rex;
|
||||
*inst++ = opcode;
|
||||
sljit_unaligned_store_s32(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
|
||||
/* The register or immediate operand. */
|
||||
sljit_s32 a, sljit_sw imma,
|
||||
/* The general operand (not immediate). */
|
||||
sljit_s32 b, sljit_sw immb)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_u8 *buf_ptr;
|
||||
sljit_u8 rex = 0;
|
||||
sljit_s32 flags = size & ~0xf;
|
||||
sljit_s32 inst_size;
|
||||
|
||||
/* The immediate operand must be 32 bit. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
|
||||
/* Both cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
|
||||
/* Size flags not allowed for typed instructions. */
|
||||
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
|
||||
/* Both size flags cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
|
||||
/* SSE2 and immediate is not possible. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
|
||||
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
|
||||
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
|
||||
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
|
||||
|
||||
size &= 0xf;
|
||||
inst_size = size;
|
||||
|
||||
if (!compiler->mode32 && !(flags & EX86_NO_REXW))
|
||||
rex |= REX_W;
|
||||
else if (flags & EX86_REX)
|
||||
rex |= REX;
|
||||
|
||||
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
|
||||
inst_size++;
|
||||
if (flags & EX86_PREF_66)
|
||||
inst_size++;
|
||||
|
||||
/* Calculate size of b. */
|
||||
inst_size += 1; /* mod r/m byte. */
|
||||
if (b & SLJIT_MEM) {
|
||||
if (!(b & OFFS_REG_MASK)) {
|
||||
if (NOT_HALFWORD(immb)) {
|
||||
PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immb));
|
||||
immb = 0;
|
||||
if (b & REG_MASK)
|
||||
b |= TO_OFFS_REG(TMP_REG2);
|
||||
else
|
||||
b |= TMP_REG2;
|
||||
}
|
||||
else if (reg_lmap[b & REG_MASK] == 4)
|
||||
b |= TO_OFFS_REG(SLJIT_SP);
|
||||
}
|
||||
|
||||
if ((b & REG_MASK) == SLJIT_UNUSED)
|
||||
inst_size += 1 + sizeof(sljit_s32); /* SIB byte required to avoid RIP based addressing. */
|
||||
else {
|
||||
if (reg_map[b & REG_MASK] >= 8)
|
||||
rex |= REX_B;
|
||||
|
||||
if (immb != 0 && (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP))) {
|
||||
/* Immediate operand. */
|
||||
if (immb <= 127 && immb >= -128)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else
|
||||
inst_size += sizeof(sljit_s32);
|
||||
}
|
||||
else if (reg_lmap[b & REG_MASK] == 5)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
|
||||
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED) {
|
||||
inst_size += 1; /* SIB byte. */
|
||||
if (reg_map[OFFS_REG(b)] >= 8)
|
||||
rex |= REX_X;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(flags & EX86_SSE2_OP2)) {
|
||||
if (reg_map[b] >= 8)
|
||||
rex |= REX_B;
|
||||
}
|
||||
else if (freg_map[b] >= 8)
|
||||
rex |= REX_B;
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
}
|
||||
else if (flags & EX86_SHIFT_INS) {
|
||||
imma &= compiler->mode32 ? 0x1f : 0x3f;
|
||||
if (imma != 1) {
|
||||
inst_size ++;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
else
|
||||
inst_size += sizeof(sljit_s32);
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
|
||||
/* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */
|
||||
if (!(flags & EX86_SSE2_OP1)) {
|
||||
if (reg_map[a] >= 8)
|
||||
rex |= REX_R;
|
||||
}
|
||||
else if (freg_map[a] >= 8)
|
||||
rex |= REX_R;
|
||||
}
|
||||
|
||||
if (rex)
|
||||
inst_size++;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
|
||||
PTR_FAIL_IF(!inst);
|
||||
|
||||
/* Encoding the byte. */
|
||||
INC_SIZE(inst_size);
|
||||
if (flags & EX86_PREF_F2)
|
||||
*inst++ = 0xf2;
|
||||
if (flags & EX86_PREF_F3)
|
||||
*inst++ = 0xf3;
|
||||
if (flags & EX86_PREF_66)
|
||||
*inst++ = 0x66;
|
||||
if (rex)
|
||||
*inst++ = rex;
|
||||
buf_ptr = inst + size;
|
||||
|
||||
/* Encode mod/rm byte. */
|
||||
if (!(flags & EX86_SHIFT_INS)) {
|
||||
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
|
||||
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
|
||||
|
||||
if (a & SLJIT_IMM)
|
||||
*buf_ptr = 0;
|
||||
else if (!(flags & EX86_SSE2_OP1))
|
||||
*buf_ptr = reg_lmap[a] << 3;
|
||||
else
|
||||
*buf_ptr = freg_lmap[a] << 3;
|
||||
}
|
||||
else {
|
||||
if (a & SLJIT_IMM) {
|
||||
if (imma == 1)
|
||||
*inst = GROUP_SHIFT_1;
|
||||
else
|
||||
*inst = GROUP_SHIFT_N;
|
||||
} else
|
||||
*inst = GROUP_SHIFT_CL;
|
||||
*buf_ptr = 0;
|
||||
}
|
||||
|
||||
if (!(b & SLJIT_MEM))
|
||||
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_lmap[b] : freg_lmap[b]);
|
||||
else if ((b & REG_MASK) != SLJIT_UNUSED) {
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
|
||||
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr |= 0x40;
|
||||
else
|
||||
*buf_ptr |= 0x80;
|
||||
}
|
||||
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
|
||||
*buf_ptr++ |= reg_lmap[b & REG_MASK];
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3);
|
||||
}
|
||||
|
||||
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr++ = immb; /* 8 bit displacement. */
|
||||
else {
|
||||
sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_s32);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (reg_lmap[b & REG_MASK] == 5)
|
||||
*buf_ptr |= 0x40;
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6);
|
||||
if (reg_lmap[b & REG_MASK] == 5)
|
||||
*buf_ptr++ = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = 0x25;
|
||||
sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_s32);
|
||||
}
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BYTE_ARG)
|
||||
*buf_ptr = imma;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
sljit_unaligned_store_s16(buf_ptr, imma);
|
||||
else if (!(flags & EX86_SHIFT_INS))
|
||||
sljit_unaligned_store_s32(buf_ptr, imma);
|
||||
}
|
||||
|
||||
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Call / return instructions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#ifndef _WIN64
|
||||
|
||||
static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src_ptr, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 src = src_ptr ? (*src_ptr) : 0;
|
||||
sljit_s32 word_arg_count = 0;
|
||||
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R3] == 1 && reg_map[TMP_REG1] == 2);
|
||||
|
||||
compiler->mode32 = 0;
|
||||
|
||||
/* Remove return value. */
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
if ((arg_types & SLJIT_DEF_MASK) < SLJIT_ARG_TYPE_F32)
|
||||
word_arg_count++;
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
if (word_arg_count == 0)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (src & SLJIT_MEM) {
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
EMIT_MOV(compiler, TMP_REG2, 0, src, srcw);
|
||||
*src_ptr = TMP_REG2;
|
||||
}
|
||||
else if (src == SLJIT_R2 && word_arg_count >= SLJIT_R2)
|
||||
*src_ptr = TMP_REG1;
|
||||
|
||||
if (word_arg_count >= 3)
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R2, 0);
|
||||
return emit_mov(compiler, SLJIT_R2, 0, SLJIT_R0, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src_ptr, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 src = src_ptr ? (*src_ptr) : 0;
|
||||
sljit_s32 arg_count = 0;
|
||||
sljit_s32 word_arg_count = 0;
|
||||
sljit_s32 float_arg_count = 0;
|
||||
sljit_s32 types = 0;
|
||||
sljit_s32 data_trandfer = 0;
|
||||
static sljit_u8 word_arg_regs[5] = { 0, SLJIT_R3, SLJIT_R1, SLJIT_R2, TMP_REG1 };
|
||||
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R3] == 1 && reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R2] == 8 && reg_map[TMP_REG1] == 9);
|
||||
|
||||
compiler->mode32 = 0;
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
|
||||
while (arg_types) {
|
||||
types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
|
||||
|
||||
switch (arg_types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
arg_count++;
|
||||
float_arg_count++;
|
||||
|
||||
if (arg_count != float_arg_count)
|
||||
data_trandfer = 1;
|
||||
break;
|
||||
default:
|
||||
arg_count++;
|
||||
word_arg_count++;
|
||||
|
||||
if (arg_count != word_arg_count || arg_count != word_arg_regs[arg_count]) {
|
||||
data_trandfer = 1;
|
||||
|
||||
if (src == word_arg_regs[arg_count]) {
|
||||
EMIT_MOV(compiler, TMP_REG2, 0, src, 0);
|
||||
*src_ptr = TMP_REG2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
arg_types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
if (!data_trandfer)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (src & SLJIT_MEM) {
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
EMIT_MOV(compiler, TMP_REG2, 0, src, srcw);
|
||||
*src_ptr = TMP_REG2;
|
||||
}
|
||||
|
||||
while (types) {
|
||||
switch (types & SLJIT_DEF_MASK) {
|
||||
case SLJIT_ARG_TYPE_F32:
|
||||
if (arg_count != float_arg_count)
|
||||
FAIL_IF(emit_sse2_load(compiler, 1, arg_count, float_arg_count, 0));
|
||||
arg_count--;
|
||||
float_arg_count--;
|
||||
break;
|
||||
case SLJIT_ARG_TYPE_F64:
|
||||
if (arg_count != float_arg_count)
|
||||
FAIL_IF(emit_sse2_load(compiler, 0, arg_count, float_arg_count, 0));
|
||||
arg_count--;
|
||||
float_arg_count--;
|
||||
break;
|
||||
default:
|
||||
if (arg_count != word_arg_count || arg_count != word_arg_regs[arg_count])
|
||||
EMIT_MOV(compiler, word_arg_regs[arg_count], 0, word_arg_count, 0);
|
||||
arg_count--;
|
||||
word_arg_count--;
|
||||
break;
|
||||
}
|
||||
|
||||
types >>= SLJIT_DEF_SHIFT;
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types)
|
||||
{
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
|
||||
|
||||
PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL, 0));
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
|
||||
return sljit_emit_jump(compiler, type);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 arg_types,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
|
||||
|
||||
FAIL_IF(call_with_args(compiler, arg_types, &src, srcw));
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
|
||||
return sljit_emit_ijump(compiler, type, src, srcw);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
dst = TMP_REG1;
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (reg_map[dst] < 8) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
POP_REG(reg_lmap[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(2);
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* REX_W is not necessary (src is not immediate). */
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = POP_rm;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (reg_map[src] < 8) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1 + 1);
|
||||
PUSH_REG(reg_lmap[src]);
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(2 + 1);
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[src]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* REX_W is not necessary (src is not immediate). */
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = GROUP_FF;
|
||||
*inst |= PUSH_rm;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
}
|
||||
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Extend input */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8* inst;
|
||||
sljit_s32 dst_r;
|
||||
|
||||
compiler->mode32 = 0;
|
||||
|
||||
if (dst == SLJIT_UNUSED && !(src & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS; /* Empty instruction. */
|
||||
|
||||
if (src & SLJIT_IMM) {
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
|
||||
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_i32;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
return emit_load_imm64(compiler, dst, srcw);
|
||||
}
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_i32;
|
||||
compiler->mode32 = 0;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
||||
if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
|
||||
dst_r = src;
|
||||
else {
|
||||
if (sign) {
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = MOVSXD_r_rm;
|
||||
} else {
|
||||
compiler->mode32 = 1;
|
||||
FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
|
||||
compiler->mode32 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM) {
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_r;
|
||||
compiler->mode32 = 0;
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) 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 HOLDER(S) 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.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Locks */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) || (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_grab_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_release_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#elif defined(_WIN32) /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
static HANDLE allocator_mutex = 0;
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
/* No idea what to do if an error occures. Static mutexes should never fail... */
|
||||
if (!allocator_mutex)
|
||||
allocator_mutex = CreateMutex(NULL, TRUE, NULL);
|
||||
else
|
||||
WaitForSingleObject(allocator_mutex, INFINITE);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
ReleaseMutex(allocator_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
static HANDLE global_mutex = 0;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_grab_lock(void)
|
||||
{
|
||||
/* No idea what to do if an error occures. Static mutexes should never fail... */
|
||||
if (!global_mutex)
|
||||
global_mutex = CreateMutex(NULL, TRUE, NULL);
|
||||
else
|
||||
WaitForSingleObject(global_mutex, INFINITE);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_release_lock(void)
|
||||
{
|
||||
ReleaseMutex(global_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&allocator_mutex);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&allocator_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_grab_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&global_mutex);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_release_lock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&global_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Stack */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
/* Provides mmap function. */
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#ifndef MAP_ANON
|
||||
#ifdef MAP_ANONYMOUS
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#endif
|
||||
#endif
|
||||
/* For detecting the page size. */
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef MAP_ANON
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Some old systems does not have MAP_ANON. */
|
||||
static sljit_s32 dev_zero = -1;
|
||||
|
||||
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
|
||||
|
||||
static SLJIT_INLINE sljit_s32 open_dev_zero(void)
|
||||
{
|
||||
dev_zero = open("/dev/zero", O_RDWR);
|
||||
return dev_zero < 0;
|
||||
}
|
||||
|
||||
#else /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static SLJIT_INLINE sljit_s32 open_dev_zero(void)
|
||||
{
|
||||
pthread_mutex_lock(&dev_zero_mutex);
|
||||
/* The dev_zero might be initialized by another thread during the waiting. */
|
||||
if (dev_zero < 0) {
|
||||
dev_zero = open("/dev/zero", O_RDWR);
|
||||
}
|
||||
pthread_mutex_unlock(&dev_zero_mutex);
|
||||
return dev_zero < 0;
|
||||
}
|
||||
|
||||
#endif /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
|
||||
|
||||
/* Planning to make it even more clever in the future. */
|
||||
static sljit_sw sljit_page_align = 0;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_FUNC sljit_allocate_stack(sljit_uw start_size, sljit_uw max_size, void *allocator_data)
|
||||
{
|
||||
struct sljit_stack *stack;
|
||||
void *ptr;
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO si;
|
||||
#endif
|
||||
|
||||
SLJIT_UNUSED_ARG(allocator_data);
|
||||
if (start_size > max_size || start_size < 1)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!sljit_page_align) {
|
||||
GetSystemInfo(&si);
|
||||
sljit_page_align = si.dwPageSize - 1;
|
||||
}
|
||||
#else
|
||||
if (!sljit_page_align) {
|
||||
sljit_page_align = sysconf(_SC_PAGESIZE);
|
||||
/* Should never happen. */
|
||||
if (sljit_page_align < 0)
|
||||
sljit_page_align = 4096;
|
||||
sljit_page_align--;
|
||||
}
|
||||
#endif
|
||||
|
||||
stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data);
|
||||
if (!stack)
|
||||
return NULL;
|
||||
|
||||
/* Align max_size. */
|
||||
max_size = (max_size + sljit_page_align) & ~sljit_page_align;
|
||||
|
||||
#ifdef _WIN32
|
||||
ptr = VirtualAlloc(NULL, max_size, MEM_RESERVE, PAGE_READWRITE);
|
||||
if (!ptr) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stack->min_start = (sljit_u8 *)ptr;
|
||||
stack->end = stack->min_start + max_size;
|
||||
stack->start = stack->end;
|
||||
|
||||
if (sljit_stack_resize(stack, stack->end - start_size) == NULL) {
|
||||
sljit_free_stack(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#ifdef MAP_ANON
|
||||
ptr = mmap(NULL, max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
if (dev_zero < 0) {
|
||||
if (open_dev_zero()) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ptr = mmap(NULL, max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0);
|
||||
#endif
|
||||
if (ptr == MAP_FAILED) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
stack->min_start = (sljit_u8 *)ptr;
|
||||
stack->end = stack->min_start + max_size;
|
||||
stack->start = stack->end - start_size;
|
||||
#endif
|
||||
stack->top = stack->end;
|
||||
return stack;
|
||||
}
|
||||
|
||||
#undef PAGE_ALIGN
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(allocator_data);
|
||||
#ifdef _WIN32
|
||||
VirtualFree((void*)stack->min_start, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap((void*)stack->min_start, stack->end - stack->min_start);
|
||||
#endif
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_u8 *SLJIT_FUNC sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_start)
|
||||
{
|
||||
sljit_uw aligned_old_start;
|
||||
sljit_uw aligned_new_start;
|
||||
|
||||
if ((new_start < stack->min_start) || (new_start >= stack->end))
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
aligned_new_start = (sljit_uw)new_start & ~sljit_page_align;
|
||||
aligned_old_start = ((sljit_uw)stack->start) & ~sljit_page_align;
|
||||
if (aligned_new_start != aligned_old_start) {
|
||||
if (aligned_new_start < aligned_old_start) {
|
||||
if (!VirtualAlloc((void*)aligned_new_start, aligned_old_start - aligned_new_start, MEM_COMMIT, PAGE_READWRITE))
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
if (!VirtualFree((void*)aligned_old_start, aligned_new_start - aligned_old_start, MEM_DECOMMIT))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (stack->start < new_start) {
|
||||
aligned_new_start = (sljit_uw)new_start & ~sljit_page_align;
|
||||
aligned_old_start = ((sljit_uw)stack->start) & ~sljit_page_align;
|
||||
/* If madvise is available, we release the unnecessary space. */
|
||||
#if defined(MADV_DONTNEED)
|
||||
if (aligned_new_start > aligned_old_start)
|
||||
madvise((void*)aligned_old_start, aligned_new_start - aligned_old_start, MADV_DONTNEED);
|
||||
#elif defined(POSIX_MADV_DONTNEED)
|
||||
if (aligned_new_start > aligned_old_start)
|
||||
posix_madvise((void*)aligned_old_start, aligned_new_start - aligned_old_start, POSIX_MADV_DONTNEED);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
stack->start = new_start;
|
||||
return new_start;
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_STACK */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,224 @@
|
||||
/*************************************************
|
||||
* Unicode Property Table handler *
|
||||
*************************************************/
|
||||
|
||||
#ifndef _UCP_H
|
||||
#define _UCP_H
|
||||
|
||||
/* This file contains definitions of the property values that are returned by
|
||||
the UCD access macros. New values that are added for new releases of Unicode
|
||||
should always be at the end of each enum, for backwards compatibility.
|
||||
|
||||
IMPORTANT: Note also that the specific numeric values of the enums have to be
|
||||
the same as the values that are generated by the maint/MultiStage2.py script,
|
||||
where the equivalent property descriptive names are listed in vectors.
|
||||
|
||||
ALSO: The specific values of the first two enums are assumed for the table
|
||||
called catposstab in pcre_compile.c. */
|
||||
|
||||
/* These are the general character categories. */
|
||||
|
||||
enum {
|
||||
ucp_C, /* Other */
|
||||
ucp_L, /* Letter */
|
||||
ucp_M, /* Mark */
|
||||
ucp_N, /* Number */
|
||||
ucp_P, /* Punctuation */
|
||||
ucp_S, /* Symbol */
|
||||
ucp_Z /* Separator */
|
||||
};
|
||||
|
||||
/* These are the particular character categories. */
|
||||
|
||||
enum {
|
||||
ucp_Cc, /* Control */
|
||||
ucp_Cf, /* Format */
|
||||
ucp_Cn, /* Unassigned */
|
||||
ucp_Co, /* Private use */
|
||||
ucp_Cs, /* Surrogate */
|
||||
ucp_Ll, /* Lower case letter */
|
||||
ucp_Lm, /* Modifier letter */
|
||||
ucp_Lo, /* Other letter */
|
||||
ucp_Lt, /* Title case letter */
|
||||
ucp_Lu, /* Upper case letter */
|
||||
ucp_Mc, /* Spacing mark */
|
||||
ucp_Me, /* Enclosing mark */
|
||||
ucp_Mn, /* Non-spacing mark */
|
||||
ucp_Nd, /* Decimal number */
|
||||
ucp_Nl, /* Letter number */
|
||||
ucp_No, /* Other number */
|
||||
ucp_Pc, /* Connector punctuation */
|
||||
ucp_Pd, /* Dash punctuation */
|
||||
ucp_Pe, /* Close punctuation */
|
||||
ucp_Pf, /* Final punctuation */
|
||||
ucp_Pi, /* Initial punctuation */
|
||||
ucp_Po, /* Other punctuation */
|
||||
ucp_Ps, /* Open punctuation */
|
||||
ucp_Sc, /* Currency symbol */
|
||||
ucp_Sk, /* Modifier symbol */
|
||||
ucp_Sm, /* Mathematical symbol */
|
||||
ucp_So, /* Other symbol */
|
||||
ucp_Zl, /* Line separator */
|
||||
ucp_Zp, /* Paragraph separator */
|
||||
ucp_Zs /* Space separator */
|
||||
};
|
||||
|
||||
/* These are grapheme break properties. Note that the code for processing them
|
||||
assumes that the values are less than 16. If more values are added that take
|
||||
the number to 16 or more, the code will have to be rewritten. */
|
||||
|
||||
enum {
|
||||
ucp_gbCR, /* 0 */
|
||||
ucp_gbLF, /* 1 */
|
||||
ucp_gbControl, /* 2 */
|
||||
ucp_gbExtend, /* 3 */
|
||||
ucp_gbPrepend, /* 4 */
|
||||
ucp_gbSpacingMark, /* 5 */
|
||||
ucp_gbL, /* 6 Hangul syllable type L */
|
||||
ucp_gbV, /* 7 Hangul syllable type V */
|
||||
ucp_gbT, /* 8 Hangul syllable type T */
|
||||
ucp_gbLV, /* 9 Hangul syllable type LV */
|
||||
ucp_gbLVT, /* 10 Hangul syllable type LVT */
|
||||
ucp_gbRegionalIndicator, /* 11 */
|
||||
ucp_gbOther /* 12 */
|
||||
};
|
||||
|
||||
/* These are the script identifications. */
|
||||
|
||||
enum {
|
||||
ucp_Arabic,
|
||||
ucp_Armenian,
|
||||
ucp_Bengali,
|
||||
ucp_Bopomofo,
|
||||
ucp_Braille,
|
||||
ucp_Buginese,
|
||||
ucp_Buhid,
|
||||
ucp_Canadian_Aboriginal,
|
||||
ucp_Cherokee,
|
||||
ucp_Common,
|
||||
ucp_Coptic,
|
||||
ucp_Cypriot,
|
||||
ucp_Cyrillic,
|
||||
ucp_Deseret,
|
||||
ucp_Devanagari,
|
||||
ucp_Ethiopic,
|
||||
ucp_Georgian,
|
||||
ucp_Glagolitic,
|
||||
ucp_Gothic,
|
||||
ucp_Greek,
|
||||
ucp_Gujarati,
|
||||
ucp_Gurmukhi,
|
||||
ucp_Han,
|
||||
ucp_Hangul,
|
||||
ucp_Hanunoo,
|
||||
ucp_Hebrew,
|
||||
ucp_Hiragana,
|
||||
ucp_Inherited,
|
||||
ucp_Kannada,
|
||||
ucp_Katakana,
|
||||
ucp_Kharoshthi,
|
||||
ucp_Khmer,
|
||||
ucp_Lao,
|
||||
ucp_Latin,
|
||||
ucp_Limbu,
|
||||
ucp_Linear_B,
|
||||
ucp_Malayalam,
|
||||
ucp_Mongolian,
|
||||
ucp_Myanmar,
|
||||
ucp_New_Tai_Lue,
|
||||
ucp_Ogham,
|
||||
ucp_Old_Italic,
|
||||
ucp_Old_Persian,
|
||||
ucp_Oriya,
|
||||
ucp_Osmanya,
|
||||
ucp_Runic,
|
||||
ucp_Shavian,
|
||||
ucp_Sinhala,
|
||||
ucp_Syloti_Nagri,
|
||||
ucp_Syriac,
|
||||
ucp_Tagalog,
|
||||
ucp_Tagbanwa,
|
||||
ucp_Tai_Le,
|
||||
ucp_Tamil,
|
||||
ucp_Telugu,
|
||||
ucp_Thaana,
|
||||
ucp_Thai,
|
||||
ucp_Tibetan,
|
||||
ucp_Tifinagh,
|
||||
ucp_Ugaritic,
|
||||
ucp_Yi,
|
||||
/* New for Unicode 5.0: */
|
||||
ucp_Balinese,
|
||||
ucp_Cuneiform,
|
||||
ucp_Nko,
|
||||
ucp_Phags_Pa,
|
||||
ucp_Phoenician,
|
||||
/* New for Unicode 5.1: */
|
||||
ucp_Carian,
|
||||
ucp_Cham,
|
||||
ucp_Kayah_Li,
|
||||
ucp_Lepcha,
|
||||
ucp_Lycian,
|
||||
ucp_Lydian,
|
||||
ucp_Ol_Chiki,
|
||||
ucp_Rejang,
|
||||
ucp_Saurashtra,
|
||||
ucp_Sundanese,
|
||||
ucp_Vai,
|
||||
/* New for Unicode 5.2: */
|
||||
ucp_Avestan,
|
||||
ucp_Bamum,
|
||||
ucp_Egyptian_Hieroglyphs,
|
||||
ucp_Imperial_Aramaic,
|
||||
ucp_Inscriptional_Pahlavi,
|
||||
ucp_Inscriptional_Parthian,
|
||||
ucp_Javanese,
|
||||
ucp_Kaithi,
|
||||
ucp_Lisu,
|
||||
ucp_Meetei_Mayek,
|
||||
ucp_Old_South_Arabian,
|
||||
ucp_Old_Turkic,
|
||||
ucp_Samaritan,
|
||||
ucp_Tai_Tham,
|
||||
ucp_Tai_Viet,
|
||||
/* New for Unicode 6.0.0: */
|
||||
ucp_Batak,
|
||||
ucp_Brahmi,
|
||||
ucp_Mandaic,
|
||||
/* New for Unicode 6.1.0: */
|
||||
ucp_Chakma,
|
||||
ucp_Meroitic_Cursive,
|
||||
ucp_Meroitic_Hieroglyphs,
|
||||
ucp_Miao,
|
||||
ucp_Sharada,
|
||||
ucp_Sora_Sompeng,
|
||||
ucp_Takri,
|
||||
/* New for Unicode 7.0.0: */
|
||||
ucp_Bassa_Vah,
|
||||
ucp_Caucasian_Albanian,
|
||||
ucp_Duployan,
|
||||
ucp_Elbasan,
|
||||
ucp_Grantha,
|
||||
ucp_Khojki,
|
||||
ucp_Khudawadi,
|
||||
ucp_Linear_A,
|
||||
ucp_Mahajani,
|
||||
ucp_Manichaean,
|
||||
ucp_Mende_Kikakui,
|
||||
ucp_Modi,
|
||||
ucp_Mro,
|
||||
ucp_Nabataean,
|
||||
ucp_Old_North_Arabian,
|
||||
ucp_Old_Permic,
|
||||
ucp_Pahawh_Hmong,
|
||||
ucp_Palmyrene,
|
||||
ucp_Psalter_Pahlavi,
|
||||
ucp_Pau_Cin_Hau,
|
||||
ucp_Siddham,
|
||||
ucp_Tirhuta,
|
||||
ucp_Warang_Citi
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* End of ucp.h */
|
||||
Reference in New Issue
Block a user