зеркало из https://github.com/mozilla/gecko-dev.git
JS1.3 initial check-in
This commit is contained in:
Родитель
a2bf16e4c8
Коммит
e75cafd1e9
|
@ -0,0 +1,531 @@
|
|||
/* -*- Mode: C; tab-width: 8; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prlog.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsobj.h" /* js_XDRObject */
|
||||
#include "jsstr.h"
|
||||
#include "jsxdrapi.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(x) x
|
||||
#else
|
||||
#define DBG(x) ((void)0)
|
||||
#endif
|
||||
|
||||
typedef struct JSXDRMemState {
|
||||
JSXDRState state;
|
||||
uint32 count;
|
||||
uint32 limit;
|
||||
} JSXDRMemState;
|
||||
|
||||
#define MEM_BLOCK 8192
|
||||
#define MEM_PRIV(xdr) ((JSXDRMemState *)(xdr))
|
||||
|
||||
#define MEM_COUNT(xdr) (MEM_PRIV(xdr)->count)
|
||||
#define MEM_LIMIT(xdr) (MEM_PRIV(xdr)->limit)
|
||||
|
||||
static char unexpected_end_of_data_str[] = "unexpected end of data";
|
||||
|
||||
#define MEM_LEFT(xdr, bytes) \
|
||||
PR_BEGIN_MACRO \
|
||||
if ((xdr)->mode == JSXDR_DECODE && \
|
||||
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
|
||||
JS_ReportError((xdr)->cx, unexpected_end_of_data_str); \
|
||||
return 0; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
/* XXXbe why does NEED even allow or cope with non-ENCODE mode? */
|
||||
#define MEM_NEED(xdr, bytes) \
|
||||
PR_BEGIN_MACRO \
|
||||
if ((xdr)->mode == JSXDR_ENCODE) { \
|
||||
if (MEM_LIMIT(xdr) && \
|
||||
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
|
||||
void *_data = JS_realloc((xdr)->cx, \
|
||||
(xdr)->data, \
|
||||
MEM_LIMIT(xdr) + MEM_BLOCK); \
|
||||
if (!_data) \
|
||||
return 0; \
|
||||
(xdr)->data = _data; \
|
||||
MEM_LIMIT(xdr) += MEM_BLOCK; \
|
||||
} \
|
||||
} else { \
|
||||
if (MEM_LIMIT(xdr) < MEM_COUNT(xdr) + bytes) { \
|
||||
JS_ReportError((xdr)->cx, unexpected_end_of_data_str); \
|
||||
return 0; \
|
||||
} \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
#define MEM_DATA(xdr) ((void *)((char *)(xdr)->data + MEM_COUNT(xdr)))
|
||||
#define MEM_INCR(xdr,bytes) (MEM_COUNT(xdr) += (bytes))
|
||||
|
||||
static JSBool
|
||||
mem_get32(JSXDRState *xdr, uint32 *lp)
|
||||
{
|
||||
MEM_LEFT(xdr, 4);
|
||||
*lp = *(uint32 *)MEM_DATA(xdr);
|
||||
MEM_INCR(xdr, 4);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
mem_set32(JSXDRState *xdr, uint32 *lp)
|
||||
{
|
||||
MEM_NEED(xdr, 4);
|
||||
*(uint32 *)MEM_DATA(xdr) = *lp;
|
||||
MEM_INCR(xdr, 4);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
mem_getbytes(JSXDRState *xdr, char **bytesp, uint32 len)
|
||||
{
|
||||
MEM_LEFT(xdr, len);
|
||||
memcpy(*bytesp, MEM_DATA(xdr), len);
|
||||
MEM_INCR(xdr, len);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
mem_setbytes(JSXDRState *xdr, char **bytesp, uint32 len)
|
||||
{
|
||||
MEM_NEED(xdr, len);
|
||||
memcpy(MEM_DATA(xdr), *bytesp, len);
|
||||
MEM_INCR(xdr, len);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static void *
|
||||
mem_raw(JSXDRState *xdr, uint32 len)
|
||||
{
|
||||
void *data;
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
MEM_NEED(xdr, len);
|
||||
} else if (xdr->mode == JSXDR_DECODE) {
|
||||
MEM_LEFT(xdr, len);
|
||||
}
|
||||
data = MEM_DATA(xdr);
|
||||
MEM_INCR(xdr, len);
|
||||
return data;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence)
|
||||
{
|
||||
switch (whence) {
|
||||
case JSXDR_SEEK_CUR:
|
||||
if ((int32)MEM_COUNT(xdr) + offset < 0) {
|
||||
JS_ReportError(xdr->cx, "illegal seek beyond start");
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (offset > 0)
|
||||
MEM_NEED(xdr, offset);
|
||||
MEM_COUNT(xdr) += offset;
|
||||
return JS_TRUE;
|
||||
case JSXDR_SEEK_SET:
|
||||
if (offset < 0) {
|
||||
JS_ReportError(xdr->cx, "illegal seek beyond start");
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
if ((uint32)offset > MEM_COUNT(xdr))
|
||||
MEM_NEED(xdr, offset - MEM_COUNT(xdr));
|
||||
MEM_COUNT(xdr) = offset;
|
||||
} else {
|
||||
if ((uint32)offset > MEM_LIMIT(xdr)) {
|
||||
JS_ReportError(xdr->cx, "illegal seek beyond end");
|
||||
return JS_FALSE;
|
||||
}
|
||||
MEM_COUNT(xdr) = offset;
|
||||
}
|
||||
return JS_TRUE;
|
||||
case JSXDR_SEEK_END:
|
||||
if (offset >= 0 ||
|
||||
xdr->mode == JSXDR_ENCODE ||
|
||||
(int32)MEM_LIMIT(xdr) + offset < 0) {
|
||||
JS_ReportError(xdr->cx, "illegal end-based seek");
|
||||
return JS_FALSE;
|
||||
}
|
||||
MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset;
|
||||
return JS_TRUE;
|
||||
default:
|
||||
JS_ReportError(xdr->cx, "unknown seek whence: %d", whence);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32
|
||||
mem_tell(JSXDRState *xdr)
|
||||
{
|
||||
return MEM_COUNT(xdr);
|
||||
}
|
||||
|
||||
static void
|
||||
mem_finalize(JSXDRState *xdr)
|
||||
{
|
||||
JSContext *cx = xdr->cx;
|
||||
JS_free(cx, xdr->data);
|
||||
}
|
||||
|
||||
static JSXDROps xdrmem_ops = {
|
||||
mem_get32, mem_set32, mem_getbytes, mem_setbytes,
|
||||
mem_raw, mem_seek, mem_tell, mem_finalize
|
||||
};
|
||||
|
||||
void
|
||||
JS_XDRNewBase(JSContext *cx, JSXDRState *xdr, JSXDRMode mode)
|
||||
{
|
||||
xdr->cx = cx;
|
||||
xdr->mode = mode;
|
||||
xdr->registry = NULL;
|
||||
xdr->nclasses = 0;
|
||||
}
|
||||
|
||||
JSXDRState *
|
||||
JS_XDRNewMem(JSContext *cx, JSXDRMode mode)
|
||||
{
|
||||
JSXDRState *xdr = JS_malloc(cx, sizeof(JSXDRMemState));
|
||||
if (!xdr)
|
||||
return NULL;
|
||||
JS_XDRNewBase(cx, xdr, mode);
|
||||
if (mode == JSXDR_ENCODE) {
|
||||
if (!(xdr->data = JS_malloc(cx, MEM_BLOCK))) {
|
||||
JS_free(cx, xdr);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* XXXbe ok, so better not deref xdr->data if not ENCODE */
|
||||
xdr->data = NULL;
|
||||
}
|
||||
xdr->ops = &xdrmem_ops;
|
||||
MEM_PRIV(xdr)->count = 0;
|
||||
MEM_PRIV(xdr)->limit = MEM_BLOCK;
|
||||
return xdr;
|
||||
}
|
||||
|
||||
void *
|
||||
JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp)
|
||||
{
|
||||
if (xdr->ops != &xdrmem_ops)
|
||||
return NULL;
|
||||
*lp = MEM_PRIV(xdr)->count;
|
||||
return xdr->data;
|
||||
}
|
||||
|
||||
void
|
||||
JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len)
|
||||
{
|
||||
if (xdr->ops != &xdrmem_ops)
|
||||
return;
|
||||
MEM_PRIV(xdr)->limit = len;
|
||||
xdr->data = data;
|
||||
MEM_PRIV(xdr)->count = 0;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRUint8(JSXDRState *xdr, uint8 *b)
|
||||
{
|
||||
uint32 l = *b;
|
||||
if (!JS_XDRUint32(xdr, &l))
|
||||
return JS_FALSE;
|
||||
*b = (uint8) l & 0xff;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRUint16(JSXDRState *xdr, uint16 *s)
|
||||
{
|
||||
uint32 l = *s;
|
||||
if (!JS_XDRUint32(xdr, &l))
|
||||
return JS_FALSE;
|
||||
*s = (uint16) l & 0xffff;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRUint32(JSXDRState *xdr, uint32 *lp)
|
||||
{
|
||||
JSBool ok;
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
uint32 xl = JSXDR_SWAB32(*lp);
|
||||
ok = xdr->ops->set32(xdr, &xl);
|
||||
} else if (xdr->mode == JSXDR_DECODE) {
|
||||
ok = xdr->ops->get32(xdr, lp);
|
||||
*lp = JSXDR_SWAB32(*lp);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRBytes(JSXDRState *xdr, char **bytesp, uint32 len)
|
||||
{
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
if (!xdr->ops->setbytes(xdr, bytesp, len))
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
if (!xdr->ops->getbytes(xdr, bytesp, len))
|
||||
return JS_FALSE;
|
||||
}
|
||||
len = xdr->ops->tell(xdr);
|
||||
if (len % JSXDR_ALIGN) {
|
||||
if (!xdr->ops->seek(xdr, JSXDR_ALIGN - (len % JSXDR_ALIGN),
|
||||
JSXDR_SEEK_CUR)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert between a C string and the XDR representation:
|
||||
* leading 32-bit count, then counted vector of chars,
|
||||
* then possibly \0 padding to multiple of 4.
|
||||
*/
|
||||
JSBool
|
||||
JS_XDRCString(JSXDRState *xdr, char **sp)
|
||||
{
|
||||
uint32 len;
|
||||
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
len = strlen(*sp);
|
||||
JS_XDRUint32(xdr, &len);
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
if (!(*sp = JS_malloc(xdr->cx, len + 1)))
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!JS_XDRBytes(xdr, sp, len)) {
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
JS_free(xdr->cx, *sp);
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
(*sp)[len] = '\0';
|
||||
} else if (xdr->mode == JSXDR_FREE) {
|
||||
JS_free(xdr->cx, *sp);
|
||||
*sp = NULL;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRCStringOrNull(JSXDRState *xdr, char **sp)
|
||||
{
|
||||
uint32 null = (*sp == NULL);
|
||||
if (!JS_XDRUint32(xdr, &null))
|
||||
return JS_FALSE;
|
||||
if (null) {
|
||||
*sp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
return JS_XDRCString(xdr, sp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert between a JS (Unicode) string and the XDR representation.
|
||||
*/
|
||||
JSBool
|
||||
JS_XDRString(JSXDRState *xdr, JSString **strp)
|
||||
{
|
||||
uint32 i, len, nbytes;
|
||||
jschar *chars, *raw;
|
||||
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
len = (*strp)->length;
|
||||
if (!JS_XDRUint32(xdr, &len))
|
||||
return JS_FALSE;
|
||||
nbytes = len * sizeof(jschar);
|
||||
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
chars = (*strp)->chars;
|
||||
} else if (xdr->mode == JSXDR_DECODE) {
|
||||
if (!(chars = JS_malloc(xdr->cx, nbytes + sizeof(jschar))))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (nbytes % JSXDR_ALIGN)
|
||||
nbytes += JSXDR_ALIGN - (nbytes % JSXDR_ALIGN);
|
||||
if (!(raw = xdr->ops->raw(xdr, nbytes)))
|
||||
goto bad;
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
for (i = 0; i < len; i++)
|
||||
raw[i] = JSXDR_SWAB16(chars[i]);
|
||||
} else if (xdr->mode == JSXDR_DECODE) {
|
||||
for (i = 0; i < len; i++)
|
||||
chars[i] = JSXDR_SWAB16(raw[i]);
|
||||
if (!(*strp = JS_NewUCString(xdr->cx, chars, len)))
|
||||
goto bad;
|
||||
}
|
||||
return JS_TRUE;
|
||||
|
||||
bad:
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
JS_free(xdr->cx, chars);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp)
|
||||
{
|
||||
uint32 null = (*strp == NULL);
|
||||
if (!JS_XDRUint32(xdr, &null))
|
||||
return JS_FALSE;
|
||||
if (null) {
|
||||
*strp = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
return JS_XDRString(xdr, strp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRDouble(JSXDRState *xdr, jsdouble **dp)
|
||||
{
|
||||
jsdouble d;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
d = **dp;
|
||||
#if IS_BIG_ENDIAN
|
||||
if (!JS_XDRUint32(xdr, (uint32 *)&d + 1) ||
|
||||
!JS_XDRUint32(xdr, (uint32 *)&d))
|
||||
#else /* !IS_BIG_ENDIAN */
|
||||
if (!JS_XDRUint32(xdr, (uint32 *)&d) ||
|
||||
!JS_XDRUint32(xdr, (uint32 *)&d + 1))
|
||||
#endif /* IS_BIG_ENDIAN */
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
*dp = JS_NewDouble(xdr->cx, d);
|
||||
if (!*dp)
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
JS_XDRValue(JSXDRState *xdr, jsval *vp)
|
||||
{
|
||||
uint32 type = JSVAL_TAG(*vp);
|
||||
if (!JS_XDRUint32(xdr, &type))
|
||||
return JS_FALSE;
|
||||
|
||||
switch (type) {
|
||||
case JSVAL_STRING: {
|
||||
JSString *str = JSVAL_TO_STRING(*vp);
|
||||
if (!JS_XDRString(xdr, &str))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
break;
|
||||
}
|
||||
case JSVAL_DOUBLE: {
|
||||
jsdouble *dp;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
dp = JSVAL_TO_DOUBLE(*vp);
|
||||
if (!JS_XDRDouble(xdr, &dp))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = DOUBLE_TO_JSVAL(dp);
|
||||
break;
|
||||
}
|
||||
case JSVAL_OBJECT: {
|
||||
JSObject *obj;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
obj = JSVAL_TO_OBJECT(*vp);
|
||||
if (!js_XDRObject(xdr, &obj))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
break;
|
||||
}
|
||||
case JSVAL_BOOLEAN: {
|
||||
uint32 bool;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
bool = (uint32)JSVAL_TO_BOOLEAN(*vp);
|
||||
if (!JS_XDRUint32(xdr, &bool))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = BOOLEAN_TO_JSVAL((JSBool)bool);
|
||||
break;
|
||||
}
|
||||
case JSVAL_VOID:
|
||||
if (!JS_XDRUint32(xdr, (uint32 *)vp))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
default:
|
||||
JS_ReportError(xdr->cx, "unknown jsval type %#lx for XDR", type);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JS_XDRDestroy(JSXDRState *xdr)
|
||||
{
|
||||
JSContext *cx = xdr->cx;
|
||||
xdr->ops->finalize(xdr);
|
||||
if (xdr->registry)
|
||||
JS_free(cx, xdr->registry);
|
||||
JS_free(cx, xdr);
|
||||
}
|
||||
|
||||
#define REGISTRY_CHUNK 4
|
||||
|
||||
JSBool
|
||||
JS_RegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp)
|
||||
{
|
||||
uintN nclasses;
|
||||
JSClass **registry;
|
||||
|
||||
nclasses = xdr->nclasses;
|
||||
if (nclasses == 0) {
|
||||
registry = JS_malloc(xdr->cx, REGISTRY_CHUNK * sizeof(JSClass *));
|
||||
} else if (nclasses % REGISTRY_CHUNK == 0) {
|
||||
registry = JS_realloc(xdr->cx,
|
||||
xdr->registry,
|
||||
(nclasses + REGISTRY_CHUNK) * sizeof(JSClass *));
|
||||
}
|
||||
if (!registry)
|
||||
return JS_FALSE;
|
||||
registry[nclasses++] = clasp;
|
||||
xdr->registry = registry;
|
||||
xdr->nclasses = nclasses;
|
||||
*idp = nclasses;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
uint32
|
||||
JS_FindClassIdByName(JSXDRState *xdr, const char *name)
|
||||
{
|
||||
uintN i;
|
||||
|
||||
for (i = 0; i < xdr->nclasses; i++) {
|
||||
if (!strcmp(name, xdr->registry[i]->name))
|
||||
return i+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSClass *
|
||||
JS_FindClassById(JSXDRState *xdr, uint32 id)
|
||||
{
|
||||
if (id > xdr->nclasses)
|
||||
return NULL;
|
||||
return xdr->registry[id-1];
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: C; tab-width: 8; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef jsxdrapi_h___
|
||||
#define jsxdrapi_h___
|
||||
|
||||
/*
|
||||
* JS external data representation interface API.
|
||||
*
|
||||
* The XDR system is comprised of three major parts:
|
||||
*
|
||||
* - the state serialization/deserialization APIs, which allow consumers
|
||||
* of the API to serialize JS runtime state (script bytecodes, atom maps,
|
||||
* object graphs, etc.) for later restoration. These portions
|
||||
* are implemented in various appropriate files, such as jsscript.c
|
||||
* for the script portions and jsobj.c for object state.
|
||||
* - the callback APIs through which the runtime requests an opaque
|
||||
* representation of a native object, and through which the runtime
|
||||
* constructs a live native object from an opaque representation. These
|
||||
* portions are the responsibility of the native object implementor.
|
||||
* - utility functions for en/decoding of primitive types, such as
|
||||
* JSStrings. This portion is implemented in jsxdrapi.c.
|
||||
*
|
||||
* Spiritually guided by Sun's XDR, where appropriate.
|
||||
*/
|
||||
|
||||
#include "jspubtd.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
/* We use little-endian byteorder for all encoded data */
|
||||
|
||||
#if defined IS_LITTLE_ENDIAN
|
||||
#define JSXDR_SWAB32(x) x
|
||||
#define JSXDR_SWAB16(x) x
|
||||
#elif defined IS_BIG_ENDIAN
|
||||
#define JSXDR_SWAB32(x) (((x) >> 24) | \
|
||||
(((x) >> 8) & 0xff00) | \
|
||||
(((x) << 8) & 0xff0000) | \
|
||||
((x) << 24))
|
||||
#define JSXDR_SWAB16(x) (((x) >> 8) | ((x) << 8))
|
||||
#else
|
||||
#error "unknown byte order"
|
||||
#endif
|
||||
|
||||
#define JSXDR_ALIGN 4
|
||||
|
||||
typedef enum JSXDRMode {
|
||||
JSXDR_ENCODE,
|
||||
JSXDR_DECODE,
|
||||
JSXDR_FREE
|
||||
} JSXDRMode;
|
||||
|
||||
typedef enum JSXDRWhence {
|
||||
JSXDR_SEEK_SET,
|
||||
JSXDR_SEEK_CUR,
|
||||
JSXDR_SEEK_END
|
||||
} JSXDRWhence;
|
||||
|
||||
typedef struct JSXDROps {
|
||||
JSBool (*get32)(JSXDRState *, uint32 *);
|
||||
JSBool (*set32)(JSXDRState *, uint32 *);
|
||||
JSBool (*getbytes)(JSXDRState *, char **, uint32);
|
||||
JSBool (*setbytes)(JSXDRState *, char **, uint32);
|
||||
void * (*raw)(JSXDRState *, uint32);
|
||||
JSBool (*seek)(JSXDRState *, int32, JSXDRWhence);
|
||||
uint32 (*tell)(JSXDRState *);
|
||||
void (*finalize)(JSXDRState *);
|
||||
} JSXDROps;
|
||||
|
||||
struct JSXDRState {
|
||||
JSXDRMode mode;
|
||||
JSXDROps *ops;
|
||||
JSContext *cx;
|
||||
JSClass **registry;
|
||||
uintN nclasses;
|
||||
void *data;
|
||||
};
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_XDRNewBase(JSContext *cx, JSXDRState *xdr, JSXDRMode mode);
|
||||
|
||||
JS_PUBLIC_API(JSXDRState *)
|
||||
JS_XDRNewMem(JSContext *cx, JSXDRMode mode);
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp);
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len);
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_XDRDestroy(JSXDRState *xdr);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRUint8(JSXDRState *xdr, uint8 *b);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRUint16(JSXDRState *xdr, uint16 *s);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRUint32(JSXDRState *xdr, uint32 *lp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRBytes(JSXDRState *xdr, char **bytes, uint32 len);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRCString(JSXDRState *xdr, char **sp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRCStringOrNull(JSXDRState *xdr, char **sp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRString(JSXDRState *xdr, JSString **strp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRDouble(JSXDRState *xdr, jsdouble **dp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_XDRValue(JSXDRState *xdr, jsval *vp);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_RegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *lp);
|
||||
|
||||
JS_PUBLIC_API(uint32)
|
||||
JS_FindClassIdByName(JSXDRState *xdr, const char *name);
|
||||
|
||||
JS_PUBLIC_API(JSClass *)
|
||||
JS_FindClassById(JSXDRState *xdr, uint32 id);
|
||||
|
||||
/* Magic values */
|
||||
|
||||
#define OBJ_XDRMAGIC 0xdead1000
|
||||
#define OBJ_XDRTYPE_OBJ 0xdead1001
|
||||
#define OBJ_XDRTYPE_FUN 0xdead1002
|
||||
#define OBJ_XDRTYPE_REGEXP 0xdead1003
|
||||
#define SCRIPT_XDRMAGIC 0xdead0001
|
||||
|
||||
#endif /* ! jsxdrapi_h___ */
|
|
@ -0,0 +1,79 @@
|
|||
!
|
||||
! atomic compare-and-swap routines for V8 sparc
|
||||
! and for V8+ (ultrasparc)
|
||||
!
|
||||
!
|
||||
! standard asm linkage macros; this module must be compiled
|
||||
! with the -P option (use C preprocessor)
|
||||
|
||||
#include <sys/asm_linkage.h>
|
||||
|
||||
! ======================================================================
|
||||
!
|
||||
! Perform the sequence *a = b atomically with respect to previous value
|
||||
! of a (a0). If *a==a0 then assign *a to b, all in one atomic operation.
|
||||
! Returns 1 if assignment happened, and 0 otherwise.
|
||||
!
|
||||
! usage : old_val = compare_and_swap(address, oldval, newval)
|
||||
!
|
||||
! -----------------------
|
||||
! Note on REGISTER USAGE:
|
||||
! as this is a LEAF procedure, a new stack frame is not created;
|
||||
! we use the caller stack frame so what would normally be %i (input)
|
||||
! registers are actually %o (output registers). Also, we must not
|
||||
! overwrite the contents of %l (local) registers as they are not
|
||||
! assumed to be volatile during calls.
|
||||
!
|
||||
! So, the registers used are:
|
||||
! %o0 [input] - the address of the value to increment
|
||||
! %o1 [input] - the old value to compare with
|
||||
! %o2 [input] - the new value to set for [%o0]
|
||||
! %o3 [local] - work register
|
||||
! -----------------------
|
||||
#ifndef ULTRA_SPARC
|
||||
! v8
|
||||
|
||||
ENTRY(compare_and_swap) ! standard assembler/ELF prologue
|
||||
|
||||
mov -1,%o3 ! busy flag
|
||||
swap [%o0],%o3 ! get current value
|
||||
l1: tst %o3 ! busy?
|
||||
bneg,a l1 ! if so, spin
|
||||
swap [%o0],%o3 ! using branch-delay to swap back value
|
||||
cmp %o1,%o3 ! compare old with current
|
||||
be,a l2 ! if equal then swap in new value
|
||||
swap [%o0],%o2 ! done.
|
||||
swap [%o0],%o3 ! otherwise, swap back current value
|
||||
retl
|
||||
mov 0,%o0 ! return false
|
||||
l2: retl
|
||||
mov 1,%o0 ! return true
|
||||
|
||||
SET_SIZE(compare_and_swap) ! standard assembler/ELF epilogue
|
||||
|
||||
!
|
||||
! end
|
||||
!
|
||||
#else /* ULTRA_SPARC */
|
||||
! ======================================================================
|
||||
!
|
||||
! v9
|
||||
|
||||
ENTRY(compare_and_swap) ! standard assembler/ELF prologue
|
||||
|
||||
cas [%o0],%o1,%o2 ! compare *w with old value and set to new if equal
|
||||
cmp %o1,%o2 ! did we succeed?
|
||||
be,a m1 ! yes
|
||||
mov 1,%o0 ! return true (annulled when no jump)
|
||||
mov 0,%o0 ! return false
|
||||
m1: retl
|
||||
nop
|
||||
|
||||
SET_SIZE(compare_and_swap) ! standard assembler/ELF epilogue
|
||||
|
||||
!
|
||||
! end
|
||||
!
|
||||
! ======================================================================
|
||||
!
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
// Some simple testing of new, eval and some string stuff.
|
||||
|
||||
// constructor -- expression array initialization
|
||||
function ExprArray(n,v)
|
||||
{
|
||||
// Initializes n values to v coerced to a string.
|
||||
for (var i = 0; i < n; i++) {
|
||||
this[i] = "" + v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Print the perfect numbers up to n and the sum expression for n's divisors.
|
||||
function perfect(n)
|
||||
{
|
||||
print("The perfect numbers up to " + n + " are:");
|
||||
|
||||
// We build sumOfDivisors[i] to hold a string expression for
|
||||
// the sum of the divisors of i, excluding i itself.
|
||||
var sumOfDivisors = new ExprArray(n+1,1);
|
||||
for (var divisor = 2; divisor <= n; divisor++) {
|
||||
for (var j = divisor + divisor; j <= n; j += divisor) {
|
||||
sumOfDivisors[j] += " + " + divisor;
|
||||
}
|
||||
// At this point everything up to 'divisor' has its sumOfDivisors
|
||||
// expression calculated, so we can determine whether it's perfect
|
||||
// already by evaluating.
|
||||
if (eval(sumOfDivisors[divisor]) == divisor) {
|
||||
print("" + divisor + " = " + sumOfDivisors[divisor]);
|
||||
}
|
||||
}
|
||||
print("That's all.");
|
||||
}
|
||||
|
||||
|
||||
print("\nA number is 'perfect' if it is equal to the sum of its")
|
||||
print("divisors (excluding itself).\n");
|
||||
perfect(500);
|
||||
|
|
@ -0,0 +1,319 @@
|
|||
/* -*- Mode: C; tab-width: 8 -*-
|
||||
* Copyright © 1996, 1997, 1998 Netscape Communications Corporation,
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Lifetime-based fast allocation, inspired by much prior art, including
|
||||
* "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
|
||||
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prarena.h"
|
||||
#include "prlog.h"
|
||||
#ifdef JS_THREADSAFE
|
||||
extern js_CompareAndSwap(prword *, prword, prword);
|
||||
#endif
|
||||
|
||||
static PRArena *arena_freelist;
|
||||
|
||||
#ifdef PR_ARENAMETER
|
||||
static PRArenaStats *arena_stats_list;
|
||||
|
||||
#define COUNT(pool,what) (pool)->stats.what++
|
||||
#else
|
||||
#define COUNT(pool,what) /* nothing */
|
||||
#endif
|
||||
|
||||
#define PR_ARENA_DEFAULT_ALIGN sizeof(double)
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size, size_t align)
|
||||
{
|
||||
if (align == 0)
|
||||
align = PR_ARENA_DEFAULT_ALIGN;
|
||||
pool->mask = PR_BITMASK(PR_CeilingLog2(align));
|
||||
pool->first.next = NULL;
|
||||
pool->first.base = pool->first.avail = pool->first.limit =
|
||||
(pruword)PR_ARENA_ALIGN(pool, &pool->first + 1);
|
||||
pool->current = &pool->first;
|
||||
pool->arenasize = size;
|
||||
#ifdef PR_ARENAMETER
|
||||
memset(&pool->stats, 0, sizeof pool->stats);
|
||||
pool->stats.name = strdup(name);
|
||||
pool->stats.next = arena_stats_list;
|
||||
arena_stats_list = &pool->stats;
|
||||
#endif
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void *)
|
||||
PR_ArenaAllocate(PRArenaPool *pool, size_t nb)
|
||||
{
|
||||
PRArena **ap, *a, *b;
|
||||
#ifdef JS_THREADSAFE
|
||||
PRArena *c;
|
||||
#endif
|
||||
size_t sz;
|
||||
void *p;
|
||||
|
||||
PR_ASSERT((nb & pool->mask) == 0);
|
||||
#if defined(XP_PC) && !defined(_WIN32)
|
||||
if (nb >= 60000U)
|
||||
return 0;
|
||||
#endif /* WIN16 */
|
||||
ap = &arena_freelist;
|
||||
for (a = pool->current; a->avail + nb > a->limit; pool->current = a) {
|
||||
if (a->next) { /* move to next arena */
|
||||
a = a->next;
|
||||
continue;
|
||||
}
|
||||
while ((b = *ap) != NULL) { /* reclaim a free arena */
|
||||
if (b->limit - b->base == pool->arenasize) {
|
||||
#ifdef JS_THREADSAFE
|
||||
do {
|
||||
c = b->next;
|
||||
} while (!js_CompareAndSwap((prword *)ap,(prword)b,(prword)c));
|
||||
#else
|
||||
*ap = b->next;
|
||||
#endif
|
||||
b->next = NULL;
|
||||
a = a->next = b;
|
||||
COUNT(pool, nreclaims);
|
||||
goto claim;
|
||||
}
|
||||
ap = &b->next;
|
||||
}
|
||||
sz = PR_MAX(pool->arenasize, nb); /* allocate a new arena */
|
||||
sz += sizeof *a + pool->mask; /* header and alignment slop */
|
||||
b = malloc(sz);
|
||||
if (!b)
|
||||
return 0;
|
||||
a = a->next = b;
|
||||
a->next = NULL;
|
||||
a->limit = (pruword)a + sz;
|
||||
PR_COUNT_ARENA(pool,++);
|
||||
COUNT(pool, nmallocs);
|
||||
claim:
|
||||
a->base = a->avail = (pruword)PR_ARENA_ALIGN(pool, a + 1);
|
||||
}
|
||||
p = (void *)a->avail;
|
||||
a->avail += nb;
|
||||
return p;
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void *)
|
||||
PR_ArenaGrow(PRArenaPool *pool, void *p, size_t size, size_t incr)
|
||||
{
|
||||
void *newp;
|
||||
|
||||
PR_ARENA_ALLOCATE(newp, pool, size + incr);
|
||||
memcpy(newp, p, size);
|
||||
return newp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free tail arenas linked after head, which may not be the true list head.
|
||||
* Reset pool->current to point to head in case it pointed at a tail arena.
|
||||
*/
|
||||
static void
|
||||
FreeArenaList(PRArenaPool *pool, PRArena *head, PRBool reallyFree)
|
||||
{
|
||||
PRArena **ap, *a;
|
||||
#ifdef JS_THREADSAFE
|
||||
PRArena *b;
|
||||
#endif
|
||||
|
||||
ap = &head->next;
|
||||
a = *ap;
|
||||
if (!a)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
do {
|
||||
PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
|
||||
a->avail = a->base;
|
||||
PR_CLEAR_UNUSED(a);
|
||||
} while ((a = a->next) != NULL);
|
||||
a = *ap;
|
||||
#endif
|
||||
|
||||
if (reallyFree) {
|
||||
do {
|
||||
*ap = a->next;
|
||||
PR_CLEAR_ARENA(a);
|
||||
PR_COUNT_ARENA(pool,--);
|
||||
free(a);
|
||||
} while ((a = *ap) != NULL);
|
||||
} else {
|
||||
/* Insert the whole arena chain at the front of the freelist. */
|
||||
do {
|
||||
ap = &(*ap)->next;
|
||||
} while (*ap);
|
||||
#ifdef JS_THREADSAFE
|
||||
do {
|
||||
*ap = b = arena_freelist;
|
||||
} while (!js_CompareAndSwap((prword*)&arena_freelist,(prword)b,(prword)a));
|
||||
#else
|
||||
*ap = arena_freelist;
|
||||
arena_freelist = a;
|
||||
#endif
|
||||
head->next = NULL;
|
||||
}
|
||||
|
||||
pool->current = head;
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaRelease(PRArenaPool *pool, char *mark)
|
||||
{
|
||||
PRArena *a;
|
||||
|
||||
for (a = pool->first.next; a; a = a->next) {
|
||||
if (PR_UPTRDIFF(mark, a) < PR_UPTRDIFF(a->avail, a)) {
|
||||
a->avail = (pruword)PR_ARENA_ALIGN(pool, mark);
|
||||
FreeArenaList(pool, a, PR_TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_FreeArenaPool(PRArenaPool *pool)
|
||||
{
|
||||
FreeArenaList(pool, &pool->first, PR_FALSE);
|
||||
COUNT(pool, ndeallocs);
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_FinishArenaPool(PRArenaPool *pool)
|
||||
{
|
||||
FreeArenaList(pool, &pool->first, PR_TRUE);
|
||||
#ifdef PR_ARENAMETER
|
||||
{
|
||||
PRArenaStats *stats, **statsp;
|
||||
|
||||
if (pool->stats.name)
|
||||
free(pool->stats.name);
|
||||
for (statsp = &arena_stats_list; (stats = *statsp) != 0;
|
||||
statsp = &stats->next) {
|
||||
if (stats == &pool->stats) {
|
||||
*statsp = stats->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_CompactArenaPool(PRArenaPool *pool)
|
||||
{
|
||||
#if 0 /* XP_MAC */
|
||||
PRArena *a = pool->first.next;
|
||||
|
||||
while (a) {
|
||||
reallocSmaller(a, a->avail - (pruword)a);
|
||||
a->limit = a->avail;
|
||||
a = a->next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaFinish()
|
||||
{
|
||||
PRArena *a, *next;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
while (arena_freelist) {
|
||||
a = arena_freelist;
|
||||
next = a->next;
|
||||
if (js_CompareAndSwap((prword*)&arena_freelist,(prword)a,(prword)next))
|
||||
free(a);
|
||||
}
|
||||
#else
|
||||
for (a = arena_freelist; a; a = next) {
|
||||
next = a->next;
|
||||
free(a);
|
||||
}
|
||||
arena_freelist = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PR_ARENAMETER
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb)
|
||||
{
|
||||
pool->stats.nallocs++;
|
||||
pool->stats.nbytes += nb;
|
||||
if (nb > pool->stats.maxalloc)
|
||||
pool->stats.maxalloc = nb;
|
||||
pool->stats.variance += nb * nb;
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountInplaceGrowth(PRArenaPool *pool, size_t size, size_t incr)
|
||||
{
|
||||
pool->stats.ninplace++;
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountGrowth(PRArenaPool *pool, size_t size, size_t incr)
|
||||
{
|
||||
pool->stats.ngrows++;
|
||||
pool->stats.nbytes += incr;
|
||||
pool->stats.variance -= size * size;
|
||||
size += incr;
|
||||
if (size > pool->stats.maxalloc)
|
||||
pool->stats.maxalloc = size;
|
||||
pool->stats.variance += size * size;
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountRelease(PRArenaPool *pool, char *mark)
|
||||
{
|
||||
pool->stats.nreleases++;
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountRetract(PRArenaPool *pool, char *mark)
|
||||
{
|
||||
pool->stats.nfastrels++;
|
||||
}
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_DumpArenaStats(FILE *fp)
|
||||
{
|
||||
PRArenaStats *stats;
|
||||
double mean, variance;
|
||||
|
||||
for (stats = arena_stats_list; stats; stats = stats->next) {
|
||||
if (stats->nallocs != 0) {
|
||||
mean = (double)stats->nbytes / stats->nallocs;
|
||||
variance = fabs(stats->variance / stats->nallocs - mean * mean);
|
||||
} else {
|
||||
mean = variance = 0;
|
||||
}
|
||||
|
||||
fprintf(fp, "\n%s allocation statistics:\n", stats->name);
|
||||
fprintf(fp, " number of arenas: %u\n", stats->narenas);
|
||||
fprintf(fp, " number of allocations: %u\n", stats->nallocs);
|
||||
fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims);
|
||||
fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs);
|
||||
fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs);
|
||||
fprintf(fp, " number of allocation growths: %u\n", stats->ngrows);
|
||||
fprintf(fp, " number of in-place growths: %u\n", stats->ninplace);
|
||||
fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
|
||||
fprintf(fp, " number of fast releases: %u\n", stats->nfastrels);
|
||||
fprintf(fp, " total bytes allocated: %u\n", stats->nbytes);
|
||||
fprintf(fp, " mean allocation size: %g\n", mean);
|
||||
fprintf(fp, " standard deviation: %g\n", sqrt(variance));
|
||||
fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc);
|
||||
}
|
||||
}
|
||||
#endif /* PR_ARENAMETER */
|
|
@ -0,0 +1,248 @@
|
|||
/* -*- Mode: C; tab-width: 8 -*-
|
||||
* Copyright © 1996, 1997, 1998 Netscape Communications Corporation,
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef prarena_h___
|
||||
#define prarena_h___
|
||||
/*
|
||||
* Lifetime-based fast allocation, inspired by much prior art, including
|
||||
* "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
|
||||
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
|
||||
*
|
||||
* Also supports LIFO allocation (PR_ARENA_MARK/PR_ARENA_RELEASE).
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "jscompat.h"
|
||||
|
||||
#undef PR_ARENA_ALIGN
|
||||
#undef PR_ARENA_ALLOCATE
|
||||
#undef PR_ARENA_GROW
|
||||
#undef PR_ARENA_MARK
|
||||
#undef PR_CLEAR_UNUSED
|
||||
#undef PR_CLEAR_ARENA
|
||||
#undef PR_ARENA_RELEASE
|
||||
#undef PR_COUNT_ARENA
|
||||
#undef PR_ARENA_DESTROY
|
||||
#undef PR_ArenaCountAllocation
|
||||
#undef PR_ArenaCountInplaceGrowth
|
||||
#undef PR_ArenaCountGrowth
|
||||
#undef PR_ArenaCountRelease
|
||||
#undef PR_ArenaCountRetract
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
#undef PRArena
|
||||
typedef struct PRArena PRArena;
|
||||
struct PRArena {
|
||||
PRArena *next; /* next arena for this lifetime */
|
||||
pruword base; /* aligned base address, follows this header */
|
||||
pruword limit; /* one beyond last byte in arena */
|
||||
pruword avail; /* points to next available byte */
|
||||
};
|
||||
|
||||
#ifdef PR_ARENAMETER
|
||||
typedef struct PRArenaStats PRArenaStats;
|
||||
|
||||
struct PRArenaStats {
|
||||
PRArenaStats *next; /* next in arenaStats list */
|
||||
char *name; /* name for debugging */
|
||||
uint32 narenas; /* number of arenas in pool */
|
||||
uint32 nallocs; /* number of PR_ARENA_ALLOCATE() calls */
|
||||
uint32 nreclaims; /* number of reclaims from freeArenas */
|
||||
uint32 nmallocs; /* number of malloc() calls */
|
||||
uint32 ndeallocs; /* number of lifetime deallocations */
|
||||
uint32 ngrows; /* number of PR_ARENA_GROW() calls */
|
||||
uint32 ninplace; /* number of in-place growths */
|
||||
uint32 nreleases; /* number of PR_ARENA_RELEASE() calls */
|
||||
uint32 nfastrels; /* number of "fast path" releases */
|
||||
size_t nbytes; /* total bytes allocated */
|
||||
size_t maxalloc; /* maximum allocation size in bytes */
|
||||
double variance; /* size variance accumulator */
|
||||
};
|
||||
#endif
|
||||
|
||||
#undef PRArenaPool
|
||||
typedef struct PRArenaPool {
|
||||
PRArena first; /* first arena in pool list */
|
||||
PRArena *current; /* arena from which to allocate space */
|
||||
size_t arenasize; /* net exact size of a new arena */
|
||||
pruword mask; /* alignment mask (power-of-2 - 1) */
|
||||
#ifdef PR_ARENAMETER
|
||||
PRArenaStats stats;
|
||||
#endif
|
||||
} PRArenaPool;
|
||||
|
||||
/*
|
||||
* If the including .c file uses only one power-of-2 alignment, it may define
|
||||
* PR_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions
|
||||
* per ALLOCATE and GROW.
|
||||
*/
|
||||
#ifdef PR_ARENA_CONST_ALIGN_MASK
|
||||
#define PR_ARENA_ALIGN(pool, n) (((pruword)(n) + PR_ARENA_CONST_ALIGN_MASK) \
|
||||
& ~PR_ARENA_CONST_ALIGN_MASK)
|
||||
|
||||
#define PR_INIT_ARENA_POOL(pool, name, size) \
|
||||
PR_InitArenaPool(pool, name, size, PR_ARENA_CONST_ALIGN_MASK + 1)
|
||||
#else
|
||||
#define PR_ARENA_ALIGN(pool, n) (((pruword)(n) + (pool)->mask) & ~(pool)->mask)
|
||||
#endif
|
||||
|
||||
#define PR_ARENA_ALLOCATE(p, pool, nb) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRArena *_a = (pool)->current; \
|
||||
size_t _nb = PR_ARENA_ALIGN(pool, nb); \
|
||||
pruword _p = _a->avail; \
|
||||
pruword _q = _p + _nb; \
|
||||
if (_q > _a->limit) \
|
||||
_p = (pruword)PR_ArenaAllocate(pool, _nb); \
|
||||
else \
|
||||
_a->avail = _q; \
|
||||
p = (void *)_p; \
|
||||
PR_ArenaCountAllocation(pool, nb); \
|
||||
PR_END_MACRO
|
||||
|
||||
#define PR_ARENA_GROW(p, pool, size, incr) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRArena *_a = (pool)->current; \
|
||||
size_t _incr = PR_ARENA_ALIGN(pool, incr); \
|
||||
pruword _p = _a->avail; \
|
||||
pruword _q = _p + _incr; \
|
||||
if (_p == (pruword)(p) + PR_ARENA_ALIGN(pool, size) && \
|
||||
_q <= _a->limit) { \
|
||||
_a->avail = _q; \
|
||||
PR_ArenaCountInplaceGrowth(pool, size, incr); \
|
||||
} else { \
|
||||
p = PR_ArenaGrow(pool, p, size, incr); \
|
||||
} \
|
||||
PR_ArenaCountGrowth(pool, size, incr); \
|
||||
PR_END_MACRO
|
||||
|
||||
#define PR_ARENA_MARK(pool) ((void *) (pool)->current->avail)
|
||||
#define PR_UPTRDIFF(p,q) ((pruword)(p) - (pruword)(q))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PR_FREE_PATTERN 0xDA
|
||||
#define PR_CLEAR_UNUSED(a) (PR_ASSERT((a)->avail <= (a)->limit), \
|
||||
memset((void*)(a)->avail, PR_FREE_PATTERN, \
|
||||
(a)->limit - (a)->avail))
|
||||
#define PR_CLEAR_ARENA(a) memset((void*)(a), PR_FREE_PATTERN, \
|
||||
(a)->limit - (pruword)(a))
|
||||
#else
|
||||
#define PR_CLEAR_UNUSED(a) /* nothing */
|
||||
#define PR_CLEAR_ARENA(a) /* nothing */
|
||||
#endif
|
||||
|
||||
#define PR_ARENA_RELEASE(pool, mark) \
|
||||
PR_BEGIN_MACRO \
|
||||
char *_m = (char *)(mark); \
|
||||
PRArena *_a = (pool)->current; \
|
||||
if (PR_UPTRDIFF(_m, _a) <= PR_UPTRDIFF(_a->avail, _a)) { \
|
||||
_a->avail = (pruword)PR_ARENA_ALIGN(pool, _m); \
|
||||
PR_CLEAR_UNUSED(_a); \
|
||||
PR_ArenaCountRetract(pool, _m); \
|
||||
} else { \
|
||||
PR_ArenaRelease(pool, _m); \
|
||||
} \
|
||||
PR_ArenaCountRelease(pool, _m); \
|
||||
PR_END_MACRO
|
||||
|
||||
#ifdef PR_ARENAMETER
|
||||
#define PR_COUNT_ARENA(pool,op) ((pool)->stats.narenas op)
|
||||
#else
|
||||
#define PR_COUNT_ARENA(pool,op)
|
||||
#endif
|
||||
|
||||
#define PR_ARENA_DESTROY(pool, a, pnext) \
|
||||
PR_BEGIN_MACRO \
|
||||
PR_COUNT_ARENA(pool,--); \
|
||||
if ((pool)->current == (a)) (pool)->current = &(pool)->first; \
|
||||
*(pnext) = (a)->next; \
|
||||
PR_CLEAR_ARENA(a); \
|
||||
free(a); \
|
||||
(a) = NULL; \
|
||||
PR_END_MACRO
|
||||
|
||||
/*
|
||||
* Initialize an arena pool with the given name for debugging and metering,
|
||||
* with a minimum size per arena of size bytes.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size,
|
||||
size_t align);
|
||||
|
||||
/*
|
||||
* Free the arenas in pool. The user may continue to allocate from pool
|
||||
* after calling this function. There is no need to call PR_InitArenaPool()
|
||||
* again unless PR_FinishArenaPool(pool) has been called.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_FreeArenaPool(PRArenaPool *pool);
|
||||
|
||||
/*
|
||||
* Free the arenas in pool and finish using it altogether.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_FinishArenaPool(PRArenaPool *pool);
|
||||
|
||||
/*
|
||||
* Compact all of the arenas in a pool so that no space is wasted.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_CompactArenaPool(PRArenaPool *pool);
|
||||
|
||||
/*
|
||||
* Finish using arenas, freeing all memory associated with them.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaFinish(void);
|
||||
|
||||
/*
|
||||
* Friend functions used by the PR_ARENA_*() macros.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void *)
|
||||
PR_ArenaAllocate(PRArenaPool *pool, size_t nb);
|
||||
|
||||
extern PR_PUBLIC_API(void *)
|
||||
PR_ArenaGrow(PRArenaPool *pool, void *p, size_t size, size_t incr);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaRelease(PRArenaPool *pool, char *mark);
|
||||
|
||||
#ifdef PR_ARENAMETER
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountInplaceGrowth(PRArenaPool *pool, size_t size, size_t incr);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountGrowth(PRArenaPool *pool, size_t size, size_t incr);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountRelease(PRArenaPool *pool, char *mark);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountRetract(PRArenaPool *pool, char *mark);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_DumpArenaStats(FILE *fp);
|
||||
|
||||
#else /* !PR_ARENAMETER */
|
||||
|
||||
#define PR_ArenaCountAllocation(ap, nb) /* nothing */
|
||||
#define PR_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */
|
||||
#define PR_ArenaCountGrowth(ap, size, incr) /* nothing */
|
||||
#define PR_ArenaCountRelease(ap, mark) /* nothing */
|
||||
#define PR_ArenaCountRetract(ap, mark) /* nothing */
|
||||
|
||||
#endif /* !PR_ARENAMETER */
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif /* prarena_h___ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C; tab-width: 8 -*-
|
||||
* Copyright © 1996, 1997, 1998 Netscape Communications Corporation,
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef prdtoa_h___
|
||||
#define prdtoa_h___
|
||||
/*
|
||||
* Public interface to portable double-precision floating point to string
|
||||
* and back conversion package.
|
||||
*/
|
||||
|
||||
#include "jscompat.h"
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* PR_strtod() returns as a double-precision floating-point number
|
||||
* the value represented by the character string pointed to by
|
||||
* s00. The string is scanned up to the first unrecognized
|
||||
* character.
|
||||
* If the value of se is not (char **)NULL, a pointer to
|
||||
* the character terminating the scan is returned in the location pointed
|
||||
* to by se. If no number can be formed, se is set to s00r, and
|
||||
* zero is returned.
|
||||
*/
|
||||
extern PR_PUBLIC_API(double)
|
||||
PR_strtod(const char *s00, char **se);
|
||||
|
||||
/*
|
||||
* PR_cnvtf()
|
||||
* conversion routines for floating point
|
||||
* prcsn - number of digits of precision to generate floating
|
||||
* point value.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_cnvtf(char *buf, intN bufsz, intN prcsn, double dval);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif /* prdtoa_h___ */
|
Загрузка…
Ссылка в новой задаче