This commit is contained in:
fur 1998-04-24 01:28:40 +00:00
Родитель a2bf16e4c8
Коммит e75cafd1e9
8 изменённых файлов: 4007 добавлений и 0 удалений

531
js/src/jsxdrapi.c Normal file
Просмотреть файл

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

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

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

79
js/src/lock_SunOS.s Normal file
Просмотреть файл

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

39
js/src/perfect.js Normal file
Просмотреть файл

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

319
js/src/prarena.c Normal file
Просмотреть файл

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

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

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

2592
js/src/prdtoa.c Normal file

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

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

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