jsinterp.c
来自「一个基于alice开发的机器人」· C语言 代码 · 共 1,783 行 · 第 1/5 页
C
1,783 行
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* build on macs with low memory */
#if defined(XP_MAC) && defined(MOZ_MAC_LOWMEM)
#pragma optimization_level 1
#endif
/*
* JavaScript bytecode interpreter.
*/
#include "jsstddef.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "jstypes.h"
#include "jsarena.h" /* Added by JSIFY */
#include "jsutil.h" /* Added by JSIFY */
#include "jsprf.h"
#include "jsapi.h"
#include "jsarray.h"
#include "jsatom.h"
#include "jsbool.h"
#include "jscntxt.h"
#include "jsconfig.h"
#include "jsdbgapi.h"
#include "jsfun.h"
#include "jsgc.h"
#include "jsinterp.h"
#include "jslock.h"
#include "jsnum.h"
#include "jsobj.h"
#include "jsopcode.h"
#include "jsscope.h"
#include "jsscript.h"
#include "jsstr.h"
#if JS_HAS_JIT
#include "jsjit.h"
#endif
#ifdef DEBUG
#define ASSERT_CACHE_IS_EMPTY(cache) \
JS_BEGIN_MACRO \
JSPropertyCacheEntry *end_, *pce_, entry_; \
JSPropertyCache *cache_ = (cache); \
JS_ASSERT(cache_->empty); \
end_ = &cache_->table[PROPERTY_CACHE_SIZE]; \
for (pce_ = &cache_->table[0]; pce_ < end_; pce_++) { \
PCE_LOAD(cache_, pce_, entry_); \
JS_ASSERT(!PCE_OBJECT(entry_)); \
JS_ASSERT(!PCE_PROPERTY(entry_)); \
} \
JS_END_MACRO
#else
#define ASSERT_CACHE_IS_EMPTY(cache) ((void)0)
#endif
void
js_FlushPropertyCache(JSContext *cx)
{
JSPropertyCache *cache;
cache = &cx->runtime->propertyCache;
if (cache->empty) {
ASSERT_CACHE_IS_EMPTY(cache);
return;
}
memset(cache->table, 0, sizeof cache->table);
cache->empty = JS_TRUE;
#ifdef JS_PROPERTY_CACHE_METERING
cache->flushes++;
#endif
}
void
js_DisablePropertyCache(JSContext *cx)
{
JS_ASSERT(!cx->runtime->propertyCache.disabled);
cx->runtime->propertyCache.disabled = JS_TRUE;
}
void
js_EnablePropertyCache(JSContext *cx)
{
JS_ASSERT(cx->runtime->propertyCache.disabled);
ASSERT_CACHE_IS_EMPTY(&cx->runtime->propertyCache);
cx->runtime->propertyCache.disabled = JS_FALSE;
}
/*
* Class for for/in loop property iterator objects.
*/
#define JSSLOT_ITER_STATE JSSLOT_PRIVATE
static void
prop_iterator_finalize(JSContext *cx, JSObject *obj)
{
jsval iter_state;
jsval iteratee;
/* Protect against stillborn iterators. */
iter_state = obj->slots[JSSLOT_ITER_STATE];
iteratee = obj->slots[JSSLOT_PARENT];
if (!JSVAL_IS_NULL(iter_state) && !JSVAL_IS_PRIMITIVE(iteratee)) {
OBJ_ENUMERATE(cx, JSVAL_TO_OBJECT(iteratee), JSENUMERATE_DESTROY,
&iter_state, NULL);
}
js_RemoveRoot(cx->runtime, &obj->slots[JSSLOT_PARENT]);
/* XXX force the GC to restart so we can collect iteratee, if possible,
during the current collector activation */
cx->runtime->gcLevel++;
}
static JSClass prop_iterator_class = {
"PropertyIterator",
0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iterator_finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
/*
* Stack macros and functions. These all use a local variable, jsval *sp, to
* point to the next free stack slot. SAVE_SP must be called before any call
* to a function that may invoke the interpreter. RESTORE_SP must be called
* only after return from js_Invoke, because only js_Invoke changes fp->sp.
*/
#define PUSH(v) (*sp++ = (v))
#define POP() (*--sp)
#ifdef DEBUG
#define SAVE_SP(fp) \
(JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase), \
(fp)->sp = sp)
#else
#define SAVE_SP(fp) ((fp)->sp = sp)
#endif
#define RESTORE_SP(fp) (sp = (fp)->sp)
/*
* Push the generating bytecode's pc onto the parallel pc stack that runs
* depth slots below the operands.
*
* NB: PUSH_OPND uses sp, depth, and pc from its lexical environment. See
* js_Interpret for these local variables' declarations and uses.
*/
#define PUSH_OPND(v) (sp[-depth] = (jsval)pc, PUSH(v))
#define STORE_OPND(n,v) (sp[(n)-depth] = (jsval)pc, sp[n] = (v))
#define POP_OPND() POP()
#define FETCH_OPND(n) (sp[n])
/*
* Push the jsdouble d using sp, depth, and pc from the lexical environment.
* Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
* for it and push a reference.
*/
#define STORE_NUMBER(cx, n, d) \
JS_BEGIN_MACRO \
jsint i_; \
jsval v_; \
\
if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) { \
v_ = INT_TO_JSVAL(i_); \
} else { \
ok = js_NewDoubleValue(cx, d, &v_); \
if (!ok) \
goto out; \
} \
STORE_OPND(n, v_); \
JS_END_MACRO
#define FETCH_NUMBER(cx, n, d) \
JS_BEGIN_MACRO \
jsval v_; \
\
v_ = FETCH_OPND(n); \
VALUE_TO_NUMBER(cx, v_, d); \
JS_END_MACRO
#define FETCH_INT(cx, n, i) \
JS_BEGIN_MACRO \
jsval v_ = FETCH_OPND(n); \
if (JSVAL_IS_INT(v_)) { \
i = JSVAL_TO_INT(v_); \
} else { \
SAVE_SP(fp); \
ok = js_ValueToECMAInt32(cx, v_, &i); \
if (!ok) \
goto out; \
} \
JS_END_MACRO
#define FETCH_UINT(cx, n, ui) \
JS_BEGIN_MACRO \
jsval v_ = FETCH_OPND(n); \
jsint i_; \
if (JSVAL_IS_INT(v_) && (i_ = JSVAL_TO_INT(v_)) >= 0) { \
ui = (uint32) i_; \
} else { \
SAVE_SP(fp); \
ok = js_ValueToECMAUint32(cx, v_, &ui); \
if (!ok) \
goto out; \
} \
JS_END_MACRO
/*
* Optimized conversion macros that test for the desired type in v before
* homing sp and calling a conversion function.
*/
#define VALUE_TO_NUMBER(cx, v, d) \
JS_BEGIN_MACRO \
if (JSVAL_IS_INT(v)) { \
d = (jsdouble)JSVAL_TO_INT(v); \
} else if (JSVAL_IS_DOUBLE(v)) { \
d = *JSVAL_TO_DOUBLE(v); \
} else { \
SAVE_SP(fp); \
ok = js_ValueToNumber(cx, v, &d); \
if (!ok) \
goto out; \
} \
JS_END_MACRO
#define POP_BOOLEAN(cx, v, b) \
JS_BEGIN_MACRO \
v = FETCH_OPND(-1); \
if (v == JSVAL_NULL) { \
b = JS_FALSE; \
} else if (JSVAL_IS_BOOLEAN(v)) { \
b = JSVAL_TO_BOOLEAN(v); \
} else { \
SAVE_SP(fp); \
ok = js_ValueToBoolean(cx, v, &b); \
if (!ok) \
goto out; \
} \
sp--; \
JS_END_MACRO
#define VALUE_TO_OBJECT(cx, v, obj) \
JS_BEGIN_MACRO \
if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) { \
obj = JSVAL_TO_OBJECT(v); \
} else { \
SAVE_SP(fp); \
obj = js_ValueToNonNullObject(cx, v); \
if (!obj) { \
ok = JS_FALSE; \
goto out; \
} \
} \
JS_END_MACRO
#if JS_BUG_VOID_TOSTRING
#define CHECK_VOID_TOSTRING(cx, v) \
if (JSVAL_IS_VOID(v)) { \
JSString *str_; \
str_ = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); \
v = STRING_TO_JSVAL(str_); \
}
#else
#define CHECK_VOID_TOSTRING(cx, v) ((void)0)
#endif
#if JS_BUG_EAGER_TOSTRING
#define CHECK_EAGER_TOSTRING(hint) (hint = JSTYPE_STRING)
#else
#define CHECK_EAGER_TOSTRING(hint) ((void)0)
#endif
#define VALUE_TO_PRIMITIVE(cx, v, hint, vp) \
JS_BEGIN_MACRO \
if (JSVAL_IS_PRIMITIVE(v)) { \
CHECK_VOID_TOSTRING(cx, v); \
*vp = v; \
} else { \
SAVE_SP(fp); \
CHECK_EAGER_TOSTRING(hint); \
ok = OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, vp); \
if (!ok) \
goto out; \
} \
JS_END_MACRO
JS_FRIEND_API(jsval *)
js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
{
jsval *sp;
if (markp)
*markp = JS_ARENA_MARK(&cx->stackPool);
JS_ARENA_ALLOCATE_CAST(sp, jsval *, &cx->stackPool, nslots * sizeof(jsval));
if (!sp) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_STACK_OVERFLOW,
(cx->fp && cx->fp->fun)
? JS_GetFunctionName(cx->fp->fun)
: "script");
}
return sp;
}
JS_FRIEND_API(void)
js_FreeRawStack(JSContext *cx, void *mark)
{
JS_ARENA_RELEASE(&cx->stackPool, mark);
}
JS_FRIEND_API(jsval *)
js_AllocStack(JSContext *cx, uintN nslots, void **markp)
{
jsval *sp, *vp, *end;
JSArena *a;
JSStackHeader *sh;
JSStackFrame *fp;
/* Callers don't check for zero nslots: we do to avoid empty segments. */
if (nslots == 0) {
*markp = NULL;
return JS_ARENA_MARK(&cx->stackPool);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?