зеркало из https://github.com/mozilla/gecko-dev.git
Bug 503952 - Use JSTempVector in scanner/parser; remove JSStringBuffer (r=brendan)
This commit is contained in:
Родитель
6ae5b0ea2d
Коммит
81528e533d
|
@ -5490,7 +5490,7 @@ JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
|
|||
JSCharBuffer cb(cx);
|
||||
if (!js_Stringify(cx, vp, replacer, space, cb))
|
||||
return false;
|
||||
return callback(cb.begin(), cb.size(), data);
|
||||
return callback(cb.begin(), cb.length(), data);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
|
|
@ -2096,7 +2096,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
const char *filename;
|
||||
JSBool ok;
|
||||
JSString *str, *arg;
|
||||
JSTokenStream ts;
|
||||
JSTokenStream ts(cx);
|
||||
JSPrincipals *principals;
|
||||
jschar *collected_args, *cp;
|
||||
void *mark;
|
||||
|
@ -2232,8 +2232,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
}
|
||||
|
||||
/* Initialize a tokenstream that reads from the given string. */
|
||||
if (!js_InitTokenStream(cx, &ts, collected_args, args_length,
|
||||
NULL, filename, lineno)) {
|
||||
if (!ts.init(cx, collected_args, args_length, NULL, filename, lineno)) {
|
||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -2296,7 +2295,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_FORMAL);
|
||||
}
|
||||
js_CloseTokenStream(cx, &ts);
|
||||
ts.close(cx);
|
||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||
if (state != OK)
|
||||
return JS_FALSE;
|
||||
|
|
|
@ -887,7 +887,7 @@ js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb)
|
|||
*/
|
||||
size_t cstrlen = strlen(cstr);
|
||||
JS_ASSERT(cstrlen < arrSize);
|
||||
size_t sizeBefore = cb.size();
|
||||
size_t sizeBefore = cb.length();
|
||||
if (!cb.growBy(cstrlen))
|
||||
return JS_FALSE;
|
||||
jschar *appendBegin = cb.begin() + sizeBefore;
|
||||
|
|
|
@ -807,7 +807,7 @@ PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, jsval value)
|
|||
}
|
||||
} else {
|
||||
ok = JS_DefineUCProperty(cx, parent, jp->objectKey.begin(),
|
||||
jp->objectKey.size(), value,
|
||||
jp->objectKey.length(), value,
|
||||
NULL, NULL, JSPROP_ENUMERATE);
|
||||
jp->objectKey.clear();
|
||||
}
|
||||
|
@ -982,7 +982,7 @@ HandleData(JSContext *cx, JSONParser *jp, JSONDataType type)
|
|||
|
||||
switch (type) {
|
||||
case JSON_DATA_STRING:
|
||||
ok = HandleString(cx, jp, jp->buffer.begin(), jp->buffer.size());
|
||||
ok = HandleString(cx, jp, jp->buffer.begin(), jp->buffer.length());
|
||||
break;
|
||||
|
||||
case JSON_DATA_KEYSTRING:
|
||||
|
@ -990,12 +990,12 @@ HandleData(JSContext *cx, JSONParser *jp, JSONDataType type)
|
|||
break;
|
||||
|
||||
case JSON_DATA_NUMBER:
|
||||
ok = HandleNumber(cx, jp, jp->buffer.begin(), jp->buffer.size());
|
||||
ok = HandleNumber(cx, jp, jp->buffer.begin(), jp->buffer.length());
|
||||
break;
|
||||
|
||||
default:
|
||||
JS_ASSERT(type == JSON_DATA_KEYWORD);
|
||||
ok = HandleKeyword(cx, jp, jp->buffer.begin(), jp->buffer.size());
|
||||
ok = HandleKeyword(cx, jp, jp->buffer.begin(), jp->buffer.length());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
#include "jsstr.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jslibmath.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
#include "jsxml.h"
|
||||
|
@ -211,7 +212,7 @@ JSCompiler::init(const jschar *base, size_t length,
|
|||
JSContext *cx = context;
|
||||
|
||||
tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
|
||||
if (!js_InitTokenStream(cx, TS(this), base, length, fp, filename, lineno)) {
|
||||
if (!tokenStream.init(cx, base, length, fp, filename, lineno)) {
|
||||
JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
|
||||
return false;
|
||||
}
|
||||
|
@ -231,7 +232,7 @@ JSCompiler::~JSCompiler()
|
|||
JS_ASSERT(tempRoot.u.compiler == this);
|
||||
JS_POP_TEMP_ROOT(cx, &tempRoot);
|
||||
JS_UNKEEP_ATOMS(cx->runtime);
|
||||
js_CloseTokenStream(cx, TS(this));
|
||||
tokenStream.close(cx);
|
||||
JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
|
||||
}
|
||||
|
||||
|
@ -8206,11 +8207,9 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
if (!pn)
|
||||
return NULL;
|
||||
|
||||
/* Token stream ensures that tokenbuf is NUL-terminated. */
|
||||
JS_ASSERT(*ts->tokenbuf.ptr == (jschar) 0);
|
||||
obj = js_NewRegExpObject(cx, ts,
|
||||
ts->tokenbuf.base,
|
||||
ts->tokenbuf.ptr - ts->tokenbuf.base,
|
||||
ts->tokenbuf.begin(),
|
||||
ts->tokenbuf.length(),
|
||||
CURRENT_TOKEN(ts).t_reflags);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
|
|
@ -822,8 +822,8 @@ struct JSCompiler {
|
|||
JSTempValueRooter tempRoot; /* root to trace traceListHead */
|
||||
|
||||
JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
|
||||
: context(cx), aleFreeList(NULL), principals(NULL), callerFrame(cfp),
|
||||
nodeList(NULL), functionCount(0), traceListHead(NULL)
|
||||
: context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL),
|
||||
callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL)
|
||||
{
|
||||
memset(tempFreeList, 0, sizeof tempFreeList);
|
||||
setPrincipals(prin);
|
||||
|
@ -833,7 +833,7 @@ struct JSCompiler {
|
|||
~JSCompiler();
|
||||
|
||||
/*
|
||||
* Initialize a compiler. Parameters are passed on to js_InitTokenStream.
|
||||
* Initialize a compiler. Parameters are passed on to init tokenStream.
|
||||
* The compiler owns the arena pool "tops-of-stack" space above the current
|
||||
* JSContext.tempPool mark. This means you cannot allocate from tempPool
|
||||
* and save the pointer beyond the next JSCompiler destructor invocation.
|
||||
|
|
|
@ -127,7 +127,6 @@ typedef struct JSScope JSScope;
|
|||
typedef struct JSScopeOps JSScopeOps;
|
||||
typedef struct JSScopeProperty JSScopeProperty;
|
||||
typedef struct JSStackHeader JSStackHeader;
|
||||
typedef struct JSStringBuffer JSStringBuffer;
|
||||
typedef struct JSSubString JSSubString;
|
||||
typedef struct JSTraceableNative JSTraceableNative;
|
||||
typedef struct JSXML JSXML;
|
||||
|
|
|
@ -2291,7 +2291,7 @@ class RegExpNativeCompiler {
|
|||
void targetCurrentPoint(LInsList &fails)
|
||||
{
|
||||
LIns *fail = lir->ins0(LIR_label);
|
||||
for (size_t i = 0; i < fails.size(); ++i) {
|
||||
for (size_t i = 0; i < fails.length(); ++i) {
|
||||
fails[i]->setTarget(fail);
|
||||
}
|
||||
fails.clear();
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#include "jsscan.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
#include "jsxml.h"
|
||||
|
@ -175,50 +176,15 @@ js_IsIdentifier(JSString *str)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#define TBMIN 64
|
||||
/* Initialize members that aren't initialized in |init|. */
|
||||
JSTokenStream::JSTokenStream(JSContext *cx)
|
||||
: tokens(), cursor(), lookahead(), ungetpos(), ungetbuf(), flags(), linelen(),
|
||||
linepos(), file(), listenerTSData(), saveEOL(), tokenbuf(cx)
|
||||
{}
|
||||
|
||||
static JSBool
|
||||
GrowTokenBuf(JSStringBuffer *sb, size_t newlength)
|
||||
{
|
||||
JSContext *cx;
|
||||
jschar *base;
|
||||
ptrdiff_t offset, length;
|
||||
size_t tbsize;
|
||||
JSArenaPool *pool;
|
||||
|
||||
cx = (JSContext*) sb->data;
|
||||
base = sb->base;
|
||||
offset = sb->ptr - base;
|
||||
pool = &cx->tempPool;
|
||||
if (!base) {
|
||||
tbsize = TBMIN * sizeof(jschar);
|
||||
length = TBMIN - 1;
|
||||
JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize);
|
||||
} else {
|
||||
length = sb->limit - base;
|
||||
if ((size_t)length >= ~(size_t)0 / sizeof(jschar)) {
|
||||
base = NULL;
|
||||
} else {
|
||||
tbsize = (length + 1) * sizeof(jschar);
|
||||
length += length + 1;
|
||||
JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize);
|
||||
}
|
||||
}
|
||||
if (!base) {
|
||||
js_ReportOutOfScriptQuota(cx);
|
||||
sb->base = STRING_BUFFER_ERROR_BASE;
|
||||
return JS_FALSE;
|
||||
}
|
||||
sb->base = base;
|
||||
sb->limit = base + length;
|
||||
sb->ptr = base + offset;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InitTokenStream(JSContext *cx, JSTokenStream *ts,
|
||||
const jschar *base, size_t length,
|
||||
FILE *fp, const char *filename, uintN lineno)
|
||||
bool
|
||||
JSTokenStream::init(JSContext *cx, const jschar *base, size_t length,
|
||||
FILE *fp, const char *fn, uintN ln)
|
||||
{
|
||||
jschar *buf;
|
||||
size_t nb;
|
||||
|
@ -231,34 +197,33 @@ js_InitTokenStream(JSContext *cx, JSTokenStream *ts,
|
|||
JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb);
|
||||
if (!buf) {
|
||||
js_ReportOutOfScriptQuota(cx);
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
memset(buf, 0, nb);
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
ts->filename = filename;
|
||||
ts->lineno = lineno;
|
||||
ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = buf;
|
||||
|
||||
/* Initialize members. */
|
||||
filename = fn;
|
||||
lineno = ln;
|
||||
linebuf.base = linebuf.limit = linebuf.ptr = buf;
|
||||
if (fp) {
|
||||
ts->file = fp;
|
||||
ts->userbuf.base = buf + JS_LINE_LIMIT;
|
||||
ts->userbuf.ptr = ts->userbuf.limit = ts->userbuf.base + JS_LINE_LIMIT;
|
||||
file = fp;
|
||||
userbuf.base = buf + JS_LINE_LIMIT;
|
||||
userbuf.ptr = userbuf.limit = userbuf.base + JS_LINE_LIMIT;
|
||||
} else {
|
||||
ts->userbuf.base = (jschar *)base;
|
||||
ts->userbuf.limit = (jschar *)base + length;
|
||||
ts->userbuf.ptr = (jschar *)base;
|
||||
userbuf.base = (jschar *)base;
|
||||
userbuf.limit = (jschar *)base + length;
|
||||
userbuf.ptr = (jschar *)base;
|
||||
}
|
||||
ts->tokenbuf.grow = GrowTokenBuf;
|
||||
ts->tokenbuf.data = cx;
|
||||
ts->listener = cx->debugHooks->sourceHandler;
|
||||
ts->listenerData = cx->debugHooks->sourceHandlerData;
|
||||
return JS_TRUE;
|
||||
listener = cx->debugHooks->sourceHandler;
|
||||
listenerData = cx->debugHooks->sourceHandlerData;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
js_CloseTokenStream(JSContext *cx, JSTokenStream *ts)
|
||||
JSTokenStream::close(JSContext *cx)
|
||||
{
|
||||
if (ts->flags & TSF_OWNFILENAME)
|
||||
cx->free((void *) ts->filename);
|
||||
if (flags & TSF_OWNFILENAME)
|
||||
cx->free((void *) filename);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -684,138 +649,8 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn,
|
|||
return warning;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
GrowStringBuffer(JSStringBuffer *sb, size_t amount)
|
||||
{
|
||||
ptrdiff_t offset = sb->ptr - sb->base;
|
||||
JS_ASSERT(offset >= 0);
|
||||
|
||||
/*
|
||||
* This addition needs an overflow check, but we can defer bounding against
|
||||
* ~size_t(0) / sizeof(jschar) till later to consolidate that test.
|
||||
*/
|
||||
size_t newlength = offset + amount + 1;
|
||||
if (size_t(offset) < newlength) {
|
||||
/* Grow by powers of two until 16MB, then grow by that chunk size. */
|
||||
const size_t CHUNK_SIZE_MASK = JS_BITMASK(24);
|
||||
|
||||
if (newlength <= CHUNK_SIZE_MASK)
|
||||
newlength = JS_BIT(JS_CeilingLog2(newlength));
|
||||
else if (newlength & CHUNK_SIZE_MASK)
|
||||
newlength = (newlength | CHUNK_SIZE_MASK) + 1;
|
||||
|
||||
/* Now do the full overflow check. */
|
||||
if (size_t(offset) < newlength && newlength < ~size_t(0) / sizeof(jschar)) {
|
||||
jschar *bp = (jschar *) js_realloc(sb->base, newlength * sizeof(jschar));
|
||||
if (bp) {
|
||||
sb->base = bp;
|
||||
sb->ptr = bp + offset;
|
||||
sb->limit = bp + newlength - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Either newlength overflow or realloc failure: poison the well. */
|
||||
js_free(sb->base);
|
||||
sb->base = STRING_BUFFER_ERROR_BASE;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeStringBuffer(JSStringBuffer *sb)
|
||||
{
|
||||
JS_ASSERT(STRING_BUFFER_OK(sb));
|
||||
if (sb->base)
|
||||
js_free(sb->base);
|
||||
}
|
||||
|
||||
void
|
||||
js_InitStringBuffer(JSStringBuffer *sb)
|
||||
{
|
||||
sb->base = sb->limit = sb->ptr = NULL;
|
||||
sb->data = NULL;
|
||||
sb->grow = GrowStringBuffer;
|
||||
sb->free = FreeStringBuffer;
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishStringBuffer(JSStringBuffer *sb)
|
||||
{
|
||||
sb->free(sb);
|
||||
}
|
||||
|
||||
void
|
||||
js_AppendChar(JSStringBuffer *sb, jschar c)
|
||||
{
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb))
|
||||
return;
|
||||
if (!ENSURE_STRING_BUFFER(sb, 1))
|
||||
return;
|
||||
bp = sb->ptr;
|
||||
*bp++ = c;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
void
|
||||
js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len)
|
||||
{
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb))
|
||||
return;
|
||||
if (len == 0 || !ENSURE_STRING_BUFFER(sb, len))
|
||||
return;
|
||||
bp = sb->ptr;
|
||||
js_strncpy(bp, buf, len);
|
||||
bp += len;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
|
||||
void
|
||||
js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count)
|
||||
{
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb) || count == 0)
|
||||
return;
|
||||
if (!ENSURE_STRING_BUFFER(sb, count))
|
||||
return;
|
||||
for (bp = sb->ptr; count; --count)
|
||||
*bp++ = c;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
void
|
||||
js_AppendCString(JSStringBuffer *sb, const char *asciiz)
|
||||
{
|
||||
size_t length;
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb) || *asciiz == '\0')
|
||||
return;
|
||||
length = strlen(asciiz);
|
||||
if (!ENSURE_STRING_BUFFER(sb, length))
|
||||
return;
|
||||
for (bp = sb->ptr; length; --length)
|
||||
*bp++ = (jschar) *asciiz++;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
void
|
||||
js_AppendJSString(JSStringBuffer *sb, JSString *str)
|
||||
{
|
||||
js_AppendUCString(sb, str->chars(), str->length());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
GetXMLEntity(JSContext *cx, JSTokenStream *ts)
|
||||
{
|
||||
|
@ -826,10 +661,11 @@ GetXMLEntity(JSContext *cx, JSTokenStream *ts)
|
|||
char *bytes;
|
||||
JSErrNum msg;
|
||||
|
||||
JSCharBuffer &tb = ts->tokenbuf;
|
||||
|
||||
/* Put the entity, including the '&' already scanned, in ts->tokenbuf. */
|
||||
offset = ts->tokenbuf.ptr - ts->tokenbuf.base;
|
||||
js_FastAppendChar(&ts->tokenbuf, '&');
|
||||
if (!STRING_BUFFER_OK(&ts->tokenbuf))
|
||||
offset = tb.length();
|
||||
if (!tb.append('&'))
|
||||
return JS_FALSE;
|
||||
while ((c = GetChar(ts)) != ';') {
|
||||
if (c == EOF || c == '\n') {
|
||||
|
@ -837,14 +673,13 @@ GetXMLEntity(JSContext *cx, JSTokenStream *ts)
|
|||
JSMSG_END_OF_XML_ENTITY);
|
||||
return JS_FALSE;
|
||||
}
|
||||
js_FastAppendChar(&ts->tokenbuf, (jschar) c);
|
||||
if (!STRING_BUFFER_OK(&ts->tokenbuf))
|
||||
if (!tb.append(c))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Let length be the number of jschars after the '&', including the ';'. */
|
||||
length = (ts->tokenbuf.ptr - ts->tokenbuf.base) - offset;
|
||||
bp = ts->tokenbuf.base + offset;
|
||||
length = tb.length() - offset;
|
||||
bp = tb.begin() + offset;
|
||||
c = d = 0;
|
||||
ispair = JS_FALSE;
|
||||
if (length > 2 && bp[1] == '#') {
|
||||
|
@ -917,18 +752,15 @@ GetXMLEntity(JSContext *cx, JSTokenStream *ts)
|
|||
*bp++ = (jschar) c;
|
||||
if (ispair)
|
||||
*bp++ = (jschar) d;
|
||||
*bp = 0;
|
||||
ts->tokenbuf.ptr = bp;
|
||||
tb.shrinkBy(tb.end() - bp);
|
||||
return JS_TRUE;
|
||||
|
||||
badncr:
|
||||
msg = JSMSG_BAD_XML_NCR;
|
||||
bad:
|
||||
/* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */
|
||||
JS_ASSERT(STRING_BUFFER_OK(&ts->tokenbuf));
|
||||
JS_ASSERT((ts->tokenbuf.ptr - bp) >= 1);
|
||||
bytes = js_DeflateString(cx, bp + 1,
|
||||
(ts->tokenbuf.ptr - bp) - 1);
|
||||
JS_ASSERT((tb.end() - bp) >= 1);
|
||||
bytes = js_DeflateString(cx, bp + 1, (tb.end() - bp) - 1);
|
||||
if (bytes) {
|
||||
js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
|
||||
msg, bytes);
|
||||
|
@ -1015,6 +847,12 @@ ScanAsSpace(jschar c)
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSAtom *
|
||||
atomize(JSContext *cx, JSCharBuffer &cb)
|
||||
{
|
||||
return js_AtomizeChars(cx, cb.begin(), cb.length(), 0);
|
||||
}
|
||||
|
||||
JSTokenType
|
||||
js_GetToken(JSContext *cx, JSTokenStream *ts)
|
||||
{
|
||||
|
@ -1030,27 +868,7 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
ptrdiff_t contentIndex;
|
||||
#endif
|
||||
|
||||
#define INIT_TOKENBUF() (ts->tokenbuf.ptr = ts->tokenbuf.base)
|
||||
#define TOKENBUF_LENGTH() (ts->tokenbuf.ptr - ts->tokenbuf.base)
|
||||
#define TOKENBUF_OK() STRING_BUFFER_OK(&ts->tokenbuf)
|
||||
#define TOKENBUF_TO_ATOM() (TOKENBUF_OK() \
|
||||
? js_AtomizeChars(cx, \
|
||||
TOKENBUF_BASE(), \
|
||||
TOKENBUF_LENGTH(), \
|
||||
0) \
|
||||
: NULL)
|
||||
#define ADD_TO_TOKENBUF(c) JS_BEGIN_MACRO \
|
||||
js_FastAppendChar(&ts->tokenbuf, jschar(c)); \
|
||||
if (!TOKENBUF_OK()) \
|
||||
goto error; \
|
||||
JS_END_MACRO
|
||||
|
||||
/* The following 4 macros should only be used when TOKENBUF_OK() is true. */
|
||||
#define TOKENBUF_BASE() (ts->tokenbuf.base)
|
||||
#define TOKENBUF_END() (ts->tokenbuf.ptr)
|
||||
#define TOKENBUF_CHAR(i) (ts->tokenbuf.base[i])
|
||||
#define TRIM_TOKENBUF(i) (ts->tokenbuf.ptr = ts->tokenbuf.base + i)
|
||||
#define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0)
|
||||
JSCharBuffer &tb = ts->tokenbuf;
|
||||
|
||||
/* Check for a pushed-back token resulting from mismatching lookahead. */
|
||||
while (ts->lookahead != 0) {
|
||||
|
@ -1070,7 +888,7 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
if (ts->flags & TSF_XMLTEXTMODE) {
|
||||
tt = TOK_XMLSPACE; /* veto if non-space, return TOK_XMLTEXT */
|
||||
tp = NewToken(ts, 0);
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
qc = (ts->flags & TSF_XMLONLYMODE) ? '<' : '{';
|
||||
|
||||
while ((c = GetChar(ts)) != qc && c != '<' && c != EOF) {
|
||||
|
@ -1083,14 +901,15 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
|
||||
if (!JS_ISXMLSPACE(c))
|
||||
tt = TOK_XMLTEXT;
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
UngetChar(ts, c);
|
||||
|
||||
if (TOKENBUF_LENGTH() == 0) {
|
||||
if (tb.empty()) {
|
||||
atom = NULL;
|
||||
} else {
|
||||
atom = TOKENBUF_TO_ATOM();
|
||||
atom = atomize(cx, tb);
|
||||
if (!atom)
|
||||
goto error;
|
||||
}
|
||||
|
@ -1117,11 +936,12 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
goto out;
|
||||
}
|
||||
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
if (JS_ISXMLNSSTART(c)) {
|
||||
JSBool sawColon = JS_FALSE;
|
||||
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
while ((c = GetChar(ts)) != EOF && JS_ISXMLNAME(c)) {
|
||||
if (c == ':') {
|
||||
int nextc;
|
||||
|
@ -1138,11 +958,12 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
sawColon = JS_TRUE;
|
||||
}
|
||||
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
|
||||
UngetChar(ts, c);
|
||||
atom = TOKENBUF_TO_ATOM();
|
||||
atom = atomize(cx, tb);
|
||||
if (!atom)
|
||||
goto error;
|
||||
tp->t_op = JSOP_STRING;
|
||||
|
@ -1179,7 +1000,9 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
*/
|
||||
if (c == '"' && !(ts->flags & TSF_XMLONLYMODE)) {
|
||||
JS_ASSERT(qc == '\'');
|
||||
js_AppendCString(&ts->tokenbuf, js_quot_entity_str);
|
||||
if (!tb.append(js_quot_entity_str,
|
||||
strlen(js_quot_entity_str)))
|
||||
goto error;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1189,9 +1012,10 @@ js_GetToken(JSContext *cx, JSTokenStream *ts)
|
|||
continue;
|
||||
}
|
||||
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
atom = TOKENBUF_TO_ATOM();
|
||||
atom = atomize(cx, tb);
|
||||
if (!atom)
|
||||
goto error;
|
||||
tp->pos.end.lineno = (uint16)ts->lineno;
|
||||
|
@ -1244,9 +1068,10 @@ retry:
|
|||
hadUnicodeEscape = JS_ISIDSTART(qc)))) {
|
||||
if (hadUnicodeEscape)
|
||||
c = qc;
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
for (;;) {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
if (c == '\\') {
|
||||
qc = GetUnicodeEscape(ts);
|
||||
|
@ -1267,8 +1092,7 @@ retry:
|
|||
*/
|
||||
if (!hadUnicodeEscape &&
|
||||
!(ts->flags & TSF_KEYWORD_IS_NAME) &&
|
||||
TOKENBUF_OK() &&
|
||||
(kw = FindKeyword(TOKENBUF_BASE(), TOKENBUF_LENGTH()))) {
|
||||
(kw = FindKeyword(tb.begin(), tb.length()))) {
|
||||
if (kw->tokentype == TOK_RESERVED) {
|
||||
if (!js_ReportCompileErrorNumber(cx, ts, NULL,
|
||||
JSREPORT_WARNING |
|
||||
|
@ -1284,7 +1108,7 @@ retry:
|
|||
}
|
||||
}
|
||||
|
||||
atom = TOKENBUF_TO_ATOM();
|
||||
atom = atomize(cx, tb);
|
||||
if (!atom)
|
||||
goto error;
|
||||
tp->t_op = JSOP_NAME;
|
||||
|
@ -1299,13 +1123,15 @@ retry:
|
|||
jsdouble dval;
|
||||
|
||||
radix = 10;
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
|
||||
if (c == '0') {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
if (JS_TOLOWER(c) == 'x') {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
radix = 16;
|
||||
} else if (JS7_ISDEC(c)) {
|
||||
|
@ -1333,22 +1159,26 @@ retry:
|
|||
radix = 10;
|
||||
}
|
||||
}
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
}
|
||||
|
||||
if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) {
|
||||
if (c == '.') {
|
||||
do {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
} while (JS7_ISDEC(c));
|
||||
}
|
||||
if (JS_TOLOWER(c) == 'e') {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
if (c == '+' || c == '-') {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
}
|
||||
if (!JS7_ISDEC(c)) {
|
||||
|
@ -1357,7 +1187,8 @@ retry:
|
|||
goto error;
|
||||
}
|
||||
do {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
} while (JS7_ISDEC(c));
|
||||
}
|
||||
|
@ -1365,19 +1196,17 @@ retry:
|
|||
|
||||
/* Put back the next char and NUL-terminate tokenbuf for js_strto*. */
|
||||
UngetChar(ts, c);
|
||||
ADD_TO_TOKENBUF(0);
|
||||
|
||||
if (!TOKENBUF_OK())
|
||||
if (!tb.append(0))
|
||||
goto error;
|
||||
|
||||
if (radix == 10) {
|
||||
if (!js_strtod(cx, TOKENBUF_BASE(), TOKENBUF_END(),
|
||||
&endptr, &dval)) {
|
||||
if (!js_strtod(cx, tb.begin(), tb.end(), &endptr, &dval)) {
|
||||
js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
|
||||
JSMSG_OUT_OF_MEMORY);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (!js_strtointeger(cx, TOKENBUF_BASE(), TOKENBUF_END(),
|
||||
if (!js_strtointeger(cx, tb.begin(), tb.end(),
|
||||
&endptr, radix, &dval)) {
|
||||
js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
|
||||
JSMSG_OUT_OF_MEMORY);
|
||||
|
@ -1391,7 +1220,7 @@ retry:
|
|||
|
||||
if (c == '"' || c == '\'') {
|
||||
qc = c;
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
while ((c = GetChar(ts)) != qc) {
|
||||
if (c == '\n' || c == EOF) {
|
||||
UngetChar(ts, c);
|
||||
|
@ -1453,9 +1282,10 @@ retry:
|
|||
break;
|
||||
}
|
||||
}
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
atom = TOKENBUF_TO_ATOM();
|
||||
atom = atomize(cx, tb);
|
||||
if (!atom)
|
||||
goto error;
|
||||
tp->pos.end.lineno = (uint16)ts->lineno;
|
||||
|
@ -1593,7 +1423,7 @@ retry:
|
|||
(JS_HAS_XML_OPTION(cx) || PeekChar(ts) != '!')) {
|
||||
/* Check for XML comment or CDATA section. */
|
||||
if (MatchChar(ts, '!')) {
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
|
||||
/* Scan XML comment. */
|
||||
if (MatchChar(ts, '-')) {
|
||||
|
@ -1602,7 +1432,8 @@ retry:
|
|||
while ((c = GetChar(ts)) != '-' || !MatchChar(ts, '-')) {
|
||||
if (c == EOF)
|
||||
goto bad_xml_markup;
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
tt = TOK_XMLCOMMENT;
|
||||
tp->t_op = JSOP_XMLCOMMENT;
|
||||
|
@ -1626,7 +1457,8 @@ retry:
|
|||
cp[1] != '>') {
|
||||
if (c == EOF)
|
||||
goto bad_xml_markup;
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
GetChar(ts); /* discard ] but not > */
|
||||
tt = TOK_XMLCDATA;
|
||||
|
@ -1643,17 +1475,17 @@ retry:
|
|||
targetLength = 0;
|
||||
contentIndex = -1;
|
||||
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
while ((c = GetChar(ts)) != '?' || PeekChar(ts) != '>') {
|
||||
if (c == EOF)
|
||||
goto bad_xml_markup;
|
||||
if (inTarget) {
|
||||
if (JS_ISXMLSPACE(c)) {
|
||||
if (TOKENBUF_LENGTH() == 0)
|
||||
if (tb.empty())
|
||||
goto bad_xml_markup;
|
||||
inTarget = JS_FALSE;
|
||||
} else {
|
||||
if (!((TOKENBUF_LENGTH() == 0)
|
||||
if (!(tb.empty()
|
||||
? JS_ISXMLNSSTART(c)
|
||||
: JS_ISXMLNS(c))) {
|
||||
goto bad_xml_markup;
|
||||
|
@ -1662,32 +1494,31 @@ retry:
|
|||
}
|
||||
} else {
|
||||
if (contentIndex < 0 && !JS_ISXMLSPACE(c))
|
||||
contentIndex = TOKENBUF_LENGTH();
|
||||
contentIndex = tb.length();
|
||||
}
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
if (targetLength == 0)
|
||||
goto bad_xml_markup;
|
||||
if (!TOKENBUF_OK())
|
||||
goto error;
|
||||
if (contentIndex < 0) {
|
||||
atom = cx->runtime->atomState.emptyAtom;
|
||||
} else {
|
||||
atom = js_AtomizeChars(cx,
|
||||
&TOKENBUF_CHAR(contentIndex),
|
||||
TOKENBUF_LENGTH() - contentIndex,
|
||||
tb.begin() + contentIndex,
|
||||
tb.length() - contentIndex,
|
||||
0);
|
||||
if (!atom)
|
||||
goto error;
|
||||
}
|
||||
TRIM_TOKENBUF(targetLength);
|
||||
tb.shrinkBy(tb.length() - targetLength);
|
||||
tp->t_atom2 = atom;
|
||||
tt = TOK_XMLPI;
|
||||
|
||||
finish_xml_markup:
|
||||
if (!MatchChar(ts, '>'))
|
||||
goto bad_xml_markup;
|
||||
atom = TOKENBUF_TO_ATOM();
|
||||
atom = atomize(cx, tb);
|
||||
if (!atom)
|
||||
goto error;
|
||||
tp->t_atom = atom;
|
||||
|
@ -1849,7 +1680,7 @@ skipline:
|
|||
uintN flags, length;
|
||||
JSBool inCharClass = JS_FALSE;
|
||||
|
||||
INIT_TOKENBUF();
|
||||
tb.clear();
|
||||
for (;;) {
|
||||
c = GetChar(ts);
|
||||
if (c == '\n' || c == EOF) {
|
||||
|
@ -1859,7 +1690,8 @@ skipline:
|
|||
goto error;
|
||||
}
|
||||
if (c == '\\') {
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
c = GetChar(ts);
|
||||
} else if (c == '[') {
|
||||
inCharClass = JS_TRUE;
|
||||
|
@ -1869,9 +1701,10 @@ skipline:
|
|||
/* For compat with IE, allow unescaped / in char classes. */
|
||||
break;
|
||||
}
|
||||
ADD_TO_TOKENBUF(c);
|
||||
if (!tb.append(c))
|
||||
goto error;
|
||||
}
|
||||
for (flags = 0, length = TOKENBUF_LENGTH() + 1; ; length++) {
|
||||
for (flags = 0, length = tb.length() + 1; ; length++) {
|
||||
c = PeekChar(ts);
|
||||
if (c == 'g' && !(flags & JSREG_GLOB))
|
||||
flags |= JSREG_GLOB;
|
||||
|
@ -1895,10 +1728,6 @@ skipline:
|
|||
(void) GetChar(ts);
|
||||
goto error;
|
||||
}
|
||||
/* XXXbe fix jsregexp.c so it doesn't depend on NUL termination */
|
||||
if (!TOKENBUF_OK())
|
||||
goto error;
|
||||
NUL_TERM_TOKENBUF();
|
||||
tp->t_reflags = flags;
|
||||
tt = TOK_REGEXP;
|
||||
break;
|
||||
|
@ -2006,8 +1835,6 @@ out:
|
|||
ts->flags |= TSF_DIRTYLINE;
|
||||
|
||||
eol_out:
|
||||
if (!STRING_BUFFER_OK(&ts->tokenbuf))
|
||||
tt = TOK_ERROR;
|
||||
JS_ASSERT(tt < TOK_LIMIT);
|
||||
tp->pos.end.index = ts->linepos +
|
||||
(ts->linebuf.ptr - ts->linebuf.base) -
|
||||
|
@ -2019,16 +1846,6 @@ error:
|
|||
tt = TOK_ERROR;
|
||||
ts->flags |= TSF_ERROR;
|
||||
goto out;
|
||||
|
||||
#undef INIT_TOKENBUF
|
||||
#undef TOKENBUF_LENGTH
|
||||
#undef TOKENBUF_OK
|
||||
#undef TOKENBUF_TO_ATOM
|
||||
#undef ADD_TO_TOKENBUF
|
||||
#undef TOKENBUF_BASE
|
||||
#undef TOKENBUF_CHAR
|
||||
#undef TRIM_TOKENBUF
|
||||
#undef NUL_TERM_TOKENBUF
|
||||
}
|
||||
|
||||
void
|
||||
|
|
105
js/src/jsscan.h
105
js/src/jsscan.h
|
@ -48,6 +48,7 @@
|
|||
#include "jsopcode.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
|
@ -161,73 +162,6 @@ typedef enum JSTokenType {
|
|||
# define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR)
|
||||
#endif
|
||||
|
||||
struct JSStringBuffer {
|
||||
jschar *base;
|
||||
jschar *limit; /* length limit for quick bounds check */
|
||||
jschar *ptr; /* slot for next non-NUL char to store */
|
||||
void *data;
|
||||
JSBool (*grow)(JSStringBuffer *sb, size_t newlength);
|
||||
void (*free)(JSStringBuffer *sb);
|
||||
};
|
||||
|
||||
#define STRING_BUFFER_ERROR_BASE ((jschar *) 1)
|
||||
#define STRING_BUFFER_OK(sb) ((sb)->base != STRING_BUFFER_ERROR_BASE)
|
||||
#define STRING_BUFFER_OFFSET(sb) ((sb)->ptr -(sb)->base)
|
||||
|
||||
extern void
|
||||
js_InitStringBuffer(JSStringBuffer *sb);
|
||||
|
||||
extern void
|
||||
js_FinishStringBuffer(JSStringBuffer *sb);
|
||||
|
||||
static inline void
|
||||
js_RewindStringBuffer(JSStringBuffer *sb)
|
||||
{
|
||||
JS_ASSERT(STRING_BUFFER_OK(sb));
|
||||
sb->ptr = sb->base;
|
||||
}
|
||||
|
||||
#define ENSURE_STRING_BUFFER(sb,n) \
|
||||
((sb)->ptr + (n) <= (sb)->limit || sb->grow(sb, n))
|
||||
|
||||
/*
|
||||
* NB: callers are obligated to test STRING_BUFFER_OK(sb) after this returns,
|
||||
* before calling it again -- but not necessarily before calling other sb ops
|
||||
* declared in this header file.
|
||||
*
|
||||
* Thus multiple calls, to ops other than this one that check STRING_BUFFER_OK
|
||||
* and suppress updating sb if true, can consolidate the final STRING_BUFFER_OK
|
||||
* test that conditions a JS_ReportOutOfMemory (if necessary -- the grow hook
|
||||
* can report OOM early, obviating the need for the callers to report).
|
||||
*
|
||||
* This style of error checking is not obviously better, and it could be worse
|
||||
* in efficiency, than the propagated failure return code style used elsewhere
|
||||
* in the engine. I view it as a failed experiment. /be
|
||||
*/
|
||||
static inline void
|
||||
js_FastAppendChar(JSStringBuffer *sb, jschar c)
|
||||
{
|
||||
JS_ASSERT(STRING_BUFFER_OK(sb));
|
||||
if (!ENSURE_STRING_BUFFER(sb, 1))
|
||||
return;
|
||||
*sb->ptr++ = c;
|
||||
}
|
||||
|
||||
extern void
|
||||
js_AppendChar(JSStringBuffer *sb, jschar c);
|
||||
|
||||
extern void
|
||||
js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count);
|
||||
|
||||
extern void
|
||||
js_AppendCString(JSStringBuffer *sb, const char *asciiz);
|
||||
|
||||
extern void
|
||||
js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len);
|
||||
|
||||
extern void
|
||||
js_AppendJSString(JSStringBuffer *sb, JSString *str);
|
||||
|
||||
struct JSTokenPtr {
|
||||
uint32 index; /* index of char in physical line */
|
||||
uint32 lineno; /* physical line number */
|
||||
|
@ -320,7 +254,6 @@ struct JSTokenStream {
|
|||
uint32 linepos; /* linebuf offset in physical line */
|
||||
JSTokenBuf linebuf; /* line buffer for diagnostics */
|
||||
JSTokenBuf userbuf; /* user input buffer if !file */
|
||||
JSStringBuffer tokenbuf; /* current token string buffer */
|
||||
const char *filename; /* input filename or null */
|
||||
FILE *file; /* stdio stream if reading from file */
|
||||
JSSourceHandler listener; /* callback for source; eg debugger */
|
||||
|
@ -328,6 +261,29 @@ struct JSTokenStream {
|
|||
void *listenerTSData;/* listener data for this TokenStream */
|
||||
jschar *saveEOL; /* save next end of line in userbuf, to
|
||||
optimize for very long lines */
|
||||
JSCharBuffer tokenbuf; /* current token string buffer */
|
||||
|
||||
/*
|
||||
* To construct a JSTokenStream, first call the constructor, which is
|
||||
* infallible, then call |init|, which can fail. To destroy a JSTokenStream,
|
||||
* first call |close| then call the destructor. If |init| fails, do not call
|
||||
* |close|.
|
||||
*
|
||||
* This class uses JSContext.tempPool to allocate internal buffers. The
|
||||
* caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE
|
||||
* after calling |close|.
|
||||
*/
|
||||
JSTokenStream(JSContext *);
|
||||
|
||||
/*
|
||||
* Create a new token stream, either from an input buffer or from a file.
|
||||
* Return false on file-open or memory-allocation failure.
|
||||
*/
|
||||
bool init(JSContext *, const jschar *base, size_t length,
|
||||
FILE *fp, const char *filename, uintN lineno);
|
||||
|
||||
void close(JSContext *);
|
||||
~JSTokenStream() {}
|
||||
};
|
||||
|
||||
#define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor])
|
||||
|
@ -380,19 +336,6 @@ struct JSTokenStream {
|
|||
#define LINE_SEPARATOR 0x2028
|
||||
#define PARA_SEPARATOR 0x2029
|
||||
|
||||
/*
|
||||
* Create a new token stream, either from an input buffer or from a file.
|
||||
* Return null on file-open or memory-allocation failure.
|
||||
*
|
||||
* The function uses JSContext.tempPool to allocate internal buffers. The
|
||||
* caller should release them using JS_ARENA_RELEASE after it has finished
|
||||
* with the token stream and has called js_CloseTokenStream.
|
||||
*/
|
||||
extern JSBool
|
||||
js_InitTokenStream(JSContext *cx, JSTokenStream *ts,
|
||||
const jschar *base, size_t length,
|
||||
FILE *fp, const char *filename, uintN lineno);
|
||||
|
||||
extern void
|
||||
js_CloseTokenStream(JSContext *cx, JSTokenStream *ts);
|
||||
|
||||
|
|
|
@ -2737,7 +2737,7 @@ js_NewStringFromCharBuffer(JSContext *cx, JSCharBuffer &cb)
|
|||
if (cb.empty())
|
||||
return ATOM_TO_STRING(cx->runtime->atomState.emptyAtom);
|
||||
|
||||
size_t length = cb.size();
|
||||
size_t length = cb.length();
|
||||
if (!cb.append('\0'))
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ struct JSTempVectorImpl
|
|||
new(dst) T(*src);
|
||||
JSTempVectorImpl::destroy(v.heapBegin(), v.heapEnd());
|
||||
v.mCx->free(v.heapBegin());
|
||||
v.heapEnd() = newbuf + v.heapSize();
|
||||
v.heapEnd() = newbuf + v.heapLength();
|
||||
v.heapBegin() = newbuf;
|
||||
v.heapCapacity() = newcap;
|
||||
return true;
|
||||
|
@ -252,7 +252,7 @@ struct JSTempVectorImpl<T, N, true>
|
|||
T *newbuf = reinterpret_cast<T *>(v.mCx->realloc(v.heapBegin(), bytes));
|
||||
if (!newbuf)
|
||||
return false;
|
||||
v.heapEnd() = newbuf + v.heapSize();
|
||||
v.heapEnd() = newbuf + v.heapLength();
|
||||
v.heapBegin() = newbuf;
|
||||
v.heapCapacity() = newcap;
|
||||
return true;
|
||||
|
@ -282,9 +282,9 @@ class JSTempVector
|
|||
typedef JSTempVectorImpl<T, N, JSUtils::IsPodType<T>::result> Impl;
|
||||
friend struct JSTempVectorImpl<T, N, JSUtils::IsPodType<T>::result>;
|
||||
|
||||
bool calculateNewCapacity(size_t curSize, size_t sizeInc, size_t &newCap);
|
||||
bool growHeapStorageBy(size_t sizeInc);
|
||||
bool convertToHeapStorage(size_t sizeInc);
|
||||
bool calculateNewCapacity(size_t curLength, size_t lengthInc, size_t &newCap);
|
||||
bool growHeapStorageBy(size_t lengthInc);
|
||||
bool convertToHeapStorage(size_t lengthInc);
|
||||
|
||||
/* magic constants */
|
||||
|
||||
|
@ -303,10 +303,10 @@ class JSTempVector
|
|||
|
||||
/*
|
||||
* Since a vector either stores elements inline or in a heap-allocated
|
||||
* buffer, reuse the storage. mSizeOrCapacity serves as the union
|
||||
* buffer, reuse the storage. mLengthOrCapacity serves as the union
|
||||
* discriminator. In inline mode (when elements are stored in u.mBuf),
|
||||
* mSizeOrCapacity holds the vector's size. In heap mode (when elements
|
||||
* are stored in [u.ptrs.mBegin, u.ptrs.mEnd)), mSizeOrCapacity holds the
|
||||
* mLengthOrCapacity holds the vector's length. In heap mode (when elements
|
||||
* are stored in [u.ptrs.mBegin, u.ptrs.mEnd)), mLengthOrCapacity holds the
|
||||
* vector's capacity.
|
||||
*/
|
||||
static const size_t sInlineCapacity =
|
||||
|
@ -317,8 +317,8 @@ class JSTempVector
|
|||
|
||||
JSContext *mCx;
|
||||
|
||||
size_t mSizeOrCapacity;
|
||||
bool usingInlineStorage() const { return mSizeOrCapacity <= sInlineCapacity; }
|
||||
size_t mLengthOrCapacity;
|
||||
bool usingInlineStorage() const { return mLengthOrCapacity <= sInlineCapacity; }
|
||||
|
||||
union {
|
||||
BufferPtrs ptrs;
|
||||
|
@ -326,14 +326,14 @@ class JSTempVector
|
|||
} u;
|
||||
|
||||
/* Only valid when usingInlineStorage() */
|
||||
size_t &inlineSize() {
|
||||
size_t &inlineLength() {
|
||||
JS_ASSERT(usingInlineStorage());
|
||||
return mSizeOrCapacity;
|
||||
return mLengthOrCapacity;
|
||||
}
|
||||
|
||||
size_t inlineSize() const {
|
||||
size_t inlineLength() const {
|
||||
JS_ASSERT(usingInlineStorage());
|
||||
return mSizeOrCapacity;
|
||||
return mLengthOrCapacity;
|
||||
}
|
||||
|
||||
T *inlineBegin() const {
|
||||
|
@ -343,11 +343,11 @@ class JSTempVector
|
|||
|
||||
T *inlineEnd() const {
|
||||
JS_ASSERT(usingInlineStorage());
|
||||
return ((T *)u.mBuf) + mSizeOrCapacity;
|
||||
return ((T *)u.mBuf) + mLengthOrCapacity;
|
||||
}
|
||||
|
||||
/* Only valid when !usingInlineStorage() */
|
||||
size_t heapSize() const {
|
||||
size_t heapLength() const {
|
||||
JS_ASSERT(!usingInlineStorage());
|
||||
/* Guaranteed by calculateNewCapacity. */
|
||||
JS_ASSERT(size_t(u.ptrs.mEnd - u.ptrs.mBegin) ==
|
||||
|
@ -357,7 +357,7 @@ class JSTempVector
|
|||
|
||||
size_t &heapCapacity() {
|
||||
JS_ASSERT(!usingInlineStorage());
|
||||
return mSizeOrCapacity;
|
||||
return mLengthOrCapacity;
|
||||
}
|
||||
|
||||
T *&heapBegin() {
|
||||
|
@ -372,7 +372,7 @@ class JSTempVector
|
|||
|
||||
size_t heapCapacity() const {
|
||||
JS_ASSERT(!usingInlineStorage());
|
||||
return mSizeOrCapacity;
|
||||
return mLengthOrCapacity;
|
||||
}
|
||||
|
||||
T *heapBegin() const {
|
||||
|
@ -413,7 +413,7 @@ class JSTempVector
|
|||
|
||||
public:
|
||||
JSTempVector(JSContext *cx)
|
||||
: mCx(cx), mSizeOrCapacity(0)
|
||||
: mCx(cx), mLengthOrCapacity(0)
|
||||
#ifdef DEBUG
|
||||
, mInProgress(false)
|
||||
#endif
|
||||
|
@ -422,12 +422,12 @@ class JSTempVector
|
|||
|
||||
/* accessors */
|
||||
|
||||
size_t size() const {
|
||||
return usingInlineStorage() ? inlineSize() : heapSize();
|
||||
size_t length() const {
|
||||
return usingInlineStorage() ? inlineLength() : heapLength();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return usingInlineStorage() ? inlineSize() == 0 : heapBegin() == heapEnd();
|
||||
return usingInlineStorage() ? inlineLength() == 0 : heapBegin() == heapEnd();
|
||||
}
|
||||
|
||||
size_t capacity() const {
|
||||
|
@ -455,12 +455,12 @@ class JSTempVector
|
|||
}
|
||||
|
||||
T &operator[](size_t i) {
|
||||
JS_ASSERT(!mInProgress && i < size());
|
||||
JS_ASSERT(!mInProgress && i < length());
|
||||
return begin()[i];
|
||||
}
|
||||
|
||||
const T &operator[](size_t i) const {
|
||||
JS_ASSERT(!mInProgress && i < size());
|
||||
JS_ASSERT(!mInProgress && i < length());
|
||||
return begin()[i];
|
||||
}
|
||||
|
||||
|
@ -489,8 +489,8 @@ class JSTempVector
|
|||
*/
|
||||
bool growBy(size_t incr);
|
||||
|
||||
/* Call shrinkBy or growBy based on whether newSize > size(). */
|
||||
bool resize(size_t newSize);
|
||||
/* Call shrinkBy or growBy based on whether newSize > length(). */
|
||||
bool resize(size_t newLength);
|
||||
|
||||
void clear();
|
||||
|
||||
|
@ -507,7 +507,7 @@ class JSTempVector
|
|||
* buffer may need to be allocated (if the elements are currently
|
||||
* stored in-place), the call can fail, returning NULL.
|
||||
*
|
||||
* N.B. Although a T*, only the range [0, size()) is constructed.
|
||||
* N.B. Although a T*, only the range [0, length()) is constructed.
|
||||
*/
|
||||
T *extractRawBuffer();
|
||||
|
||||
|
@ -526,11 +526,11 @@ class JSTempVector
|
|||
* literal to a vector. This could not be done generically since one must take
|
||||
* care not to append the terminating '\0'.
|
||||
*/
|
||||
template <class T, size_t N, size_t ArraySize>
|
||||
template <class T, size_t N, size_t ArrayLength>
|
||||
bool
|
||||
js_AppendLiteral(JSTempVector<T,N> &v, const char (&array)[ArraySize])
|
||||
js_AppendLiteral(JSTempVector<T,N> &v, const char (&array)[ArrayLength])
|
||||
{
|
||||
return v.append(array, array + ArraySize - 1);
|
||||
return v.append(array, array + ArrayLength - 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -550,21 +550,21 @@ JSTempVector<T,N>::~JSTempVector()
|
|||
}
|
||||
|
||||
/*
|
||||
* Calculate a new capacity size that is at least sizeInc greater than
|
||||
* curSize and check for overflow.
|
||||
* Calculate a new capacity that is at least lengthInc greater than
|
||||
* curLength and check for overflow.
|
||||
*/
|
||||
template <class T, size_t N>
|
||||
inline bool
|
||||
JSTempVector<T,N>::calculateNewCapacity(size_t curSize, size_t sizeInc,
|
||||
JSTempVector<T,N>::calculateNewCapacity(size_t curLength, size_t lengthInc,
|
||||
size_t &newCap)
|
||||
{
|
||||
size_t newMinCap = curSize + sizeInc;
|
||||
size_t newMinCap = curLength + lengthInc;
|
||||
|
||||
/*
|
||||
* Check for overflow in the above addition, below CEILING_LOG2, and later
|
||||
* multiplication by sizeof(T).
|
||||
*/
|
||||
if (newMinCap < curSize ||
|
||||
if (newMinCap < curLength ||
|
||||
newMinCap & JSUtils::MulOverflowMask<2 * sizeof(T)>::result) {
|
||||
js_ReportAllocationOverflow(mCx);
|
||||
return false;
|
||||
|
@ -589,28 +589,28 @@ JSTempVector<T,N>::calculateNewCapacity(size_t curSize, size_t sizeInc,
|
|||
|
||||
/*
|
||||
* This function will grow the current heap capacity to have capacity
|
||||
* (heapSize() + sizeInc) and fail on OOM or integer overflow.
|
||||
* (heapLength() + lengthInc) and fail on OOM or integer overflow.
|
||||
*/
|
||||
template <class T, size_t N>
|
||||
inline bool
|
||||
JSTempVector<T,N>::growHeapStorageBy(size_t sizeInc)
|
||||
JSTempVector<T,N>::growHeapStorageBy(size_t lengthInc)
|
||||
{
|
||||
size_t newCap;
|
||||
return calculateNewCapacity(heapSize(), sizeInc, newCap) &&
|
||||
return calculateNewCapacity(heapLength(), lengthInc, newCap) &&
|
||||
Impl::growTo(*this, newCap);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will create a new heap buffer with capacity (inlineSize() +
|
||||
* sizeInc()), move all elements in the inline buffer to this new buffer,
|
||||
* This function will create a new heap buffer with capacity (inlineLength() +
|
||||
* lengthInc()), move all elements in the inline buffer to this new buffer,
|
||||
* and fail on OOM or integer overflow.
|
||||
*/
|
||||
template <class T, size_t N>
|
||||
inline bool
|
||||
JSTempVector<T,N>::convertToHeapStorage(size_t sizeInc)
|
||||
JSTempVector<T,N>::convertToHeapStorage(size_t lengthInc)
|
||||
{
|
||||
size_t newCap;
|
||||
if (!calculateNewCapacity(inlineSize(), sizeInc, newCap))
|
||||
if (!calculateNewCapacity(inlineLength(), lengthInc, newCap))
|
||||
return false;
|
||||
|
||||
/* Allocate buffer. */
|
||||
|
@ -619,14 +619,14 @@ JSTempVector<T,N>::convertToHeapStorage(size_t sizeInc)
|
|||
return false;
|
||||
|
||||
/* Copy inline elements into heap buffer. */
|
||||
size_t size = inlineSize();
|
||||
size_t length = inlineLength();
|
||||
Impl::copyConstruct(newBuf, inlineBegin(), inlineEnd());
|
||||
Impl::destroy(inlineBegin(), inlineEnd());
|
||||
|
||||
/* Switch in heap buffer. */
|
||||
mSizeOrCapacity = newCap; /* marks us as !usingInlineStorage() */
|
||||
mLengthOrCapacity = newCap; /* marks us as !usingInlineStorage() */
|
||||
heapBegin() = newBuf;
|
||||
heapEnd() = newBuf + size;
|
||||
heapEnd() = newBuf + length;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -637,10 +637,10 @@ JSTempVector<T,N>::reserve(size_t request)
|
|||
ReentrancyGuard g(*this);
|
||||
if (usingInlineStorage()) {
|
||||
if (request > sInlineCapacity)
|
||||
return convertToHeapStorage(request - inlineSize());
|
||||
return convertToHeapStorage(request - inlineLength());
|
||||
} else {
|
||||
if (request > heapCapacity())
|
||||
return growHeapStorageBy(request - heapSize());
|
||||
return growHeapStorageBy(request - heapLength());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -650,10 +650,10 @@ inline void
|
|||
JSTempVector<T,N>::shrinkBy(size_t incr)
|
||||
{
|
||||
ReentrancyGuard g(*this);
|
||||
JS_ASSERT(incr <= size());
|
||||
JS_ASSERT(incr <= length());
|
||||
if (usingInlineStorage()) {
|
||||
Impl::destroy(inlineEnd() - incr, inlineEnd());
|
||||
inlineSize() -= incr;
|
||||
inlineLength() -= incr;
|
||||
} else {
|
||||
Impl::destroy(heapEnd() - incr, heapEnd());
|
||||
heapEnd() -= incr;
|
||||
|
@ -666,12 +666,12 @@ JSTempVector<T,N>::growBy(size_t incr)
|
|||
{
|
||||
ReentrancyGuard g(*this);
|
||||
if (usingInlineStorage()) {
|
||||
size_t freespace = sInlineCapacity - inlineSize();
|
||||
size_t freespace = sInlineCapacity - inlineLength();
|
||||
if (incr <= freespace) {
|
||||
T *newend = inlineEnd() + incr;
|
||||
if (!JSUtils::IsPodType<T>::result)
|
||||
Impl::initialize(inlineEnd(), newend);
|
||||
inlineSize() += incr;
|
||||
inlineLength() += incr;
|
||||
JS_ASSERT(usingInlineStorage());
|
||||
return true;
|
||||
}
|
||||
|
@ -680,7 +680,7 @@ JSTempVector<T,N>::growBy(size_t incr)
|
|||
}
|
||||
else {
|
||||
/* grow if needed */
|
||||
size_t freespace = heapCapacity() - heapSize();
|
||||
size_t freespace = heapCapacity() - heapLength();
|
||||
if (incr > freespace) {
|
||||
if (!growHeapStorageBy(incr))
|
||||
return false;
|
||||
|
@ -688,7 +688,7 @@ JSTempVector<T,N>::growBy(size_t incr)
|
|||
}
|
||||
|
||||
/* We are !usingInlineStorage(). Initialize new elements. */
|
||||
JS_ASSERT(heapCapacity() - heapSize() >= incr);
|
||||
JS_ASSERT(heapCapacity() - heapLength() >= incr);
|
||||
T *newend = heapEnd() + incr;
|
||||
if (!JSUtils::IsPodType<T>::result)
|
||||
Impl::initialize(heapEnd(), newend);
|
||||
|
@ -698,12 +698,12 @@ JSTempVector<T,N>::growBy(size_t incr)
|
|||
|
||||
template <class T, size_t N>
|
||||
inline bool
|
||||
JSTempVector<T,N>::resize(size_t newsize)
|
||||
JSTempVector<T,N>::resize(size_t newLength)
|
||||
{
|
||||
size_t cursize = size();
|
||||
if (newsize > cursize)
|
||||
return growBy(newsize - cursize);
|
||||
shrinkBy(cursize - newsize);
|
||||
size_t curLength = length();
|
||||
if (newLength > curLength)
|
||||
return growBy(newLength - curLength);
|
||||
shrinkBy(curLength - newLength);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -714,7 +714,7 @@ JSTempVector<T,N>::clear()
|
|||
ReentrancyGuard g(*this);
|
||||
if (usingInlineStorage()) {
|
||||
Impl::destroy(inlineBegin(), inlineEnd());
|
||||
inlineSize() = 0;
|
||||
inlineLength() = 0;
|
||||
}
|
||||
else {
|
||||
Impl::destroy(heapBegin(), heapEnd());
|
||||
|
@ -728,21 +728,21 @@ JSTempVector<T,N>::append(const T &t)
|
|||
{
|
||||
ReentrancyGuard g(*this);
|
||||
if (usingInlineStorage()) {
|
||||
if (inlineSize() < sInlineCapacity) {
|
||||
if (inlineLength() < sInlineCapacity) {
|
||||
new(inlineEnd()) T(t);
|
||||
++inlineSize();
|
||||
++inlineLength();
|
||||
JS_ASSERT(usingInlineStorage());
|
||||
return true;
|
||||
}
|
||||
if (!convertToHeapStorage(1))
|
||||
return false;
|
||||
} else {
|
||||
if (heapSize() == heapCapacity() && !growHeapStorageBy(1))
|
||||
if (heapLength() == heapCapacity() && !growHeapStorageBy(1))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We are !usingInlineStorage(). Initialize new elements. */
|
||||
JS_ASSERT(heapSize() <= heapCapacity() && heapCapacity() - heapSize() >= 1);
|
||||
JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= 1);
|
||||
new(heapEnd()++) T(t);
|
||||
return true;
|
||||
}
|
||||
|
@ -753,23 +753,23 @@ JSTempVector<T,N>::appendN(const T &t, size_t needed)
|
|||
{
|
||||
ReentrancyGuard g(*this);
|
||||
if (usingInlineStorage()) {
|
||||
size_t freespace = sInlineCapacity - inlineSize();
|
||||
size_t freespace = sInlineCapacity - inlineLength();
|
||||
if (needed <= freespace) {
|
||||
Impl::copyConstructN(inlineEnd(), needed, t);
|
||||
inlineSize() += needed;
|
||||
inlineLength() += needed;
|
||||
JS_ASSERT(usingInlineStorage());
|
||||
return true;
|
||||
}
|
||||
if (!convertToHeapStorage(needed))
|
||||
return false;
|
||||
} else {
|
||||
size_t freespace = heapCapacity() - heapSize();
|
||||
size_t freespace = heapCapacity() - heapLength();
|
||||
if (needed > freespace && !growHeapStorageBy(needed))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We are !usingInlineStorage(). Initialize new elements. */
|
||||
JS_ASSERT(heapSize() <= heapCapacity() && heapCapacity() - heapSize() >= needed);
|
||||
JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= needed);
|
||||
Impl::copyConstructN(heapEnd(), needed, t);
|
||||
heapEnd() += needed;
|
||||
return true;
|
||||
|
@ -783,23 +783,23 @@ JSTempVector<T,N>::append(const U *insBegin, const U *insEnd)
|
|||
ReentrancyGuard g(*this);
|
||||
size_t needed = JSUtils::PointerRangeSize(insBegin, insEnd);
|
||||
if (usingInlineStorage()) {
|
||||
size_t freespace = sInlineCapacity - inlineSize();
|
||||
size_t freespace = sInlineCapacity - inlineLength();
|
||||
if (needed <= freespace) {
|
||||
Impl::copyConstruct(inlineEnd(), insBegin, insEnd);
|
||||
inlineSize() += needed;
|
||||
inlineLength() += needed;
|
||||
JS_ASSERT(usingInlineStorage());
|
||||
return true;
|
||||
}
|
||||
if (!convertToHeapStorage(needed))
|
||||
return false;
|
||||
} else {
|
||||
size_t freespace = heapCapacity() - heapSize();
|
||||
size_t freespace = heapCapacity() - heapLength();
|
||||
if (needed > freespace && !growHeapStorageBy(needed))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We are !usingInlineStorage(). Initialize new elements. */
|
||||
JS_ASSERT(heapSize() <= heapCapacity() && heapCapacity() - heapSize() >= needed);
|
||||
JS_ASSERT(heapLength() <= heapCapacity() && heapCapacity() - heapLength() >= needed);
|
||||
Impl::copyConstruct(heapEnd(), insBegin, insEnd);
|
||||
heapEnd() += needed;
|
||||
return true;
|
||||
|
@ -820,7 +820,7 @@ JSTempVector<T,N>::popBack()
|
|||
ReentrancyGuard g(*this);
|
||||
JS_ASSERT(!empty());
|
||||
if (usingInlineStorage()) {
|
||||
--inlineSize();
|
||||
--inlineLength();
|
||||
inlineEnd()->~T();
|
||||
} else {
|
||||
--heapEnd();
|
||||
|
@ -833,17 +833,17 @@ inline T *
|
|||
JSTempVector<T,N>::extractRawBuffer()
|
||||
{
|
||||
if (usingInlineStorage()) {
|
||||
T *ret = reinterpret_cast<T *>(mCx->malloc(inlineSize() * sizeof(T)));
|
||||
T *ret = reinterpret_cast<T *>(mCx->malloc(inlineLength() * sizeof(T)));
|
||||
if (!ret)
|
||||
return NULL;
|
||||
Impl::copyConstruct(ret, inlineBegin(), inlineEnd());
|
||||
Impl::destroy(inlineBegin(), inlineEnd());
|
||||
inlineSize() = 0;
|
||||
inlineLength() = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
T *ret = heapBegin();
|
||||
mSizeOrCapacity = 0; /* marks us as !usingInlineStorage() */
|
||||
mLengthOrCapacity = 0; /* marks us as !usingInlineStorage() */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -856,7 +856,7 @@ JSTempVector<T,N>::replaceRawBuffer(T *p, size_t length)
|
|||
/* Destroy what we have. */
|
||||
if (usingInlineStorage()) {
|
||||
Impl::destroy(inlineBegin(), inlineEnd());
|
||||
inlineSize() = 0;
|
||||
inlineLength() = 0;
|
||||
} else {
|
||||
Impl::destroy(heapBegin(), heapEnd());
|
||||
mCx->free(heapBegin());
|
||||
|
@ -865,15 +865,15 @@ JSTempVector<T,N>::replaceRawBuffer(T *p, size_t length)
|
|||
/* Take in the new buffer. */
|
||||
if (length <= sInlineCapacity) {
|
||||
/*
|
||||
* (mSizeOrCapacity <= sInlineCapacity) means inline storage, so we MUST
|
||||
* use inline storage, even though p might otherwise be acceptable.
|
||||
* (mLengthOrCapacity <= sInlineCapacity) means inline storage, so we
|
||||
* MUST use inline storage, even though p might otherwise be acceptable.
|
||||
*/
|
||||
mSizeOrCapacity = length; /* marks us as usingInlineStorage() */
|
||||
mLengthOrCapacity = length; /* marks us as usingInlineStorage() */
|
||||
Impl::copyConstruct(inlineBegin(), p, p + length);
|
||||
Impl::destroy(p, p + length);
|
||||
mCx->free(p);
|
||||
} else {
|
||||
mSizeOrCapacity = length; /* marks us as !usingInlineStorage() */
|
||||
mLengthOrCapacity = length; /* marks us as !usingInlineStorage() */
|
||||
heapBegin() = p;
|
||||
heapEnd() = heapBegin() + length;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче