Backed out changeset 972c44aa9d1f (bug 452598).
This commit is contained in:
@@ -88,4 +88,3 @@ BUILTIN2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32,
|
|||||||
BUILTIN2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1)
|
BUILTIN2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1)
|
||||||
BUILTIN2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, 1)
|
BUILTIN2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, 1)
|
||||||
BUILTIN1(extern, OBJECT, js_Arguments, CONTEXT, 0, 0)
|
BUILTIN1(extern, OBJECT, js_Arguments, CONTEXT, 0, 0)
|
||||||
BUILTIN4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT, 0, 0)
|
|
||||||
|
|||||||
@@ -533,7 +533,7 @@ static struct {
|
|||||||
{
|
{
|
||||||
/* 0*/ JSOP_SWAP,
|
/* 0*/ JSOP_SWAP,
|
||||||
/* 1*/ JSOP_POP,
|
/* 1*/ JSOP_POP,
|
||||||
/* 2*/ JSOP_NULL,
|
/* 2*/ JSOP_NULLTHIS,
|
||||||
/* 3*/ JSOP_CALL, 0, 0,
|
/* 3*/ JSOP_CALL, 0, 0,
|
||||||
/* 6*/ JSOP_STOP,
|
/* 6*/ JSOP_STOP,
|
||||||
},
|
},
|
||||||
@@ -815,7 +815,7 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||||||
0, /* JSOP_LOOKUPSWITCH */
|
0, /* JSOP_LOOKUPSWITCH */
|
||||||
0, /* JSOP_STRICTEQ */
|
0, /* JSOP_STRICTEQ */
|
||||||
0, /* JSOP_STRICTNE */
|
0, /* JSOP_STRICTNE */
|
||||||
0, /* JSOP_SETCALL */
|
0, /* JSOP_NULLTHIS */
|
||||||
3, /* JSOP_ITER */
|
3, /* JSOP_ITER */
|
||||||
2, /* JSOP_NEXTITER */
|
2, /* JSOP_NEXTITER */
|
||||||
0, /* JSOP_ENDITER */
|
0, /* JSOP_ENDITER */
|
||||||
@@ -869,14 +869,14 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||||||
0, /* JSOP_DEFFUN */
|
0, /* JSOP_DEFFUN */
|
||||||
0, /* JSOP_DEFCONST */
|
0, /* JSOP_DEFCONST */
|
||||||
0, /* JSOP_DEFVAR */
|
0, /* JSOP_DEFVAR */
|
||||||
0, /* JSOP_LAMBDA */
|
0, /* JSOP_ANONFUNOBJ */
|
||||||
0, /* JSOP_CALLEE */
|
0, /* JSOP_NAMEDFUNOBJ */
|
||||||
0, /* JSOP_SETLOCALPOP */
|
0, /* JSOP_SETLOCALPOP */
|
||||||
0, /* JSOP_PICK */
|
0, /* JSOP_IFPRIMTOP */
|
||||||
|
0, /* JSOP_SETCALL */
|
||||||
0, /* JSOP_TRY */
|
0, /* JSOP_TRY */
|
||||||
0, /* JSOP_FINALLY */
|
0, /* JSOP_FINALLY */
|
||||||
0, /* JSOP_GETDSLOT */
|
0, /* JSOP_OBJTOP */
|
||||||
0, /* JSOP_CALLDSLOT */
|
|
||||||
0, /* JSOP_ARGSUB */
|
0, /* JSOP_ARGSUB */
|
||||||
0, /* JSOP_ARGCNT */
|
0, /* JSOP_ARGCNT */
|
||||||
0, /* JSOP_DEFLOCALFUN */
|
0, /* JSOP_DEFLOCALFUN */
|
||||||
@@ -926,8 +926,8 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||||||
0, /* JSOP_XMLCOMMENT */
|
0, /* JSOP_XMLCOMMENT */
|
||||||
0, /* JSOP_XMLPI */
|
0, /* JSOP_XMLPI */
|
||||||
0, /* JSOP_CALLPROP */
|
0, /* JSOP_CALLPROP */
|
||||||
|
0, /* JSOP_GETFUNNS */
|
||||||
0, /* JSOP_GETUPVAR */
|
0, /* JSOP_GETUPVAR */
|
||||||
0, /* JSOP_CALLUPVAR */
|
|
||||||
0, /* JSOP_DELDESC */
|
0, /* JSOP_DELDESC */
|
||||||
0, /* JSOP_UINT24 */
|
0, /* JSOP_UINT24 */
|
||||||
0, /* JSOP_INDEXBASE */
|
0, /* JSOP_INDEXBASE */
|
||||||
@@ -942,17 +942,25 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||||||
0, /* JSOP_TYPEOFEXPR */
|
0, /* JSOP_TYPEOFEXPR */
|
||||||
0, /* JSOP_ENTERBLOCK */
|
0, /* JSOP_ENTERBLOCK */
|
||||||
0, /* JSOP_LEAVEBLOCK */
|
0, /* JSOP_LEAVEBLOCK */
|
||||||
0, /* JSOP_IFPRIMTOP */
|
0, /* JSOP_PICK */
|
||||||
0, /* JSOP_PRIMTOP */
|
0, /* JSOP_PRIMTOP */
|
||||||
|
0, /* JSOP_UNUSED203 */
|
||||||
|
0, /* JSOP_UNUSED204 */
|
||||||
|
0, /* JSOP_UNUSED205 */
|
||||||
|
0, /* JSOP_UNUSED206 */
|
||||||
|
0, /* JSOP_UNUSED207 */
|
||||||
|
0, /* JSOP_UNUSED208 */
|
||||||
|
0, /* JSOP_UNUSED209 */
|
||||||
0, /* JSOP_GENERATOR */
|
0, /* JSOP_GENERATOR */
|
||||||
0, /* JSOP_YIELD */
|
0, /* JSOP_YIELD */
|
||||||
0, /* JSOP_ARRAYPUSH */
|
0, /* JSOP_ARRAYPUSH */
|
||||||
0, /* JSOP_GETFUNNS */
|
0, /* JSOP_CALLUPVAR */
|
||||||
0, /* JSOP_ENUMCONSTELEM */
|
0, /* JSOP_ENUMCONSTELEM */
|
||||||
0, /* JSOP_LEAVEBLOCKEXPR */
|
0, /* JSOP_LEAVEBLOCKEXPR */
|
||||||
0, /* JSOP_GETTHISPROP */
|
0, /* JSOP_GETTHISPROP */
|
||||||
0, /* JSOP_GETARGPROP */
|
0, /* JSOP_GETARGPROP */
|
||||||
0, /* JSOP_GETLOCALPROP */
|
0, /* JSOP_GETLOCALPROP */
|
||||||
|
0, /* JSOP_UNUSED219 */
|
||||||
0, /* JSOP_INDEXBASE1 */
|
0, /* JSOP_INDEXBASE1 */
|
||||||
0, /* JSOP_INDEXBASE2 */
|
0, /* JSOP_INDEXBASE2 */
|
||||||
0, /* JSOP_INDEXBASE3 */
|
0, /* JSOP_INDEXBASE3 */
|
||||||
@@ -965,10 +973,6 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||||||
0, /* JSOP_LENGTH */
|
0, /* JSOP_LENGTH */
|
||||||
0, /* JSOP_NEWARRAY */
|
0, /* JSOP_NEWARRAY */
|
||||||
0, /* JSOP_HOLE */
|
0, /* JSOP_HOLE */
|
||||||
0, /* JSOP_DEFFUN_FC */
|
|
||||||
0, /* JSOP_DEFLOCALFUN_FC */
|
|
||||||
0, /* JSOP_LAMBDA_FC */
|
|
||||||
0, /* JSOP_OBJTOP */
|
|
||||||
0, /* JSOP_LOOP */
|
0, /* JSOP_LOOP */
|
||||||
};
|
};
|
||||||
#define JSOP_IS_IMACOP(x) (0 \
|
#define JSOP_IS_IMACOP(x) (0 \
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end equality
|
.end
|
||||||
|
|
||||||
.igroup binary JSOP_BITOR-JSOP_MOD
|
.igroup binary JSOP_BITOR-JSOP_MOD
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end binary
|
.end
|
||||||
|
|
||||||
.igroup add JSOP_ADD
|
.igroup add JSOP_ADD
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end add
|
.end
|
||||||
|
|
||||||
.igroup unary JSOP_NEG-JSOP_POS
|
.igroup unary JSOP_NEG-JSOP_POS
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end unary
|
.end
|
||||||
|
|
||||||
.igroup call JSOP_CALL
|
.igroup call JSOP_CALL
|
||||||
|
|
||||||
@@ -344,10 +344,9 @@
|
|||||||
stop # strobj
|
stop # strobj
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end call
|
.end
|
||||||
|
|
||||||
.igroup apply JSOP_APPLY
|
.igroup apply JSOP_APPLY
|
||||||
|
|
||||||
.imacro apply0 # apply fun this arr
|
.imacro apply0 # apply fun this arr
|
||||||
pick 3 # fun this arr apply
|
pick 3 # fun this arr apply
|
||||||
pop # fun this arr
|
pop # fun this arr
|
||||||
@@ -567,7 +566,7 @@
|
|||||||
.imacro call0 # call fun
|
.imacro call0 # call fun
|
||||||
swap # fun call
|
swap # fun call
|
||||||
pop # fun
|
pop # fun
|
||||||
null # fun this
|
nullthis # fun this
|
||||||
call 0 #
|
call 0 #
|
||||||
stop #
|
stop #
|
||||||
.end #
|
.end #
|
||||||
@@ -628,7 +627,7 @@
|
|||||||
stop #
|
stop #
|
||||||
.end #
|
.end #
|
||||||
|
|
||||||
.end apply
|
.end
|
||||||
|
|
||||||
.igroup iter JSOP_ITER
|
.igroup iter JSOP_ITER
|
||||||
|
|
||||||
@@ -666,7 +665,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end iter
|
.end
|
||||||
|
|
||||||
.igroup nextiter JSOP_NEXTITER
|
.igroup nextiter JSOP_NEXTITER
|
||||||
|
|
||||||
@@ -692,7 +691,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end nextiter
|
.end
|
||||||
|
|
||||||
.igroup getelem JSOP_GETELEM
|
.igroup getelem JSOP_GETELEM
|
||||||
|
|
||||||
@@ -736,7 +735,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end getelem
|
.end
|
||||||
|
|
||||||
.igroup setelem JSOP_SETELEM
|
.igroup setelem JSOP_SETELEM
|
||||||
|
|
||||||
@@ -762,7 +761,7 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end setelem
|
.end
|
||||||
|
|
||||||
.igroup initelem JSOP_INITELEM
|
.igroup initelem JSOP_INITELEM
|
||||||
|
|
||||||
@@ -788,4 +787,4 @@
|
|||||||
stop
|
stop
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.end initelem
|
.end
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ MSG_DEF(JSMSG_UNTERMINATED_STRING, 138, 0, JSEXN_SYNTAXERR, "unterminated str
|
|||||||
MSG_DEF(JSMSG_TOO_MANY_PARENS, 139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
|
MSG_DEF(JSMSG_TOO_MANY_PARENS, 139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
|
||||||
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 140, 0, JSEXN_SYNTAXERR, "unterminated comment")
|
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 140, 0, JSEXN_SYNTAXERR, "unterminated comment")
|
||||||
MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
|
MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
|
||||||
MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 142, 0, JSEXN_TYPEERR, "bad cloned function scope chain")
|
MSG_DEF(JSMSG_UNUSED142, 142, 0, JSEXN_NONE, "unused142")
|
||||||
MSG_DEF(JSMSG_SHARPVAR_TOO_BIG, 143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number")
|
MSG_DEF(JSMSG_SHARPVAR_TOO_BIG, 143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number")
|
||||||
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character")
|
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character")
|
||||||
MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
|
MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
|
||||||
|
|||||||
124
js/src/jsapi.cpp
124
js/src/jsapi.cpp
@@ -4350,74 +4350,10 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
|||||||
{
|
{
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
|
if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
|
||||||
/*
|
/* Indicate we cannot clone this object. */
|
||||||
* We cannot clone this object, so fail (we used to return funobj, bad
|
return funobj;
|
||||||
* idea, but we changed incompatibly to teach any abusers a lesson!).
|
|
||||||
*/
|
|
||||||
jsval v = OBJECT_TO_JSVAL(funobj);
|
|
||||||
js_ReportIsNotFunction(cx, &v, 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
return js_CloneFunctionObject(cx, GET_FUNCTION_PRIVATE(cx, funobj), parent);
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
|
||||||
JSObject *clone = js_CloneFunctionObject(cx, fun, parent);
|
|
||||||
if (!clone)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A flat closure carries its own environment, so why clone it? In case
|
|
||||||
* someone wants to mutate its fixed slots or add ad-hoc properties. API
|
|
||||||
* compatibility suggests we not return funobj and let callers mutate the
|
|
||||||
* returned object at will.
|
|
||||||
*
|
|
||||||
* But it's worse than that: API compatibility according to the test for
|
|
||||||
* bug 300079 requires we get "upvars" from parent and its ancestors! So
|
|
||||||
* we do that (grudgingly!). The scope chain ancestors are searched as if
|
|
||||||
* they were activations, respecting the skip field in each upvar's cookie
|
|
||||||
* but looking up the property by name instead of frame slot.
|
|
||||||
*/
|
|
||||||
if (FUN_FLAT_CLOSURE(fun)) {
|
|
||||||
JS_ASSERT(funobj->dslots);
|
|
||||||
JS_ASSERT(JSSLOT_FREE(&js_FunctionClass) == JS_INITIAL_NSLOTS);
|
|
||||||
|
|
||||||
uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
|
|
||||||
JS_ASSERT(nslots == JS_INITIAL_NSLOTS);
|
|
||||||
nslots += js_FunctionClass.reserveSlots(cx, clone);
|
|
||||||
if (!js_ReallocSlots(cx, clone, nslots, JS_TRUE))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
|
|
||||||
JS_ASSERT(uva->length <= size_t(clone->dslots[-1]));
|
|
||||||
|
|
||||||
void *mark = JS_ARENA_MARK(&cx->tempPool);
|
|
||||||
jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool);
|
|
||||||
if (!names)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
uint32 i = 0, n = uva->length;
|
|
||||||
for (; i < n; i++) {
|
|
||||||
JSObject *obj = parent;
|
|
||||||
for (uintN skip = UPVAR_FRAME_SKIP(uva->vector[i]); skip != 0; --skip) {
|
|
||||||
if (!obj) {
|
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
||||||
JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
|
|
||||||
goto break2;
|
|
||||||
}
|
|
||||||
obj = OBJ_GET_PARENT(cx, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(names[i]);
|
|
||||||
if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &clone->dslots[i]))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break2:
|
|
||||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
|
||||||
if (i < n)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
@@ -4737,8 +4673,8 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
|||||||
|
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
||||||
script = JSCompiler::compileScript(cx, obj, NULL, principals, tcflags,
|
script = js_CompileScript(cx, obj, NULL, principals, tcflags,
|
||||||
chars, length, NULL, filename, lineno);
|
chars, length, NULL, filename, lineno);
|
||||||
LAST_FRAME_CHECKS(cx, script);
|
LAST_FRAME_CHECKS(cx, script);
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
@@ -4750,6 +4686,7 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
|
|||||||
jschar *chars;
|
jschar *chars;
|
||||||
JSBool result;
|
JSBool result;
|
||||||
JSExceptionState *exnState;
|
JSExceptionState *exnState;
|
||||||
|
JSParseContext pc;
|
||||||
JSErrorReporter older;
|
JSErrorReporter older;
|
||||||
|
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
@@ -4763,21 +4700,20 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
|
|||||||
*/
|
*/
|
||||||
result = JS_TRUE;
|
result = JS_TRUE;
|
||||||
exnState = JS_SaveExceptionState(cx);
|
exnState = JS_SaveExceptionState(cx);
|
||||||
{
|
if (js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL, NULL,
|
||||||
JSCompiler jsc(cx);
|
1)) {
|
||||||
if (jsc.init(chars, length, NULL, NULL, 1)) {
|
older = JS_SetErrorReporter(cx, NULL);
|
||||||
older = JS_SetErrorReporter(cx, NULL);
|
if (!js_ParseScript(cx, obj, &pc) &&
|
||||||
if (!jsc.parse(obj) &&
|
(pc.tokenStream.flags & TSF_UNEXPECTED_EOF)) {
|
||||||
(jsc.tokenStream.flags & TSF_UNEXPECTED_EOF)) {
|
/*
|
||||||
/*
|
* We ran into an error. If it was because we ran out of source,
|
||||||
* We ran into an error. If it was because we ran out of
|
* we return false, so our caller will know to try to collect more
|
||||||
* source, we return false so our caller knows to try to
|
* buffered source.
|
||||||
* collect more buffered source.
|
*/
|
||||||
*/
|
result = JS_FALSE;
|
||||||
result = JS_FALSE;
|
|
||||||
}
|
|
||||||
JS_SetErrorReporter(cx, older);
|
|
||||||
}
|
}
|
||||||
|
JS_SetErrorReporter(cx, older);
|
||||||
|
js_FinishParseContext(cx, &pc);
|
||||||
}
|
}
|
||||||
JS_free(cx, chars);
|
JS_free(cx, chars);
|
||||||
JS_RestoreExceptionState(cx, exnState);
|
JS_RestoreExceptionState(cx, exnState);
|
||||||
@@ -4804,8 +4740,8 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
||||||
script = JSCompiler::compileScript(cx, obj, NULL, NULL, tcflags,
|
script = js_CompileScript(cx, obj, NULL, NULL, tcflags,
|
||||||
NULL, 0, fp, filename, 1);
|
NULL, 0, fp, filename, 1);
|
||||||
if (fp != stdin)
|
if (fp != stdin)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
LAST_FRAME_CHECKS(cx, script);
|
LAST_FRAME_CHECKS(cx, script);
|
||||||
@@ -4829,8 +4765,8 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
|
|||||||
|
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
||||||
script = JSCompiler::compileScript(cx, obj, NULL, principals, tcflags,
|
script = js_CompileScript(cx, obj, NULL, principals, tcflags,
|
||||||
NULL, 0, file, filename, 1);
|
NULL, 0, file, filename, 1);
|
||||||
LAST_FRAME_CHECKS(cx, script);
|
LAST_FRAME_CHECKS(cx, script);
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
@@ -4966,8 +4902,8 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JSCompiler::compileFunctionBody(cx, fun, principals,
|
if (!js_CompileFunctionBody(cx, fun, principals, chars, length,
|
||||||
chars, length, filename, lineno)) {
|
filename, lineno)) {
|
||||||
fun = NULL;
|
fun = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -5167,11 +5103,11 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
|||||||
JSBool ok;
|
JSBool ok;
|
||||||
|
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
script = JSCompiler::compileScript(cx, obj, NULL, principals,
|
script = js_CompileScript(cx, obj, NULL, principals,
|
||||||
!rval
|
!rval
|
||||||
? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
|
? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
|
||||||
: TCF_COMPILE_N_GO,
|
: TCF_COMPILE_N_GO,
|
||||||
chars, length, NULL, filename, lineno);
|
chars, length, NULL, filename, lineno);
|
||||||
if (!script) {
|
if (!script) {
|
||||||
LAST_FRAME_CHECKS(cx, script);
|
LAST_FRAME_CHECKS(cx, script);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|||||||
@@ -235,8 +235,8 @@ BOOLEAN_TO_JSVAL(JSBool b)
|
|||||||
#define JSFUN_FAST_NATIVE 0x0800 /* JSFastNative needs no JSStackFrame */
|
#define JSFUN_FAST_NATIVE 0x0800 /* JSFastNative needs no JSStackFrame */
|
||||||
|
|
||||||
#define JSFUN_FLAGS_MASK 0x0ff8 /* overlay JSFUN_* attributes --
|
#define JSFUN_FLAGS_MASK 0x0ff8 /* overlay JSFUN_* attributes --
|
||||||
bits 12-15 are used internally to
|
note that bit #15 is used internally
|
||||||
flag interpreted functions */
|
to flag interpreted functions */
|
||||||
|
|
||||||
#define JSFUN_STUB_GSOPS 0x1000 /* use JS_PropertyStub getter/setter
|
#define JSFUN_STUB_GSOPS 0x1000 /* use JS_PropertyStub getter/setter
|
||||||
instead of defaulting to class gsops
|
instead of defaulting to class gsops
|
||||||
|
|||||||
@@ -3277,7 +3277,7 @@ js_FastNewArrayWithLength(JSContext* cx, JSObject* proto, uint32 i)
|
|||||||
JSObject* FASTCALL
|
JSObject* FASTCALL
|
||||||
js_NewUninitializedArray(JSContext* cx, JSObject* proto, uint32 len)
|
js_NewUninitializedArray(JSContext* cx, JSObject* proto, uint32 len)
|
||||||
{
|
{
|
||||||
JSObject* obj = js_FastNewArrayWithLength(cx, proto, len);
|
JSObject *obj = js_FastNewArrayWithLength(cx, proto, len);
|
||||||
if (!obj || !ResizeSlots(cx, obj, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
|
if (!obj || !ResizeSlots(cx, obj, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
|
||||||
return NULL;
|
return NULL;
|
||||||
return obj;
|
return obj;
|
||||||
|
|||||||
@@ -73,11 +73,8 @@ extern JSClass js_ArrayClass, js_SlowArrayClass;
|
|||||||
*
|
*
|
||||||
* Therefore the interpreter (js_Interpret in JSOP_GETPROP and JSOP_CALLPROP)
|
* Therefore the interpreter (js_Interpret in JSOP_GETPROP and JSOP_CALLPROP)
|
||||||
* and js_GetPropertyHelper use this inline function to skip up one link in the
|
* and js_GetPropertyHelper use this inline function to skip up one link in the
|
||||||
* prototype chain when obj is a dense array, in order to find a native object
|
* prototype chain when obj is a dense array, in order to find a likely-native
|
||||||
* (to wit, Array.prototype) in which to probe for cached methods.
|
* object (to wit, Array.prototype) in which to probe for cached methods.
|
||||||
*
|
|
||||||
* Note that setting aobj.__proto__ for a dense array aobj turns aobj into a
|
|
||||||
* slow array, avoiding the neede to skip.
|
|
||||||
*
|
*
|
||||||
* Callers of js_GetProtoIfDenseArray must take care to use the original object
|
* Callers of js_GetProtoIfDenseArray must take care to use the original object
|
||||||
* (obj) for the |this| value of a getter, setter, or method call (bug 476447).
|
* (obj) for the |this| value of a getter, setter, or method call (bug 476447).
|
||||||
|
|||||||
@@ -49,15 +49,13 @@
|
|||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jsatom.h"
|
#include "jsatom.h"
|
||||||
#include "jsbit.h"
|
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
#include "jsversion.h"
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
#include "jslock.h"
|
#include "jslock.h"
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
#include "jsparse.h"
|
|
||||||
#include "jsscan.h"
|
#include "jsscan.h"
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
#include "jsversion.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ATOM_HASH assumes that JSHashNumber is 32-bit even on 64-bit systems.
|
* ATOM_HASH assumes that JSHashNumber is 32-bit even on 64-bit systems.
|
||||||
@@ -935,70 +933,32 @@ js_hash_atom_ptr(const void *key)
|
|||||||
return ATOM_HASH(atom);
|
return ATOM_HASH(atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JS_BITS_PER_WORD == 32
|
|
||||||
# define TEMP_SIZE_START_LOG2 5
|
|
||||||
#else
|
|
||||||
# define TEMP_SIZE_START_LOG2 6
|
|
||||||
#endif
|
|
||||||
#define TEMP_SIZE_LIMIT_LOG2 (TEMP_SIZE_START_LOG2 + NUM_TEMP_FREELISTS)
|
|
||||||
|
|
||||||
#define TEMP_SIZE_START JS_BIT(TEMP_SIZE_START_LOG2)
|
|
||||||
#define TEMP_SIZE_LIMIT JS_BIT(TEMP_SIZE_LIMIT_LOG2)
|
|
||||||
|
|
||||||
JS_STATIC_ASSERT(TEMP_SIZE_START >= sizeof(JSHashTable));
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
js_alloc_temp_space(void *priv, size_t size)
|
js_alloc_temp_space(void *priv, size_t size)
|
||||||
{
|
{
|
||||||
JSCompiler *jsc = (JSCompiler *) priv;
|
JSContext *cx = (JSContext *) priv;
|
||||||
|
|
||||||
void *space;
|
void *space;
|
||||||
if (size < TEMP_SIZE_LIMIT) {
|
|
||||||
int bin = JS_CeilingLog2(size) - TEMP_SIZE_START_LOG2;
|
|
||||||
JS_ASSERT(unsigned(bin) < NUM_TEMP_FREELISTS);
|
|
||||||
|
|
||||||
space = jsc->tempFreeList[bin];
|
JS_ARENA_ALLOCATE(space, &cx->tempPool, size);
|
||||||
if (space) {
|
|
||||||
jsc->tempFreeList[bin] = *(void **)space;
|
|
||||||
return space;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ARENA_ALLOCATE(space, &jsc->context->tempPool, size);
|
|
||||||
if (!space)
|
if (!space)
|
||||||
js_ReportOutOfScriptQuota(jsc->context);
|
js_ReportOutOfScriptQuota(cx);
|
||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
js_free_temp_space(void *priv, void *item, size_t size)
|
js_free_temp_space(void *priv, void *item)
|
||||||
{
|
{
|
||||||
if (size >= TEMP_SIZE_LIMIT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
JSCompiler *jsc = (JSCompiler *) priv;
|
|
||||||
int bin = JS_CeilingLog2(size) - TEMP_SIZE_START_LOG2;
|
|
||||||
JS_ASSERT(unsigned(bin) < NUM_TEMP_FREELISTS);
|
|
||||||
|
|
||||||
*(void **)item = jsc->tempFreeList[bin];
|
|
||||||
jsc->tempFreeList[bin] = item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSHashEntry *
|
static JSHashEntry *
|
||||||
js_alloc_temp_entry(void *priv, const void *key)
|
js_alloc_temp_entry(void *priv, const void *key)
|
||||||
{
|
{
|
||||||
JSCompiler *jsc = (JSCompiler *) priv;
|
JSContext *cx = (JSContext *) priv;
|
||||||
JSAtomListElement *ale;
|
JSAtomListElement *ale;
|
||||||
|
|
||||||
ale = jsc->aleFreeList;
|
JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool);
|
||||||
if (ale) {
|
|
||||||
jsc->aleFreeList = ALE_NEXT(ale);
|
|
||||||
return &ale->entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &jsc->context->tempPool);
|
|
||||||
if (!ale) {
|
if (!ale) {
|
||||||
js_ReportOutOfScriptQuota(jsc->context);
|
js_ReportOutOfScriptQuota(cx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &ale->entry;
|
return &ale->entry;
|
||||||
@@ -1007,11 +967,6 @@ js_alloc_temp_entry(void *priv, const void *key)
|
|||||||
static void
|
static void
|
||||||
js_free_temp_entry(void *priv, JSHashEntry *he, uintN flag)
|
js_free_temp_entry(void *priv, JSHashEntry *he, uintN flag)
|
||||||
{
|
{
|
||||||
JSCompiler *jsc = (JSCompiler *) priv;
|
|
||||||
JSAtomListElement *ale = (JSAtomListElement *) he;
|
|
||||||
|
|
||||||
ALE_SET_NEXT(ale, jsc->aleFreeList);
|
|
||||||
jsc->aleFreeList = ale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSHashAllocOps temp_alloc_ops = {
|
static JSHashAllocOps temp_alloc_ops = {
|
||||||
@@ -1020,181 +975,67 @@ static JSHashAllocOps temp_alloc_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
JSAtomListElement *
|
JSAtomListElement *
|
||||||
JSAtomList::rawLookup(JSAtom *atom, JSHashEntry **&hep)
|
js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al)
|
||||||
{
|
{
|
||||||
JSAtomListElement *ale;
|
|
||||||
|
|
||||||
if (table) {
|
|
||||||
hep = JS_HashTableRawLookup(table, ATOM_HASH(atom), atom);
|
|
||||||
ale = *hep ? (JSAtomListElement *) *hep : NULL;
|
|
||||||
} else {
|
|
||||||
JSHashEntry **alep = &list;
|
|
||||||
hep = NULL;
|
|
||||||
while ((ale = (JSAtomListElement *)*alep) != NULL) {
|
|
||||||
if (ALE_ATOM(ale) == atom) {
|
|
||||||
/* Hit, move atom's element to the front of the list. */
|
|
||||||
*alep = ale->entry.next;
|
|
||||||
ale->entry.next = list;
|
|
||||||
list = &ale->entry;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
alep = &ale->entry.next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ale;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ATOM_LIST_HASH_THRESHOLD 12
|
|
||||||
|
|
||||||
JSAtomListElement *
|
|
||||||
JSAtomList::add(JSCompiler *jsc, JSAtom *atom, AddHow how)
|
|
||||||
{
|
|
||||||
JS_ASSERT(!set);
|
|
||||||
|
|
||||||
JSAtomListElement *ale, *ale2, *next;
|
JSAtomListElement *ale, *ale2, *next;
|
||||||
JSHashEntry **hep;
|
JSHashEntry **hep;
|
||||||
|
|
||||||
ale = rawLookup(atom, hep);
|
ATOM_LIST_LOOKUP(ale, hep, al, atom);
|
||||||
if (!ale || how != UNIQUE) {
|
if (!ale) {
|
||||||
if (count < ATOM_LIST_HASH_THRESHOLD && !table) {
|
if (al->count < 10) {
|
||||||
/* Few enough for linear search and no hash table yet needed. */
|
/* Few enough for linear search, no hash table needed. */
|
||||||
ale = (JSAtomListElement *)js_alloc_temp_entry(jsc, atom);
|
JS_ASSERT(!al->table);
|
||||||
|
ale = (JSAtomListElement *)js_alloc_temp_entry(cx, atom);
|
||||||
if (!ale)
|
if (!ale)
|
||||||
return NULL;
|
return NULL;
|
||||||
ALE_SET_ATOM(ale, atom);
|
ALE_SET_ATOM(ale, atom);
|
||||||
|
ale->entry.next = al->list;
|
||||||
if (how == HOIST) {
|
al->list = &ale->entry;
|
||||||
ale->entry.next = NULL;
|
|
||||||
hep = (JSHashEntry **) &list;
|
|
||||||
while (*hep)
|
|
||||||
hep = &(*hep)->next;
|
|
||||||
*hep = &ale->entry;
|
|
||||||
} else {
|
|
||||||
ale->entry.next = list;
|
|
||||||
list = &ale->entry;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/* We want to hash. Have we already made a hash table? */
|
||||||
* We should hash, or else we already are hashing, but count was
|
if (!al->table) {
|
||||||
* reduced by JSAtomList::rawRemove below ATOM_LIST_HASH_THRESHOLD.
|
|
||||||
* Check whether we should create the table.
|
|
||||||
*/
|
|
||||||
if (!table) {
|
|
||||||
/* No hash table yet, so hep had better be null! */
|
/* No hash table yet, so hep had better be null! */
|
||||||
JS_ASSERT(!hep);
|
JS_ASSERT(!hep);
|
||||||
table = JS_NewHashTable(count + 1, js_hash_atom_ptr,
|
al->table = JS_NewHashTable(al->count + 1, js_hash_atom_ptr,
|
||||||
JS_CompareValues, JS_CompareValues,
|
JS_CompareValues, JS_CompareValues,
|
||||||
&temp_alloc_ops, jsc);
|
&temp_alloc_ops, cx);
|
||||||
if (!table)
|
if (!al->table)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set ht->nentries explicitly, because we are moving entries
|
* Set ht->nentries explicitly, because we are moving entries
|
||||||
* from list to ht, not calling JS_HashTable(Raw|)Add.
|
* from al to ht, not calling JS_HashTable(Raw|)Add.
|
||||||
*/
|
*/
|
||||||
table->nentries = count;
|
al->table->nentries = al->count;
|
||||||
|
|
||||||
/*
|
/* Insert each ale on al->list into the new hash table. */
|
||||||
* Insert each ale on list into the new hash table. Append to
|
for (ale2 = (JSAtomListElement *)al->list; ale2; ale2 = next) {
|
||||||
* the hash chain rather than inserting at the bucket head, to
|
|
||||||
* preserve order among entries with the same key.
|
|
||||||
*/
|
|
||||||
for (ale2 = (JSAtomListElement *)list; ale2; ale2 = next) {
|
|
||||||
next = ALE_NEXT(ale2);
|
next = ALE_NEXT(ale2);
|
||||||
ale2->entry.keyHash = ATOM_HASH(ALE_ATOM(ale2));
|
ale2->entry.keyHash = ATOM_HASH(ALE_ATOM(ale2));
|
||||||
hep = JS_HashTableRawLookup(table, ale2->entry.keyHash,
|
hep = JS_HashTableRawLookup(al->table, ale2->entry.keyHash,
|
||||||
ale2->entry.key);
|
ale2->entry.key);
|
||||||
while (*hep)
|
ale2->entry.next = *hep;
|
||||||
hep = &(*hep)->next;
|
|
||||||
*hep = &ale2->entry;
|
*hep = &ale2->entry;
|
||||||
ale2->entry.next = NULL;
|
|
||||||
}
|
}
|
||||||
list = NULL;
|
al->list = NULL;
|
||||||
|
|
||||||
/* Set hep for insertion of atom's ale, immediately below. */
|
/* Set hep for insertion of atom's ale, immediately below. */
|
||||||
hep = JS_HashTableRawLookup(table, ATOM_HASH(atom), atom);
|
hep = JS_HashTableRawLookup(al->table, ATOM_HASH(atom), atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, add an entry for atom into the hash bucket at hep. */
|
/* Finally, add an entry for atom into the hash bucket at hep. */
|
||||||
ale = (JSAtomListElement *)
|
ale = (JSAtomListElement *)
|
||||||
JS_HashTableRawAdd(table, hep, ATOM_HASH(atom), atom, NULL);
|
JS_HashTableRawAdd(al->table, hep, ATOM_HASH(atom), atom,
|
||||||
|
NULL);
|
||||||
if (!ale)
|
if (!ale)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
|
||||||
* If hoisting, move ale to the end of its chain after we called
|
|
||||||
* JS_HashTableRawAdd, since RawAdd may have grown the table and
|
|
||||||
* then recomputed hep to refer to the pointer to the first entry
|
|
||||||
* with the given key.
|
|
||||||
*/
|
|
||||||
if (how == HOIST && ale->entry.next) {
|
|
||||||
*hep = ale->entry.next;
|
|
||||||
ale->entry.next = NULL;
|
|
||||||
do {
|
|
||||||
hep = &(*hep)->next;
|
|
||||||
} while (*hep);
|
|
||||||
*hep = &ale->entry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ALE_SET_INDEX(ale, count++);
|
ALE_SET_INDEX(ale, al->count++);
|
||||||
}
|
}
|
||||||
return ale;
|
return ale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
JSAtomList::rawRemove(JSCompiler *jsc, JSAtomListElement *ale, JSHashEntry **hep)
|
|
||||||
{
|
|
||||||
JS_ASSERT(!set);
|
|
||||||
JS_ASSERT(count != 0);
|
|
||||||
|
|
||||||
if (table) {
|
|
||||||
JS_ASSERT(hep);
|
|
||||||
JS_HashTableRawRemove(table, hep, &ale->entry);
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(!hep);
|
|
||||||
hep = &list;
|
|
||||||
while (*hep != &ale->entry) {
|
|
||||||
JS_ASSERT(*hep);
|
|
||||||
hep = &(*hep)->next;
|
|
||||||
}
|
|
||||||
*hep = ale->entry.next;
|
|
||||||
js_free_temp_entry(jsc, &ale->entry, HT_FREE_ENTRY);
|
|
||||||
}
|
|
||||||
|
|
||||||
--count;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSAtomListElement *
|
|
||||||
JSAtomListIterator::operator ()()
|
|
||||||
{
|
|
||||||
JSAtomListElement *ale;
|
|
||||||
JSHashTable *ht;
|
|
||||||
|
|
||||||
if (index == uint32(-1))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ale = next;
|
|
||||||
if (!ale) {
|
|
||||||
ht = list->table;
|
|
||||||
if (!ht)
|
|
||||||
goto done;
|
|
||||||
do {
|
|
||||||
if (index == JS_BIT(JS_HASH_BITS - ht->shift))
|
|
||||||
goto done;
|
|
||||||
next = (JSAtomListElement *) ht->buckets[index++];
|
|
||||||
} while (!next);
|
|
||||||
ale = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
next = ALE_NEXT(ale);
|
|
||||||
return ale;
|
|
||||||
|
|
||||||
done:
|
|
||||||
index = uint32(-1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static intN
|
static intN
|
||||||
js_map_atom(JSHashEntry *he, intN i, void *arg)
|
js_map_atom(JSHashEntry *he, intN i, void *arg)
|
||||||
{
|
{
|
||||||
@@ -1240,5 +1081,5 @@ js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al)
|
|||||||
vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
|
vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
|
||||||
} while ((ale = ALE_NEXT(ale)) != NULL);
|
} while ((ale = ALE_NEXT(ale)) != NULL);
|
||||||
}
|
}
|
||||||
al->clear();
|
ATOM_LIST_INIT(al);
|
||||||
}
|
}
|
||||||
|
|||||||
116
js/src/jsatom.h
116
js/src/jsatom.h
@@ -88,99 +88,51 @@ struct JSAtomListElement {
|
|||||||
|
|
||||||
#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key)
|
#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key)
|
||||||
#define ALE_INDEX(ale) ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value))
|
#define ALE_INDEX(ale) ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value))
|
||||||
#define ALE_DEFN(ale) ((JSDefinition *) (ale)->entry.value)
|
#define ALE_JSOP(ale) ((JSOp) JS_PTR_TO_UINT32((ale)->entry.value))
|
||||||
#define ALE_VALUE(ale) ((jsval) (ale)->entry.value)
|
#define ALE_VALUE(ale) ((jsval) (ale)->entry.value)
|
||||||
#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next)
|
#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next)
|
||||||
|
|
||||||
#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom))
|
#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom))
|
||||||
#define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index))
|
#define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index))
|
||||||
#define ALE_SET_DEFN(ale, dn) ((ale)->entry.value = (void *)(dn))
|
#define ALE_SET_JSOP(ale,op) ((ale)->entry.value = JS_UINT32_TO_PTR(op))
|
||||||
#define ALE_SET_VALUE(ale, v) ((ale)->entry.value = (void *)(v))
|
#define ALE_SET_VALUE(ale, v) ((ale)->entry.value = (void *)(v))
|
||||||
#define ALE_SET_NEXT(ale,nxt) ((ale)->entry.next = (JSHashEntry *)(nxt))
|
|
||||||
|
|
||||||
/*
|
struct JSAtomList {
|
||||||
* NB: JSAtomSet must be plain-old-data as it is embedded in the pn_u union in
|
|
||||||
* JSParseNode. JSAtomList encapsulates all operational uses of a JSAtomSet.
|
|
||||||
*
|
|
||||||
* The JSAtomList name is traditional, even though the implementation is a map
|
|
||||||
* (not to be confused with JSAtomMap). In particular the "ALE" and "ale" short
|
|
||||||
* names for JSAtomListElement variables roll off the fingers, compared to ASE
|
|
||||||
* or AME alternatives.
|
|
||||||
*/
|
|
||||||
struct JSAtomSet {
|
|
||||||
JSHashEntry *list; /* literals indexed for mapping */
|
JSHashEntry *list; /* literals indexed for mapping */
|
||||||
JSHashTable *table; /* hash table if list gets too long */
|
JSHashTable *table; /* hash table if list gets too long */
|
||||||
jsuint count; /* count of indexed literals */
|
jsuint count; /* count of indexed literals */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#define ATOM_LIST_INIT(al) ((al)->list = NULL, (al)->table = NULL, \
|
||||||
|
(al)->count = 0)
|
||||||
|
|
||||||
struct JSAtomList : public JSAtomSet
|
#define ATOM_LIST_SEARCH(_ale,_al,_atom) \
|
||||||
{
|
JS_BEGIN_MACRO \
|
||||||
#ifdef DEBUG
|
JSHashEntry **_hep; \
|
||||||
const JSAtomSet* set; /* asserted null in mutating methods */
|
ATOM_LIST_LOOKUP(_ale, _hep, _al, _atom); \
|
||||||
#endif
|
JS_END_MACRO
|
||||||
|
|
||||||
JSAtomList() {
|
#define ATOM_LIST_LOOKUP(_ale,_hep,_al,_atom) \
|
||||||
list = NULL; table = NULL; count = 0;
|
JS_BEGIN_MACRO \
|
||||||
#ifdef DEBUG
|
if ((_al)->table) { \
|
||||||
set = NULL;
|
_hep = JS_HashTableRawLookup((_al)->table, ATOM_HASH(_atom), \
|
||||||
#endif
|
_atom); \
|
||||||
}
|
_ale = *_hep ? (JSAtomListElement *) *_hep : NULL; \
|
||||||
|
} else { \
|
||||||
JSAtomList(const JSAtomSet& as) {
|
JSHashEntry **_alep = &(_al)->list; \
|
||||||
list = as.list; table = as.table; count = as.count;
|
_hep = NULL; \
|
||||||
#ifdef DEBUG
|
while ((_ale = (JSAtomListElement *)*_alep) != NULL) { \
|
||||||
set = &as;
|
if (ALE_ATOM(_ale) == (_atom)) { \
|
||||||
#endif
|
/* Hit, move atom's element to the front of the list. */ \
|
||||||
}
|
*_alep = (_ale)->entry.next; \
|
||||||
|
(_ale)->entry.next = (_al)->list; \
|
||||||
void clear() { JS_ASSERT(!set); list = NULL; table = NULL; count = 0; }
|
(_al)->list = &_ale->entry; \
|
||||||
|
break; \
|
||||||
JSAtomListElement *lookup(JSAtom *atom) {
|
} \
|
||||||
JSHashEntry **hep;
|
_alep = &_ale->entry.next; \
|
||||||
return rawLookup(atom, hep);
|
} \
|
||||||
}
|
} \
|
||||||
|
JS_END_MACRO
|
||||||
JSAtomListElement *rawLookup(JSAtom *atom, JSHashEntry **&hep);
|
|
||||||
|
|
||||||
enum AddHow { UNIQUE, SHADOW, HOIST };
|
|
||||||
|
|
||||||
JSAtomListElement *add(JSCompiler *jsc, JSAtom *atom, AddHow how = UNIQUE);
|
|
||||||
|
|
||||||
void remove(JSCompiler *jsc, JSAtom *atom) {
|
|
||||||
JSHashEntry **hep;
|
|
||||||
JSAtomListElement *ale = rawLookup(atom, hep);
|
|
||||||
if (ale)
|
|
||||||
rawRemove(jsc, ale, hep);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rawRemove(JSCompiler *jsc, JSAtomListElement *ale, JSHashEntry **hep);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Iterate over an atom list. We define a call operator to minimize the syntax
|
|
||||||
* tax for users. We do not use a more standard pattern using ++ and * because
|
|
||||||
* (a) it's the wrong pattern for a non-scalar; (b) it's overkill -- one method
|
|
||||||
* is enough. (This comment is overkill!)
|
|
||||||
*/
|
|
||||||
class JSAtomListIterator {
|
|
||||||
JSAtomList* list;
|
|
||||||
JSAtomListElement* next;
|
|
||||||
uint32 index;
|
|
||||||
|
|
||||||
public:
|
|
||||||
JSAtomListIterator(JSAtomList* al) : list(al) { reset(); }
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
next = (JSAtomListElement *) list->list;
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSAtomListElement* operator ()();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
struct JSAtomMap {
|
struct JSAtomMap {
|
||||||
JSAtom **vector; /* array of ptrs to indexed atoms */
|
JSAtom **vector; /* array of ptrs to indexed atoms */
|
||||||
@@ -474,6 +426,12 @@ js_DumpAtoms(JSContext *cx, FILE *fp);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assign atom an index and insert it on al.
|
||||||
|
*/
|
||||||
|
extern JSAtomListElement *
|
||||||
|
js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For all unmapped atoms recorded in al, add a mapping from the atom's index
|
* For all unmapped atoms recorded in al, add a mapping from the atom's index
|
||||||
* to its address. map->length must already be set to the number of atoms in
|
* to its address. map->length must already be set to the number of atoms in
|
||||||
|
|||||||
@@ -253,10 +253,8 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
|
|||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot != sprop->slot) {
|
if (slot != sprop->slot)
|
||||||
js_FreeSlot(cx, obj, slot);
|
|
||||||
goto slot_changed;
|
goto slot_changed;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SCOPE_EXTEND_SHAPE(cx, scope, sprop);
|
SCOPE_EXTEND_SHAPE(cx, scope, sprop);
|
||||||
@@ -276,6 +274,7 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
|
|||||||
slot = sprop2->slot;
|
slot = sprop2->slot;
|
||||||
|
|
||||||
slot_changed:
|
slot_changed:
|
||||||
|
js_FreeSlot(cx, obj, slot);
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
@@ -368,31 +367,6 @@ js_Arguments(JSContext* cx)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* FASTCALL
|
|
||||||
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject *parent)
|
|
||||||
{
|
|
||||||
JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
|
|
||||||
|
|
||||||
JSFunction *fun = (JSFunction*) funobj;
|
|
||||||
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
|
|
||||||
|
|
||||||
JS_ASSERT(JS_ON_TRACE(cx));
|
|
||||||
JSObject* closure = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
|
|
||||||
if (!closure)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
closure->classword = jsuword(&js_FunctionClass);
|
|
||||||
closure->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
|
||||||
closure->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
|
|
||||||
closure->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
|
|
||||||
for (unsigned i = JSSLOT_PRIVATE + 1; i != JS_INITIAL_NSLOTS; ++i)
|
|
||||||
closure->fslots[i] = JSVAL_VOID;
|
|
||||||
|
|
||||||
closure->map = js_HoldObjectMap(cx, proto->map);
|
|
||||||
closure->dslots = NULL;
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BUILTIN1 JS_DEFINE_CALLINFO_1
|
#define BUILTIN1 JS_DEFINE_CALLINFO_1
|
||||||
#define BUILTIN2 JS_DEFINE_CALLINFO_2
|
#define BUILTIN2 JS_DEFINE_CALLINFO_2
|
||||||
#define BUILTIN3 JS_DEFINE_CALLINFO_3
|
#define BUILTIN3 JS_DEFINE_CALLINFO_3
|
||||||
|
|||||||
@@ -471,27 +471,26 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
|||||||
#if defined DEBUG && defined XP_UNIX
|
#if defined DEBUG && defined XP_UNIX
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
|
|
||||||
class JSAutoFile {
|
class AutoFile {
|
||||||
public:
|
public:
|
||||||
JSAutoFile() : mFile(NULL) {}
|
AutoFile() : mFp(NULL) {}
|
||||||
|
|
||||||
~JSAutoFile() {
|
~AutoFile() {
|
||||||
if (mFile)
|
if (mFp)
|
||||||
fclose(mFile);
|
fclose(mFp);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *open(const char *fname, const char *mode) {
|
FILE *open(const char *fname, const char *mode) {
|
||||||
return mFile = fopen(fname, mode);
|
return mFp = fopen(fname, mode);
|
||||||
}
|
}
|
||||||
operator FILE *() {
|
operator FILE *() {
|
||||||
return mFile;
|
return mFp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FILE *mFile;
|
FILE *mFp;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef JS_EVAL_CACHE_METERING
|
|
||||||
static void
|
static void
|
||||||
DumpEvalCacheMeter(JSContext *cx)
|
DumpEvalCacheMeter(JSContext *cx)
|
||||||
{
|
{
|
||||||
@@ -505,7 +504,7 @@ DumpEvalCacheMeter(JSContext *cx)
|
|||||||
};
|
};
|
||||||
JSEvalCacheMeter *ecm = &JS_THREAD_DATA(cx)->evalCacheMeter;
|
JSEvalCacheMeter *ecm = &JS_THREAD_DATA(cx)->evalCacheMeter;
|
||||||
|
|
||||||
static JSAutoFile fp;
|
static AutoFile fp;
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
fp.open("/tmp/evalcache.stats", "w");
|
fp.open("/tmp/evalcache.stats", "w");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
@@ -528,49 +527,10 @@ DumpEvalCacheMeter(JSContext *cx)
|
|||||||
fflush(fp);
|
fflush(fp);
|
||||||
}
|
}
|
||||||
# define DUMP_EVAL_CACHE_METER(cx) DumpEvalCacheMeter(cx)
|
# define DUMP_EVAL_CACHE_METER(cx) DumpEvalCacheMeter(cx)
|
||||||
#endif
|
#else
|
||||||
|
|
||||||
#ifdef JS_FUNCTION_METERING
|
|
||||||
static void
|
|
||||||
DumpFunctionMeter(JSContext *cx)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
const char *name;
|
|
||||||
ptrdiff_t offset;
|
|
||||||
} table[] = {
|
|
||||||
#define frob(x) { #x, offsetof(JSFunctionMeter, x) }
|
|
||||||
FUNCTION_KIND_METER_LIST(frob)
|
|
||||||
#undef frob
|
|
||||||
};
|
|
||||||
JSFunctionMeter *fm = &cx->runtime->functionMeter;
|
|
||||||
|
|
||||||
static JSAutoFile fp;
|
|
||||||
if (!fp) {
|
|
||||||
fp.open("/tmp/function.stats", "a");
|
|
||||||
if (!fp)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "function meter (%s):\n", cx->runtime->lastScriptFilename);
|
|
||||||
for (uintN i = 0; i < JS_ARRAY_LENGTH(table); ++i) {
|
|
||||||
fprintf(fp, "%-11.11s %d\n",
|
|
||||||
table[i].name, *(int32 *)((uint8 *)fm + table[i].offset));
|
|
||||||
}
|
|
||||||
fflush(fp);
|
|
||||||
}
|
|
||||||
# define DUMP_FUNCTION_METER(cx) DumpFunctionMeter(cx)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* DEBUG && XP_UNIX */
|
|
||||||
|
|
||||||
#ifndef DUMP_EVAL_CACHE_METER
|
|
||||||
# define DUMP_EVAL_CACHE_METER(cx) ((void) 0)
|
# define DUMP_EVAL_CACHE_METER(cx) ((void) 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DUMP_FUNCTION_METER
|
|
||||||
# define DUMP_FUNCTION_METER(cx) ((void) 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
void
|
||||||
js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||||
{
|
{
|
||||||
@@ -673,7 +633,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
|||||||
if (last) {
|
if (last) {
|
||||||
js_GC(cx, GC_LAST_CONTEXT);
|
js_GC(cx, GC_LAST_CONTEXT);
|
||||||
DUMP_EVAL_CACHE_METER(cx);
|
DUMP_EVAL_CACHE_METER(cx);
|
||||||
DUMP_FUNCTION_METER(cx);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the script filename table if it exists and is empty. Do this
|
* Free the script filename table if it exists and is empty. Do this
|
||||||
|
|||||||
@@ -198,8 +198,7 @@ typedef struct InterpStruct InterpStruct;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define JS_EVAL_CACHE_METERING 1
|
# define JS_EVAL_CACHE_METERING 1
|
||||||
# define JS_FUNCTION_METERING 1
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
|
/* Number of potentially reusable scriptsToGC to search for the eval cache. */
|
||||||
@@ -210,27 +209,14 @@ typedef struct InterpStruct InterpStruct;
|
|||||||
|
|
||||||
#ifdef JS_EVAL_CACHE_METERING
|
#ifdef JS_EVAL_CACHE_METERING
|
||||||
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
|
# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope)
|
||||||
# define identity(x) x
|
# define ID(x) x
|
||||||
|
|
||||||
/* Have to typedef this for LiveConnect C code, which includes us. */
|
/* Have to typedef this for LiveConnect C code, which includes us. */
|
||||||
typedef struct JSEvalCacheMeter {
|
typedef struct JSEvalCacheMeter {
|
||||||
uint64 EVAL_CACHE_METER_LIST(identity);
|
uint64 EVAL_CACHE_METER_LIST(ID);
|
||||||
} JSEvalCacheMeter;
|
} JSEvalCacheMeter;
|
||||||
|
|
||||||
# undef identity
|
# undef ID
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JS_FUNCTION_METERING
|
|
||||||
# define FUNCTION_KIND_METER_LIST(_) \
|
|
||||||
_(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \
|
|
||||||
_(display), _(flat), _(setupvar), _(badfunarg)
|
|
||||||
# define identity(x) x
|
|
||||||
|
|
||||||
typedef struct JSFunctionMeter {
|
|
||||||
int32 FUNCTION_KIND_METER_LIST(identity);
|
|
||||||
} JSFunctionMeter;
|
|
||||||
|
|
||||||
# undef identity
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct JSThreadData {
|
struct JSThreadData {
|
||||||
@@ -669,11 +655,6 @@ struct JSRuntime {
|
|||||||
#ifdef JS_GCMETER
|
#ifdef JS_GCMETER
|
||||||
JSGCStats gcStats;
|
JSGCStats gcStats;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JS_FUNCTION_METERING
|
|
||||||
JSFunctionMeter functionMeter;
|
|
||||||
char lastScriptFilename[1024];
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
|
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
|
||||||
@@ -687,6 +668,7 @@ struct JSRuntime {
|
|||||||
#else
|
#else
|
||||||
# define EVAL_CACHE_METER(x) ((void) 0)
|
# define EVAL_CACHE_METER(x) ((void) 0)
|
||||||
#endif
|
#endif
|
||||||
|
#undef DECLARE_EVAL_CACHE_METER
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
|
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
|
||||||
@@ -781,7 +763,7 @@ typedef struct JSLocalRootStack {
|
|||||||
* structure */
|
* structure */
|
||||||
#define JSTVU_SPROP (-3) /* u.sprop roots property tree node */
|
#define JSTVU_SPROP (-3) /* u.sprop roots property tree node */
|
||||||
#define JSTVU_WEAK_ROOTS (-4) /* u.weakRoots points to saved weak roots */
|
#define JSTVU_WEAK_ROOTS (-4) /* u.weakRoots points to saved weak roots */
|
||||||
#define JSTVU_COMPILER (-5) /* u.compiler roots JSCompiler* */
|
#define JSTVU_PARSE_CONTEXT (-5) /* u.parseContext roots JSParseContext* */
|
||||||
#define JSTVU_SCRIPT (-6) /* u.script roots JSScript* */
|
#define JSTVU_SCRIPT (-6) /* u.script roots JSScript* */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -836,8 +818,8 @@ typedef struct JSLocalRootStack {
|
|||||||
#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr) \
|
#define JS_PUSH_TEMP_ROOT_WEAK_COPY(cx,weakRoots_,tvr) \
|
||||||
JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots)
|
JS_PUSH_TEMP_ROOT_COMMON(cx, weakRoots_, tvr, JSTVU_WEAK_ROOTS, weakRoots)
|
||||||
|
|
||||||
#define JS_PUSH_TEMP_ROOT_COMPILER(cx,pc,tvr) \
|
#define JS_PUSH_TEMP_ROOT_PARSE_CONTEXT(cx,pc,tvr) \
|
||||||
JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_COMPILER, compiler)
|
JS_PUSH_TEMP_ROOT_COMMON(cx, pc, tvr, JSTVU_PARSE_CONTEXT, parseContext)
|
||||||
|
|
||||||
#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr) \
|
#define JS_PUSH_TEMP_ROOT_SCRIPT(cx,script_,tvr) \
|
||||||
JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script)
|
JS_PUSH_TEMP_ROOT_COMMON(cx, script_, tvr, JSTVU_SCRIPT, script)
|
||||||
@@ -1073,7 +1055,7 @@ class JSAutoTempValueRooter
|
|||||||
}
|
}
|
||||||
|
|
||||||
jsval value() { return mTvr.u.value; }
|
jsval value() { return mTvr.u.value; }
|
||||||
jsval *addr() { return &mTvr.u.value; }
|
jsval * addr() { return &mTvr.u.value; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
JSContext *mContext;
|
JSContext *mContext;
|
||||||
|
|||||||
@@ -1252,15 +1252,15 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* NB: This function breaks the assumption that the compiler can see all
|
* NB: This function breaks the assumption that the compiler can see all
|
||||||
* calls and properly compute a static level. In order to get around this,
|
* calls and properly compute a static depth. In order to get around this,
|
||||||
* we use a static level that will cause us not to attempt to optimize
|
* we use a static depth that will cause us not to attempt to optimize
|
||||||
* variable references made by this frame.
|
* variable references made by this frame.
|
||||||
*/
|
*/
|
||||||
script = JSCompiler::compileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
|
script = js_CompileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp),
|
||||||
TCF_COMPILE_N_GO |
|
TCF_COMPILE_N_GO |
|
||||||
TCF_PUT_STATIC_LEVEL(JS_DISPLAY_SIZE),
|
TCF_PUT_STATIC_DEPTH(JS_DISPLAY_SIZE),
|
||||||
chars, length, NULL,
|
chars, length, NULL,
|
||||||
filename, lineno);
|
filename, lineno);
|
||||||
if (!script)
|
if (!script)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
|||||||
1363
js/src/jsemit.cpp
1363
js/src/jsemit.cpp
File diff suppressed because it is too large
Load Diff
228
js/src/jsemit.h
228
js/src/jsemit.h
@@ -46,7 +46,6 @@
|
|||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
#include "jsatom.h"
|
#include "jsatom.h"
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
#include "jsparse.h"
|
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
#include "jsprvtd.h"
|
#include "jsprvtd.h"
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
@@ -124,14 +123,13 @@ typedef struct JSStmtInfo JSStmtInfo;
|
|||||||
struct JSStmtInfo {
|
struct JSStmtInfo {
|
||||||
uint16 type; /* statement type */
|
uint16 type; /* statement type */
|
||||||
uint16 flags; /* flags, see below */
|
uint16 flags; /* flags, see below */
|
||||||
uint32 blockid; /* for simplified dominance computation */
|
|
||||||
ptrdiff_t update; /* loop update offset (top if none) */
|
ptrdiff_t update; /* loop update offset (top if none) */
|
||||||
ptrdiff_t breaks; /* offset of last break in loop */
|
ptrdiff_t breaks; /* offset of last break in loop */
|
||||||
ptrdiff_t continues; /* offset of last continue in loop */
|
ptrdiff_t continues; /* offset of last continue in loop */
|
||||||
union {
|
union {
|
||||||
JSAtom *label; /* name of LABEL */
|
JSAtom *label; /* name of LABEL */
|
||||||
JSObject *blockObj; /* block scope object */
|
JSObject *blockObj; /* block scope object */
|
||||||
};
|
} u;
|
||||||
JSStmtInfo *down; /* info for enclosing statement */
|
JSStmtInfo *down; /* info for enclosing statement */
|
||||||
JSStmtInfo *downScope; /* next enclosing lexical scope */
|
JSStmtInfo *downScope; /* next enclosing lexical scope */
|
||||||
};
|
};
|
||||||
@@ -152,132 +150,101 @@ struct JSStmtInfo {
|
|||||||
#define GOSUBS(stmt) ((stmt).breaks)
|
#define GOSUBS(stmt) ((stmt).breaks)
|
||||||
#define GUARDJUMP(stmt) ((stmt).continues)
|
#define GUARDJUMP(stmt) ((stmt).continues)
|
||||||
|
|
||||||
|
#define AT_TOP_LEVEL(tc) \
|
||||||
|
(!(tc)->topStmt || ((tc)->topStmt->flags & SIF_BODY_BLOCK))
|
||||||
|
|
||||||
#define SET_STATEMENT_TOP(stmt, top) \
|
#define SET_STATEMENT_TOP(stmt, top) \
|
||||||
((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1))
|
((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1))
|
||||||
|
|
||||||
#ifdef JS_SCOPE_DEPTH_METER
|
|
||||||
# define JS_SCOPE_DEPTH_METERING(code) ((void) (code))
|
|
||||||
#else
|
|
||||||
# define JS_SCOPE_DEPTH_METERING(code) ((void) 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct JSTreeContext { /* tree context for semantic checks */
|
struct JSTreeContext { /* tree context for semantic checks */
|
||||||
uint16 flags; /* statement state flags, see below */
|
uint16 flags; /* statement state flags, see below */
|
||||||
uint16 ngvars; /* max. no. of global variables/regexps */
|
uint16 ngvars; /* max. no. of global variables/regexps */
|
||||||
uint32 bodyid; /* block number of program/function body */
|
|
||||||
uint32 blockidGen; /* preincremented block number generator */
|
|
||||||
JSStmtInfo *topStmt; /* top of statement info stack */
|
JSStmtInfo *topStmt; /* top of statement info stack */
|
||||||
JSStmtInfo *topScopeStmt; /* top lexical scope statement */
|
JSStmtInfo *topScopeStmt; /* top lexical scope statement */
|
||||||
JSObject *blockChain; /* compile time block scope chain (NB: one
|
JSObject *blockChain; /* compile time block scope chain (NB: one
|
||||||
deeper than the topScopeStmt/downScope
|
deeper than the topScopeStmt/downScope
|
||||||
chain when in head of let block/expr) */
|
chain when in head of let block/expr) */
|
||||||
JSParseNode *blockNode; /* parse node for a block with let declarations
|
JSParseNode *blockNode; /* parse node for a lexical scope.
|
||||||
(block with its own lexical scope) */
|
XXX combine with blockChain? */
|
||||||
JSAtomList decls; /* function, const, and var declarations */
|
JSAtomList decls; /* function, const, and var declarations */
|
||||||
JSCompiler *compiler; /* ptr to common parsing and lexing data */
|
JSParseContext *parseContext;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
|
||||||
JSFunction *fun; /* function to store argument and variable
|
JSFunction *fun; /* function to store argument and variable
|
||||||
names when flags & TCF_IN_FUNCTION */
|
names when flags & TCF_IN_FUNCTION */
|
||||||
JSObject *scopeChain; /* scope chain object for the script */
|
JSObject *scopeChain; /* scope chain object for the script */
|
||||||
};
|
} u;
|
||||||
|
|
||||||
JSAtomList lexdeps; /* unresolved lexical name dependencies */
|
|
||||||
JSAtomList upvars; /* resolved lexical name dependencies */
|
|
||||||
JSTreeContext *parent; /* enclosing function or global context */
|
|
||||||
uintN staticLevel; /* static compilation unit nesting level */
|
|
||||||
|
|
||||||
JSFunctionBox *funbox; /* null or box for function we're compiling
|
|
||||||
if (flags & TCF_IN_FUNCTION) and not in
|
|
||||||
JSCompiler::compileFunctionBody */
|
|
||||||
JSFunctionBox *functionList;
|
|
||||||
|
|
||||||
#ifdef JS_SCOPE_DEPTH_METER
|
#ifdef JS_SCOPE_DEPTH_METER
|
||||||
uint16 scopeDepth; /* current lexical scope chain depth */
|
uint16 scopeDepth; /* current lexical scope chain depth */
|
||||||
uint16 maxScopeDepth; /* maximum lexical scope chain depth */
|
uint16 maxScopeDepth; /* maximum lexical scope chain depth */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JSTreeContext(JSCompiler *jsc)
|
|
||||||
: flags(0), ngvars(0), bodyid(0), blockidGen(0),
|
|
||||||
topStmt(NULL), topScopeStmt(NULL), blockChain(NULL), blockNode(NULL),
|
|
||||||
compiler(jsc), scopeChain(NULL), parent(NULL), staticLevel(0),
|
|
||||||
funbox(NULL), functionList(NULL)
|
|
||||||
{
|
|
||||||
JS_SCOPE_DEPTH_METERING(scopeDepth = maxScopeDepth = 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For functions the tree context is constructed and destructed a second
|
|
||||||
* time during code generation. To avoid a redundant stats update in such
|
|
||||||
* cases, we store (uintN) -1 in maxScopeDepth.
|
|
||||||
*/
|
|
||||||
~JSTreeContext() {
|
|
||||||
JS_SCOPE_DEPTH_METERING(maxScopeDepth == (uintN) -1 ||
|
|
||||||
JS_BASIC_STATS_ACCUM(&compiler
|
|
||||||
->context
|
|
||||||
->runtime
|
|
||||||
->lexicalScopeDepthStats,
|
|
||||||
maxScopeDepth));
|
|
||||||
}
|
|
||||||
|
|
||||||
uintN blockid() { return topStmt ? topStmt->blockid : bodyid; }
|
|
||||||
|
|
||||||
bool atTopLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
|
|
||||||
|
|
||||||
/* Test whether we're in a statement of given type. */
|
|
||||||
bool inStatement(JSStmtType type);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TCF_IN_FUNCTION 0x01 /* parsing inside function body */
|
||||||
|
#define TCF_RETURN_EXPR 0x02 /* function has 'return expr;' */
|
||||||
|
#define TCF_RETURN_VOID 0x04 /* function has 'return;' */
|
||||||
|
#define TCF_IN_FOR_INIT 0x08 /* parsing init expr of for; exclude 'in' */
|
||||||
|
#define TCF_NO_SCRIPT_RVAL 0x10 /* API caller does not want result value
|
||||||
|
from global script */
|
||||||
|
#define TCF_FUN_USES_NONLOCALS 0x20 /* function refers to non-local names */
|
||||||
|
#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */
|
||||||
|
#define TCF_FUN_IS_GENERATOR 0x80 /* parsed yield statement in function */
|
||||||
|
#define TCF_HAS_FUNCTION_STMT 0x100 /* block contains a function statement */
|
||||||
|
#define TCF_GENEXP_LAMBDA 0x200 /* flag lambda from generator expression */
|
||||||
|
#define TCF_COMPILE_N_GO 0x400 /* compiler-and-go mode of script, can
|
||||||
|
optimize name references based on scope
|
||||||
|
chain */
|
||||||
|
#define TCF_HAS_SHARPS 0x800 /* source contains sharp defs or uses */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags to propagate out of the blocks.
|
* Flags to propagate out of the blocks.
|
||||||
*/
|
*/
|
||||||
#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID)
|
#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID)
|
||||||
|
|
||||||
/*
|
|
||||||
* TreeContext flags must fit in 16 bits, and all bits are in use now. Widening
|
|
||||||
* requires changing JSFunctionBox.tcflags too and repacking. Alternative fix
|
|
||||||
* gets rid of flags, probably starting with TCF_HAS_FUNCTION_STMT.
|
|
||||||
*/
|
|
||||||
#define TCF_COMPILING 0x01 /* JSTreeContext is JSCodeGenerator */
|
|
||||||
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
|
|
||||||
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
|
|
||||||
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
|
|
||||||
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
|
|
||||||
#define TCF_FUN_SETS_OUTER_NAME 0x20 /* function set outer name (lexical or free) */
|
|
||||||
#define TCF_FUN_PARAM_ARGUMENTS 0x40 /* function has parameter named arguments */
|
|
||||||
#define TCF_FUN_USES_ARGUMENTS 0x80 /* function uses arguments except as a
|
|
||||||
parameter name */
|
|
||||||
#define TCF_FUN_HEAVYWEIGHT 0x100 /* function needs Call object per call */
|
|
||||||
#define TCF_FUN_IS_GENERATOR 0x200 /* parsed yield statement in function */
|
|
||||||
#define TCF_FUN_IS_FUNARG 0x400 /* function escapes as an argument, return
|
|
||||||
value, or via the heap */
|
|
||||||
#define TCF_HAS_FUNCTION_STMT 0x800 /* block contains a function statement */
|
|
||||||
#define TCF_GENEXP_LAMBDA 0x1000 /* flag lambda from generator expression */
|
|
||||||
#define TCF_COMPILE_N_GO 0x2000 /* compiler-and-go mode of script, can
|
|
||||||
optimize name references based on scope
|
|
||||||
chain */
|
|
||||||
#define TCF_NO_SCRIPT_RVAL 0x4000 /* API caller does not want result value
|
|
||||||
from global script */
|
|
||||||
#define TCF_HAS_SHARPS 0x8000 /* source contains sharp defs or uses */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags to propagate from FunctionBody.
|
* Flags to propagate from FunctionBody.
|
||||||
*/
|
*/
|
||||||
#define TCF_FUN_FLAGS (TCF_FUN_SETS_OUTER_NAME | \
|
#define TCF_FUN_FLAGS (TCF_FUN_IS_GENERATOR | \
|
||||||
TCF_FUN_USES_ARGUMENTS | \
|
TCF_FUN_HEAVYWEIGHT | \
|
||||||
TCF_FUN_PARAM_ARGUMENTS | \
|
TCF_FUN_USES_NONLOCALS | \
|
||||||
TCF_FUN_HEAVYWEIGHT | \
|
|
||||||
TCF_FUN_IS_GENERATOR | \
|
|
||||||
TCF_FUN_IS_FUNARG | \
|
|
||||||
TCF_HAS_SHARPS)
|
TCF_HAS_SHARPS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags field, not stored in JSTreeContext.flags, for passing a static level
|
* Flags field, not stored in JSTreeContext.flags, for passing staticDepth
|
||||||
* into js_CompileScript.
|
* into js_CompileScript.
|
||||||
*/
|
*/
|
||||||
#define TCF_STATIC_LEVEL_MASK 0xffff0000
|
#define TCF_STATIC_DEPTH_MASK 0xffff0000
|
||||||
#define TCF_GET_STATIC_LEVEL(f) ((uint32)(f) >> 16)
|
#define TCF_GET_STATIC_DEPTH(f) ((uint32)(f) >> 16)
|
||||||
#define TCF_PUT_STATIC_LEVEL(d) ((uint16)(d) << 16)
|
#define TCF_PUT_STATIC_DEPTH(d) ((uint16)(d) << 16)
|
||||||
|
|
||||||
|
#ifdef JS_SCOPE_DEPTH_METER
|
||||||
|
# define JS_SCOPE_DEPTH_METERING(code) ((void) (code))
|
||||||
|
#else
|
||||||
|
# define JS_SCOPE_DEPTH_METERING(code) ((void) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TREE_CONTEXT_INIT(tc, pc) \
|
||||||
|
((tc)->flags = (tc)->ngvars = 0, \
|
||||||
|
(tc)->topStmt = (tc)->topScopeStmt = NULL, \
|
||||||
|
(tc)->blockChain = NULL, \
|
||||||
|
ATOM_LIST_INIT(&(tc)->decls), \
|
||||||
|
(tc)->blockNode = NULL, \
|
||||||
|
(tc)->parseContext = (pc), \
|
||||||
|
(tc)->u.scopeChain = NULL, \
|
||||||
|
JS_SCOPE_DEPTH_METERING((tc)->scopeDepth = (tc)->maxScopeDepth = 0))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For functions TREE_CONTEXT_FINISH is called the second time to finish the
|
||||||
|
* extra tc created during code generation. We skip stats update in such
|
||||||
|
* cases.
|
||||||
|
*/
|
||||||
|
#define TREE_CONTEXT_FINISH(cx, tc) \
|
||||||
|
JS_SCOPE_DEPTH_METERING( \
|
||||||
|
(tc)->maxScopeDepth == (uintN) -1 || \
|
||||||
|
JS_BASIC_STATS_ACCUM(&(cx)->runtime->lexicalScopeDepthStats, \
|
||||||
|
(tc)->maxScopeDepth))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Span-dependent instructions are jumps whose span (from the jump bytecode to
|
* Span-dependent instructions are jumps whose span (from the jump bytecode to
|
||||||
@@ -347,18 +314,17 @@ struct JSTryNode {
|
|||||||
JSTryNode *prev;
|
JSTryNode *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JSCGObjectList {
|
typedef struct JSEmittedObjectList {
|
||||||
uint32 length; /* number of emitted so far objects */
|
uint32 length; /* number of emitted so far objects */
|
||||||
JSObjectBox *lastbox; /* last emitted object */
|
JSParsedObjectBox *lastPob; /* last emitted object */
|
||||||
|
} JSEmittedObjectList;
|
||||||
|
|
||||||
JSCGObjectList() : length(0), lastbox(NULL) {}
|
extern void
|
||||||
|
FinishParsedObjects(JSEmittedObjectList *emittedList, JSObjectArray *objectMap);
|
||||||
|
|
||||||
uintN index(JSObjectBox *objbox);
|
struct JSCodeGenerator {
|
||||||
void finish(JSObjectArray *array);
|
JSTreeContext treeContext; /* base state: statement info stack, etc. */
|
||||||
};
|
|
||||||
|
|
||||||
struct JSCodeGenerator : public JSTreeContext
|
|
||||||
{
|
|
||||||
JSArenaPool *codePool; /* pointer to thread code arena pool */
|
JSArenaPool *codePool; /* pointer to thread code arena pool */
|
||||||
JSArenaPool *notePool; /* pointer to thread srcnote arena pool */
|
JSArenaPool *notePool; /* pointer to thread srcnote arena pool */
|
||||||
void *codeMark; /* low watermark in cg->codePool */
|
void *codeMark; /* low watermark in cg->codePool */
|
||||||
@@ -397,33 +363,17 @@ struct JSCodeGenerator : public JSTreeContext
|
|||||||
uintN emitLevel; /* js_EmitTree recursion level */
|
uintN emitLevel; /* js_EmitTree recursion level */
|
||||||
JSAtomList constList; /* compile time constants */
|
JSAtomList constList; /* compile time constants */
|
||||||
|
|
||||||
JSCGObjectList objectList; /* list of emitted objects */
|
JSEmittedObjectList objectList; /* list of emitted so far objects */
|
||||||
JSCGObjectList regexpList; /* list of emitted regexp that will be
|
JSEmittedObjectList regexpList; /* list of emitted so far regexp
|
||||||
cloned during execution */
|
that will be cloned during execution */
|
||||||
|
|
||||||
|
uintN staticDepth; /* static frame chain depth */
|
||||||
JSAtomList upvarList; /* map of atoms to upvar indexes */
|
JSAtomList upvarList; /* map of atoms to upvar indexes */
|
||||||
JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */
|
JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */
|
||||||
|
JSCodeGenerator *parent; /* enclosing function or global context */
|
||||||
/*
|
|
||||||
* Initialize cg to allocate bytecode space from codePool, source note
|
|
||||||
* space from notePool, and all other arena-allocated temporaries from
|
|
||||||
* jsc->context->tempPool.
|
|
||||||
*/
|
|
||||||
JSCodeGenerator(JSCompiler *jsc,
|
|
||||||
JSArenaPool *codePool, JSArenaPool *notePool,
|
|
||||||
uintN lineno);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Release cg->codePool, cg->notePool, and compiler->context->tempPool to
|
|
||||||
* marks set by JSCodeGenerator's ctor. Note that cgs are magic: they own
|
|
||||||
* the arena pool "tops-of-stack" space above their codeMark, noteMark, and
|
|
||||||
* tempMark points. This means you cannot alloc from tempPool and save the
|
|
||||||
* pointer beyond the next JSCodeGenerator destructor call.
|
|
||||||
*/
|
|
||||||
~JSCodeGenerator();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CG_TS(cg) TS((cg)->compiler)
|
#define CG_TS(cg) TS((cg)->treeContext.parseContext)
|
||||||
|
|
||||||
#define CG_BASE(cg) ((cg)->current->base)
|
#define CG_BASE(cg) ((cg)->current->base)
|
||||||
#define CG_LIMIT(cg) ((cg)->current->limit)
|
#define CG_LIMIT(cg) ((cg)->current->limit)
|
||||||
@@ -446,6 +396,25 @@ struct JSCodeGenerator : public JSTreeContext
|
|||||||
#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main)
|
#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main)
|
||||||
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
|
#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize cg to allocate bytecode space from codePool, source note space
|
||||||
|
* from notePool, and all other arena-allocated temporaries from cx->tempPool.
|
||||||
|
*/
|
||||||
|
extern JS_FRIEND_API(void)
|
||||||
|
js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
|
||||||
|
JSArenaPool *codePool, JSArenaPool *notePool,
|
||||||
|
uintN lineno);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release cg->codePool, cg->notePool, and cx->tempPool to marks set by
|
||||||
|
* js_InitCodeGenerator. Note that cgs are magic: they own the arena pool
|
||||||
|
* "tops-of-stack" space above their codeMark, noteMark, and tempMark points.
|
||||||
|
* This means you cannot alloc from tempPool and save the pointer beyond the
|
||||||
|
* next JS_FinishCodeGenerator.
|
||||||
|
*/
|
||||||
|
extern JS_FRIEND_API(void)
|
||||||
|
js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit one bytecode.
|
* Emit one bytecode.
|
||||||
*/
|
*/
|
||||||
@@ -495,6 +464,13 @@ extern JSBool
|
|||||||
js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
|
js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
|
||||||
ptrdiff_t off);
|
ptrdiff_t off);
|
||||||
|
|
||||||
|
/* Test whether we're in a statement of given type. */
|
||||||
|
extern JSBool
|
||||||
|
js_InStatement(JSTreeContext *tc, JSStmtType type);
|
||||||
|
|
||||||
|
/* Test whether we're in a with statement. */
|
||||||
|
#define js_InWithStatement(tc) js_InStatement(tc, STMT_WITH)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Push the C-stack-allocated struct at stmt onto the stmtInfo stack.
|
* Push the C-stack-allocated struct at stmt onto the stmtInfo stack.
|
||||||
*/
|
*/
|
||||||
@@ -519,9 +495,9 @@ extern void
|
|||||||
js_PopStatement(JSTreeContext *tc);
|
js_PopStatement(JSTreeContext *tc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Like js_PopStatement(cg), also patch breaks and continues unless the top
|
* Like js_PopStatement(&cg->treeContext), also patch breaks and continues
|
||||||
* statement info record represents a try-catch-finally suite. May fail if a
|
* unless the top statement info record represents a try-catch-finally suite.
|
||||||
* jump offset overflows.
|
* May fail if a jump offset overflows.
|
||||||
*/
|
*/
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg);
|
js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg);
|
||||||
@@ -608,7 +584,7 @@ typedef enum JSSrcNoteType {
|
|||||||
SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or
|
SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or
|
||||||
to an index label in a regular (structuring)
|
to an index label in a regular (structuring)
|
||||||
or a destructuring object initialiser */
|
or a destructuring object initialiser */
|
||||||
SRC_GENEXP = 1, /* JSOP_LAMBDA from generator expression */
|
SRC_GENEXP = 1, /* JSOP_ANONFUNOBJ from generator expression */
|
||||||
SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */
|
SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */
|
||||||
SRC_FOR_IN = 2, /* JSOP_GOTO to for-in loop condition from
|
SRC_FOR_IN = 2, /* JSOP_GOTO to for-in loop condition from
|
||||||
before loop (same arity as SRC_IF_ELSE) */
|
before loop (same arity as SRC_IF_ELSE) */
|
||||||
|
|||||||
214
js/src/jsfun.cpp
214
js/src/jsfun.cpp
@@ -586,7 +586,7 @@ JSClass js_ArgumentsClass = {
|
|||||||
JS_CLASS_TRACE(args_or_call_trace), NULL
|
JS_CLASS_TRACE(args_or_call_trace), NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define JSSLOT_CALLEE (JSSLOT_PRIVATE + 1)
|
#define JSSLOT_SCRIPTED_FUNCTION (JSSLOT_PRIVATE + 1)
|
||||||
#define JSSLOT_CALL_ARGUMENTS (JSSLOT_PRIVATE + 2)
|
#define JSSLOT_CALL_ARGUMENTS (JSSLOT_PRIVATE + 2)
|
||||||
#define CALL_CLASS_FIXED_RESERVED_SLOTS 2
|
#define CALL_CLASS_FIXED_RESERVED_SLOTS 2
|
||||||
|
|
||||||
@@ -617,8 +617,8 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JS_SetPrivate(cx, callobj, fp);
|
JS_SetPrivate(cx, callobj, fp);
|
||||||
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->callee));
|
STOBJ_SET_SLOT(callobj, JSSLOT_SCRIPTED_FUNCTION,
|
||||||
STOBJ_SET_SLOT(callobj, JSSLOT_CALLEE, OBJECT_TO_JSVAL(fp->callee));
|
OBJECT_TO_JSVAL(FUN_OBJECT(fp->fun)));
|
||||||
fp->callobj = callobj;
|
fp->callobj = callobj;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -630,19 +630,19 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
|||||||
return callobj;
|
return callobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSFunction *
|
JSFunction *
|
||||||
GetCallObjectFunction(JSObject *obj)
|
js_GetCallObjectFunction(JSObject *obj)
|
||||||
{
|
{
|
||||||
jsval v;
|
jsval v;
|
||||||
|
|
||||||
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
|
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
|
||||||
v = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE);
|
v = STOBJ_GET_SLOT(obj, JSSLOT_SCRIPTED_FUNCTION);
|
||||||
if (JSVAL_IS_VOID(v)) {
|
if (JSVAL_IS_VOID(v)) {
|
||||||
/* Newborn or prototype object. */
|
/* Newborn or prototype object. */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
|
JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
|
||||||
return GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v));
|
return (JSFunction *) JSVAL_TO_OBJECT(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(JSBool)
|
JS_FRIEND_API(JSBool)
|
||||||
@@ -678,7 +678,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun = fp->fun;
|
fun = fp->fun;
|
||||||
JS_ASSERT(fun == GetCallObjectFunction(callobj));
|
JS_ASSERT(fun == js_GetCallObjectFunction(callobj));
|
||||||
n = JS_GET_LOCAL_NAME_COUNT(fun);
|
n = JS_GET_LOCAL_NAME_COUNT(fun);
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
JS_LOCK_OBJ(cx, callobj);
|
JS_LOCK_OBJ(cx, callobj);
|
||||||
@@ -718,7 +718,7 @@ call_enumerate(JSContext *cx, JSObject *obj)
|
|||||||
JSObject *pobj;
|
JSObject *pobj;
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
|
|
||||||
fun = GetCallObjectFunction(obj);
|
fun = js_GetCallObjectFunction(obj);
|
||||||
n = fun ? JS_GET_LOCAL_NAME_COUNT(fun) : 0;
|
n = fun ? JS_GET_LOCAL_NAME_COUNT(fun) : 0;
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
@@ -778,7 +778,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
|
|||||||
if (STOBJ_GET_CLASS(obj) != &js_CallClass)
|
if (STOBJ_GET_CLASS(obj) != &js_CallClass)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
fun = GetCallObjectFunction(obj);
|
fun = js_GetCallObjectFunction(obj);
|
||||||
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
|
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
|
||||||
|
|
||||||
if (kind == JSCPK_ARGUMENTS) {
|
if (kind == JSCPK_ARGUMENTS) {
|
||||||
@@ -868,39 +868,28 @@ SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||||||
return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_TRUE);
|
return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSClass js_DeclEnvClass = {
|
|
||||||
js_Object_str,
|
|
||||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
|
||||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
|
|
||||||
JSCLASS_NO_OPTIONAL_MEMBERS
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
|
call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
|
||||||
JSObject **objp)
|
JSObject **objp)
|
||||||
{
|
{
|
||||||
jsval callee;
|
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
jsid id;
|
jsid id;
|
||||||
JSLocalKind localKind;
|
JSLocalKind localKind;
|
||||||
JSPropertyOp getter, setter;
|
JSPropertyOp getter, setter;
|
||||||
uintN slot, attrs;
|
uintN slot, attrs;
|
||||||
|
|
||||||
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
|
|
||||||
if (!JSVAL_IS_STRING(idval))
|
if (!JSVAL_IS_STRING(idval))
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
callee = STOBJ_GET_SLOT(obj, JSSLOT_CALLEE);
|
fun = js_GetCallObjectFunction(obj);
|
||||||
if (JSVAL_IS_VOID(callee))
|
if (!fun)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
|
|
||||||
|
|
||||||
if (!js_ValueToStringId(cx, idval, &id))
|
if (!js_ValueToStringId(cx, idval, &id))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);
|
localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);
|
||||||
if (localKind != JSLOCAL_NONE && localKind != JSLOCAL_UPVAR) {
|
if (localKind != JSLOCAL_NONE) {
|
||||||
JS_ASSERT((uint16) slot == slot);
|
JS_ASSERT((uint16) slot == slot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -943,32 +932,6 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
|
|||||||
*objp = obj;
|
*objp = obj;
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If fun is a named function expression and id matches its name, resolve
|
|
||||||
* this call object's saved callee function object under that name in obj's
|
|
||||||
* parent declarative environment object.
|
|
||||||
*/
|
|
||||||
if ((fun->flags & JSFUN_LAMBDA) && JSID_TO_ATOM(id) == fun->atom) {
|
|
||||||
JSObject *parent = STOBJ_GET_PARENT(obj);
|
|
||||||
|
|
||||||
if (STOBJ_GET_CLASS(parent) != &js_DeclEnvClass) {
|
|
||||||
parent = js_NewObjectWithGivenProto(cx, &js_DeclEnvClass, NULL, parent, 0);
|
|
||||||
if (!parent)
|
|
||||||
return JS_FALSE;
|
|
||||||
STOBJ_SET_PARENT(obj, parent);
|
|
||||||
|
|
||||||
attrs = JSPROP_PERMANENT | JSPROP_READONLY;
|
|
||||||
if (!js_DefineNativeProperty(cx, parent, id, callee, NULL, NULL, attrs, 0, 0, NULL))
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not resolve, let normal scope chain search find the name. */
|
|
||||||
JS_ASSERT(!*objp);
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Control flow reaches here only if id was not resolved. */
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -992,7 +955,7 @@ call_reserveSlots(JSContext *cx, JSObject *obj)
|
|||||||
{
|
{
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
|
|
||||||
fun = GetCallObjectFunction(obj);
|
fun = js_GetCallObjectFunction(obj);
|
||||||
return JS_GET_LOCAL_NAME_COUNT(fun);
|
return JS_GET_LOCAL_NAME_COUNT(fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1179,6 +1142,15 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* No need to reflect fun.prototype in 'fun.prototype = ... '.
|
* No need to reflect fun.prototype in 'fun.prototype = ... '.
|
||||||
|
*
|
||||||
|
* This is not just an optimization, because we must not resolve when
|
||||||
|
* defining hidden properties during compilation. The setup code for the
|
||||||
|
* prototype and the lazy properties below eventually calls the property
|
||||||
|
* hooks for the function object. That in turn calls fun_reserveSlots to
|
||||||
|
* get the number of the reserved slots which is just the number of
|
||||||
|
* regular expressions literals in the function. When compiling, that
|
||||||
|
* number is not yet ready so we must make sure that fun_resolve does
|
||||||
|
* nothing until the code for the function is generated.
|
||||||
*/
|
*/
|
||||||
if (flags & JSRESOLVE_ASSIGNING)
|
if (flags & JSRESOLVE_ASSIGNING)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
@@ -1264,9 +1236,9 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||||||
JSContext *cx;
|
JSContext *cx;
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
uint32 nullAtom; /* flag to indicate if fun->atom is NULL */
|
uint32 nullAtom; /* flag to indicate if fun->atom is NULL */
|
||||||
uintN nargs, nvars, nupvars, n;
|
uintN nargs, nvars, n;
|
||||||
uint32 localsword; /* word to xdr argument and variable counts */
|
uint32 localsword; /* word to xdr argument and variable counts */
|
||||||
uint32 flagsword; /* word to xdr upvars count and fun->flags */
|
uint32 flagsword; /* originally only flags was JS_XDRUint8'd */
|
||||||
JSTempValueRooter tvr;
|
JSTempValueRooter tvr;
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
|
|
||||||
@@ -1282,9 +1254,8 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||||||
nullAtom = !fun->atom;
|
nullAtom = !fun->atom;
|
||||||
nargs = fun->nargs;
|
nargs = fun->nargs;
|
||||||
nvars = fun->u.i.nvars;
|
nvars = fun->u.i.nvars;
|
||||||
nupvars = fun->u.i.nupvars;
|
|
||||||
localsword = (nargs << 16) | nvars;
|
localsword = (nargs << 16) | nvars;
|
||||||
flagsword = (nupvars << 16) | fun->flags;
|
flagsword = fun->flags;
|
||||||
} else {
|
} else {
|
||||||
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
|
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
|
||||||
if (!fun)
|
if (!fun)
|
||||||
@@ -1292,12 +1263,11 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||||||
STOBJ_CLEAR_PARENT(FUN_OBJECT(fun));
|
STOBJ_CLEAR_PARENT(FUN_OBJECT(fun));
|
||||||
STOBJ_CLEAR_PROTO(FUN_OBJECT(fun));
|
STOBJ_CLEAR_PROTO(FUN_OBJECT(fun));
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
nvars = nargs = nupvars = 0; /* quell GCC uninitialized warning */
|
nvars = nargs = 0; /* quell GCC uninitialized warning */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* From here on, control flow must flow through label out. */
|
/* From here on, control flow must flow through label out. */
|
||||||
MUST_FLOW_THROUGH("out");
|
|
||||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
|
JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
|
||||||
ok = JS_TRUE;
|
ok = JS_TRUE;
|
||||||
|
|
||||||
@@ -1312,14 +1282,13 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||||||
|
|
||||||
if (xdr->mode == JSXDR_DECODE) {
|
if (xdr->mode == JSXDR_DECODE) {
|
||||||
nargs = localsword >> 16;
|
nargs = localsword >> 16;
|
||||||
nvars = uint16(localsword);
|
nvars = localsword & JS_BITMASK(16);
|
||||||
JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
|
JS_ASSERT(flagsword | JSFUN_INTERPRETED);
|
||||||
nupvars = flagsword >> 16;
|
fun->flags = (uint16) flagsword;
|
||||||
fun->flags = uint16(flagsword);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do arguments and local vars */
|
/* do arguments and local vars */
|
||||||
n = nargs + nvars + nupvars;
|
n = nargs + nvars;
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
void *mark;
|
void *mark;
|
||||||
uintN i;
|
uintN i;
|
||||||
@@ -1341,7 +1310,6 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||||||
* names (indexes starting from nargs) bitmap's bit is set when the
|
* names (indexes starting from nargs) bitmap's bit is set when the
|
||||||
* name is declared as const, not as ordinary var.
|
* name is declared as const, not as ordinary var.
|
||||||
* */
|
* */
|
||||||
MUST_FLOW_THROUGH("release_mark");
|
|
||||||
bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
|
bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
|
||||||
JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
|
JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
|
||||||
bitmapLength * sizeof *bitmap);
|
bitmapLength * sizeof *bitmap);
|
||||||
@@ -1397,12 +1365,10 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||||||
if (xdr->mode == JSXDR_DECODE) {
|
if (xdr->mode == JSXDR_DECODE) {
|
||||||
localKind = (i < nargs)
|
localKind = (i < nargs)
|
||||||
? JSLOCAL_ARG
|
? JSLOCAL_ARG
|
||||||
: (i < nargs + nvars)
|
: bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
|
||||||
? (bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
|
JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
|
||||||
JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
|
? JSLOCAL_CONST
|
||||||
? JSLOCAL_CONST
|
: JSLOCAL_VAR;
|
||||||
: JSLOCAL_VAR)
|
|
||||||
: JSLOCAL_UPVAR;
|
|
||||||
ok = js_AddLocal(xdr->cx, fun, name, localKind);
|
ok = js_AddLocal(xdr->cx, fun, name, localKind);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto release_mark;
|
goto release_mark;
|
||||||
@@ -1540,7 +1506,7 @@ fun_reserveSlots(JSContext *cx, JSObject *obj)
|
|||||||
fun = (JSFunction *) JS_GetPrivate(cx, obj);
|
fun = (JSFunction *) JS_GetPrivate(cx, obj);
|
||||||
nslots = 0;
|
nslots = 0;
|
||||||
if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) {
|
if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) {
|
||||||
if (fun->u.i.nupvars != 0)
|
if (fun->u.i.script->upvarsOffset != 0)
|
||||||
nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length;
|
nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length;
|
||||||
if (fun->u.i.script->regexpsOffset != 0)
|
if (fun->u.i.script->regexpsOffset != 0)
|
||||||
nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length;
|
nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length;
|
||||||
@@ -2067,9 +2033,9 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
str = cx->runtime->emptyString;
|
str = cx->runtime->emptyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSCompiler::compileFunctionBody(cx, fun, principals,
|
return js_CompileFunctionBody(cx, fun, principals,
|
||||||
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||||
filename, lineno);
|
filename, lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
@@ -2137,8 +2103,8 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
|
|||||||
|
|
||||||
/* Initialize all function members. */
|
/* Initialize all function members. */
|
||||||
fun->nargs = nargs;
|
fun->nargs = nargs;
|
||||||
fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRACEABLE);
|
fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED | JSFUN_TRACEABLE);
|
||||||
if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
|
if (flags & JSFUN_INTERPRETED) {
|
||||||
JS_ASSERT(!native);
|
JS_ASSERT(!native);
|
||||||
JS_ASSERT(nargs == 0);
|
JS_ASSERT(nargs == 0);
|
||||||
fun->u.i.nvars = 0;
|
fun->u.i.nvars = 0;
|
||||||
@@ -2175,82 +2141,31 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
|
|||||||
JSObject *
|
JSObject *
|
||||||
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
|
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
|
||||||
{
|
{
|
||||||
|
JSObject *clone;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The cloned function object does not need the extra JSFunction members
|
* The cloned function object does not need the extra fields beyond
|
||||||
* beyond JSObject as it points to fun via the private slot.
|
* JSObject as it points to fun via the private slot.
|
||||||
*/
|
*/
|
||||||
JSObject *clone = js_NewObject(cx, &js_FunctionClass, NULL, parent,
|
clone = js_NewObject(cx, &js_FunctionClass, NULL, parent,
|
||||||
sizeof(JSObject));
|
sizeof(JSObject));
|
||||||
if (!clone)
|
if (!clone)
|
||||||
return NULL;
|
return NULL;
|
||||||
clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
|
clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
|
||||||
js_NewFlatClosure(JSContext *cx, JSFunction *fun)
|
|
||||||
{
|
|
||||||
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
|
|
||||||
|
|
||||||
JSObject *closure = js_CloneFunctionObject(cx, fun, cx->fp->scopeChain);
|
|
||||||
if (!closure || fun->u.i.script->upvarsOffset == 0)
|
|
||||||
return closure;
|
|
||||||
|
|
||||||
uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
|
|
||||||
JS_ASSERT(nslots == JS_INITIAL_NSLOTS);
|
|
||||||
nslots += fun_reserveSlots(cx, closure);
|
|
||||||
if (!js_ReallocSlots(cx, closure, nslots, JS_TRUE))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
|
|
||||||
JS_ASSERT(uva->length <= size_t(closure->dslots[-1]));
|
|
||||||
|
|
||||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
|
||||||
|
|
||||||
for (uint32 i = 0, n = uva->length; i < n; i++) {
|
|
||||||
JSStackFrame *fp2 = fp;
|
|
||||||
for (uintN skip = UPVAR_FRAME_SKIP(uva->vector[i]); skip != 0; --skip)
|
|
||||||
fp2 = fp2->down;
|
|
||||||
|
|
||||||
uintN slot = UPVAR_FRAME_SLOT(uva->vector[i]);
|
|
||||||
jsval *vp;
|
|
||||||
if (fp2->fun && slot < fp2->fun->nargs) {
|
|
||||||
vp = fp2->argv;
|
|
||||||
} else {
|
|
||||||
if (fp2->fun)
|
|
||||||
slot -= fp2->fun->nargs;
|
|
||||||
JS_ASSERT(slot < fp2->script->nslots);
|
|
||||||
vp = fp2->slots;
|
|
||||||
}
|
|
||||||
|
|
||||||
closure->dslots[i] = vp[slot];
|
|
||||||
}
|
|
||||||
|
|
||||||
return closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSFunction *
|
JSFunction *
|
||||||
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
|
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
|
||||||
uintN nargs, uintN attrs)
|
uintN nargs, uintN attrs)
|
||||||
{
|
{
|
||||||
JSPropertyOp gsop;
|
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
|
JSPropertyOp gsop;
|
||||||
|
|
||||||
if (attrs & JSFUN_STUB_GSOPS) {
|
|
||||||
/*
|
|
||||||
* JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
|
|
||||||
* the defined property's attributes. This allows us to encode another,
|
|
||||||
* internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
|
|
||||||
* for more on this.
|
|
||||||
*/
|
|
||||||
attrs &= ~JSFUN_STUB_GSOPS;
|
|
||||||
gsop = JS_PropertyStub;
|
|
||||||
} else {
|
|
||||||
gsop = NULL;
|
|
||||||
}
|
|
||||||
fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
|
fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
|
||||||
if (!fun)
|
if (!fun)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
gsop = (attrs & JSFUN_STUB_GSOPS) ? JS_PropertyStub : NULL;
|
||||||
if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
|
if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
|
||||||
OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
|
OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
|
||||||
gsop, gsop,
|
gsop, gsop,
|
||||||
@@ -2539,18 +2454,11 @@ js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind)
|
|||||||
map->lastdup = NULL;
|
map->lastdup = NULL;
|
||||||
for (i = 0; i != MAX_ARRAY_LOCALS; ++i) {
|
for (i = 0; i != MAX_ARRAY_LOCALS; ++i) {
|
||||||
taggedAtom = array[i];
|
taggedAtom = array[i];
|
||||||
uintN j = i;
|
if (!HashLocalName(cx, map, (JSAtom *) (taggedAtom & ~1),
|
||||||
JSLocalKind k = JSLOCAL_ARG;
|
(i < fun->nargs)
|
||||||
if (j >= fun->nargs) {
|
? JSLOCAL_ARG
|
||||||
j -= fun->nargs;
|
: (taggedAtom & 1) ? JSLOCAL_CONST : JSLOCAL_VAR,
|
||||||
if (j < fun->u.i.nvars) {
|
(i < fun->nargs) ? i : i - fun->nargs)) {
|
||||||
k = (taggedAtom & 1) ? JSLOCAL_CONST : JSLOCAL_VAR;
|
|
||||||
} else {
|
|
||||||
j -= fun->u.i.nvars;
|
|
||||||
k = JSLOCAL_UPVAR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!HashLocalName(cx, map, (JSAtom *) (taggedAtom & ~1), k, j)) {
|
|
||||||
FreeLocalNameHash(cx, map);
|
FreeLocalNameHash(cx, map);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
@@ -2662,14 +2570,10 @@ get_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
|
|||||||
constFlag = 0;
|
constFlag = 0;
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(entry->localKind == JSLOCAL_VAR ||
|
JS_ASSERT(entry->localKind == JSLOCAL_VAR ||
|
||||||
entry->localKind == JSLOCAL_CONST ||
|
entry->localKind == JSLOCAL_CONST);
|
||||||
entry->localKind == JSLOCAL_UPVAR);
|
JS_ASSERT(entry->index < args->fun->u.i.nvars);
|
||||||
JS_ASSERT(entry->index < args->fun->u.i.nvars + args->fun->u.i.nupvars);
|
JS_ASSERT(args->nCopiedVars++ < args->fun->u.i.nvars);
|
||||||
JS_ASSERT(args->nCopiedVars++ < args->fun->u.i.nvars + args->fun->u.i.nupvars);
|
i = args->fun->nargs + entry->index;
|
||||||
i = args->fun->nargs;
|
|
||||||
if (entry->localKind == JSLOCAL_UPVAR)
|
|
||||||
i += args->fun->u.i.nvars;
|
|
||||||
i += entry->index;
|
|
||||||
constFlag = (entry->localKind == JSLOCAL_CONST);
|
constFlag = (entry->localKind == JSLOCAL_CONST);
|
||||||
}
|
}
|
||||||
args->names[i] = (jsuword) entry->name | constFlag;
|
args->names[i] = (jsuword) entry->name | constFlag;
|
||||||
@@ -2722,7 +2626,7 @@ js_GetLocalNameArray(JSContext *cx, JSFunction *fun, JSArenaPool *pool)
|
|||||||
#if !JS_HAS_DESTRUCTURING
|
#if !JS_HAS_DESTRUCTURING
|
||||||
JS_ASSERT(args.nCopiedArgs == fun->nargs);
|
JS_ASSERT(args.nCopiedArgs == fun->nargs);
|
||||||
#endif
|
#endif
|
||||||
JS_ASSERT(args.nCopiedVars == fun->u.i.nvars + fun->u.i.nupvars);
|
JS_ASSERT(args.nCopiedVars == fun->u.i.nvars);
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,57 +89,17 @@ struct JSFunction {
|
|||||||
JSAtom *atom; /* name for diagnostics and decompiling */
|
JSAtom *atom; /* name for diagnostics and decompiling */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
#define JSFUN_TRACEABLE 0x2000 /* can trace across calls to this native
|
||||||
* The high two bits of fun->flags encode whether the function is native or
|
|
||||||
* interpreted, and if interpreted, what kind of optimized closure form (if
|
|
||||||
* any) it might be.
|
|
||||||
*
|
|
||||||
* 00 not interpreted
|
|
||||||
* 01 interpreted, neither flat nor null closure
|
|
||||||
* 10 interpreted, flat closure
|
|
||||||
* 11 interpreted, null closure
|
|
||||||
*
|
|
||||||
* FUN_FLAT_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset != 0.
|
|
||||||
* FUN_NULL_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset == 0.
|
|
||||||
*
|
|
||||||
* FUN_INTERPRETED but not FUN_FLAT_CLOSURE and u.i.script->upvarsOffset != 0
|
|
||||||
* is an Algol-like function expression or nested function, i.e., a function
|
|
||||||
* that never escapes upward or downward (heapward), and is only ever called.
|
|
||||||
*
|
|
||||||
* Finally, FUN_INTERPRETED and u.i.script->upvarsOffset == 0 could be either
|
|
||||||
* a non-closure (a global function definition, or any function that uses no
|
|
||||||
* outer names), or a closure of an escaping function that uses outer names
|
|
||||||
* whose values can't be snapshot (because the outer names could be reassigned
|
|
||||||
* after the closure is formed, or because assignments could not be analyzed
|
|
||||||
* due to with or eval).
|
|
||||||
*
|
|
||||||
* Such a hard-case function must use JSOP_NAME, etc., and reify outer function
|
|
||||||
* activations' call objects, etc. if it's not a global function.
|
|
||||||
*
|
|
||||||
* NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag
|
|
||||||
* bit only, never stored in fun->flags.
|
|
||||||
*
|
|
||||||
* If we need more bits in the future, all flags for FUN_INTERPRETED functions
|
|
||||||
* can move to u.i.script->flags. For now we use function flag bits to minimize
|
|
||||||
* pointer-chasing.
|
|
||||||
*/
|
|
||||||
#define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
|
|
||||||
#define JSFUN_TRACEABLE 0x2000 /* can trace across calls to this native
|
|
||||||
function; use FUN_TRCINFO if set,
|
function; use FUN_TRCINFO if set,
|
||||||
FUN_CLASP if unset */
|
FUN_CLASP if unset */
|
||||||
#define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */
|
#define JSFUN_EXPR_CLOSURE 0x4000 /* expression closure: function(x)x*x */
|
||||||
#define JSFUN_FLAT_CLOSURE 0x8000 /* flag (aka "display") closure */
|
#define JSFUN_INTERPRETED 0x8000 /* use u.i if set, u.n if unset */
|
||||||
#define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */
|
|
||||||
#define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
|
#define JSFUN_SCRIPT_OR_FAST_NATIVE (JSFUN_INTERPRETED | JSFUN_FAST_NATIVE)
|
||||||
optimization level -- see above */
|
|
||||||
|
|
||||||
#define FUN_OBJECT(fun) (&(fun)->object)
|
#define FUN_OBJECT(fun) (&(fun)->object)
|
||||||
#define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK)
|
#define FUN_INTERPRETED(fun) ((fun)->flags & JSFUN_INTERPRETED)
|
||||||
#define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k))
|
#define FUN_SLOW_NATIVE(fun) (!((fun)->flags & JSFUN_SCRIPT_OR_FAST_NATIVE))
|
||||||
#define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED)
|
|
||||||
#define FUN_FLAT_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_FLAT_CLOSURE)
|
|
||||||
#define FUN_NULL_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_NULL_CLOSURE)
|
|
||||||
#define FUN_SLOW_NATIVE(fun) (!FUN_INTERPRETED(fun) && !((fun)->flags & JSFUN_FAST_NATIVE))
|
|
||||||
#define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL)
|
#define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL)
|
||||||
#define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL)
|
#define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL)
|
||||||
#define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \
|
#define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \
|
||||||
@@ -209,11 +169,11 @@ js_TraceFunction(JSTracer *trc, JSFunction *fun);
|
|||||||
extern void
|
extern void
|
||||||
js_FinalizeFunction(JSContext *cx, JSFunction *fun);
|
js_FinalizeFunction(JSContext *cx, JSFunction *fun);
|
||||||
|
|
||||||
extern JS_REQUIRES_STACK JSObject *
|
extern JSObject *
|
||||||
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent);
|
js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent);
|
||||||
|
|
||||||
extern JS_REQUIRES_STACK JSObject *
|
extern JSBool
|
||||||
js_NewFlatClosure(JSContext *cx, JSFunction *fun);
|
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *object);
|
||||||
|
|
||||||
extern JSFunction *
|
extern JSFunction *
|
||||||
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
|
js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
|
||||||
|
|||||||
@@ -3092,8 +3092,8 @@ js_TraceContext(JSTracer *trc, JSContext *acx)
|
|||||||
case JSTVU_WEAK_ROOTS:
|
case JSTVU_WEAK_ROOTS:
|
||||||
TraceWeakRoots(trc, tvr->u.weakRoots);
|
TraceWeakRoots(trc, tvr->u.weakRoots);
|
||||||
break;
|
break;
|
||||||
case JSTVU_COMPILER:
|
case JSTVU_PARSE_CONTEXT:
|
||||||
tvr->u.compiler->trace(trc);
|
js_TraceParseContext(trc, tvr->u.parseContext);
|
||||||
break;
|
break;
|
||||||
case JSTVU_SCRIPT:
|
case JSTVU_SCRIPT:
|
||||||
js_TraceScript(trc, tvr->u.script);
|
js_TraceScript(trc, tvr->u.script);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ DefaultAllocTable(void *pool, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DefaultFreeTable(void *pool, void *item, size_t size)
|
DefaultFreeTable(void *pool, void *item)
|
||||||
{
|
{
|
||||||
free(item);
|
free(item);
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ JS_NewHashTable(uint32 n, JSHashFunction keyHash,
|
|||||||
nb = n * sizeof(JSHashEntry *);
|
nb = n * sizeof(JSHashEntry *);
|
||||||
ht->buckets = (JSHashEntry**) allocOps->allocTable(allocPriv, nb);
|
ht->buckets = (JSHashEntry**) allocOps->allocTable(allocPriv, nb);
|
||||||
if (!ht->buckets) {
|
if (!ht->buckets) {
|
||||||
allocOps->freeTable(allocPriv, ht, nb);
|
allocOps->freeTable(allocPriv, ht);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(ht->buckets, 0, nb);
|
memset(ht->buckets, 0, nb);
|
||||||
@@ -153,11 +153,11 @@ JS_HashTableDestroy(JSHashTable *ht)
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
|
memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
|
||||||
#endif
|
#endif
|
||||||
allocOps->freeTable(allocPriv, ht->buckets, n * sizeof ht->buckets[0]);
|
allocOps->freeTable(allocPriv, ht->buckets);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
memset(ht, 0xDB, sizeof *ht);
|
memset(ht, 0xDB, sizeof *ht);
|
||||||
#endif
|
#endif
|
||||||
allocOps->freeTable(allocPriv, ht, sizeof *ht);
|
allocOps->freeTable(allocPriv, ht);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -198,7 +198,9 @@ Resize(JSHashTable *ht, uint32 newshift)
|
|||||||
{
|
{
|
||||||
size_t nb, nentries, i;
|
size_t nb, nentries, i;
|
||||||
JSHashEntry **oldbuckets, *he, *next, **hep;
|
JSHashEntry **oldbuckets, *he, *next, **hep;
|
||||||
|
#ifdef DEBUG
|
||||||
size_t nold = NBUCKETS(ht);
|
size_t nold = NBUCKETS(ht);
|
||||||
|
#endif
|
||||||
|
|
||||||
JS_ASSERT(newshift < JS_HASH_BITS);
|
JS_ASSERT(newshift < JS_HASH_BITS);
|
||||||
|
|
||||||
@@ -228,20 +230,17 @@ Resize(JSHashTable *ht, uint32 newshift)
|
|||||||
hep = BUCKET_HEAD(ht, he->keyHash);
|
hep = BUCKET_HEAD(ht, he->keyHash);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not require unique entries, instead appending he to the
|
* Since he comes from the old table, it must be unique and we
|
||||||
* chain starting at hep.
|
* simply add it to the head of bucket chain without chain lookup.
|
||||||
*/
|
*/
|
||||||
while (*hep)
|
he->next = *hep;
|
||||||
hep = &(*hep)->next;
|
|
||||||
he->next = NULL;
|
|
||||||
*hep = he;
|
*hep = he;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
memset(oldbuckets, 0xDB, nold * sizeof oldbuckets[0]);
|
memset(oldbuckets, 0xDB, nold * sizeof oldbuckets[0]);
|
||||||
#endif
|
#endif
|
||||||
ht->allocOps->freeTable(ht->allocPriv, oldbuckets,
|
ht->allocOps->freeTable(ht->allocPriv, oldbuckets);
|
||||||
nold * sizeof oldbuckets[0]);
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ typedef intN (* JSHashEnumerator)(JSHashEntry *he, intN i, void *arg);
|
|||||||
|
|
||||||
typedef struct JSHashAllocOps {
|
typedef struct JSHashAllocOps {
|
||||||
void * (*allocTable)(void *pool, size_t size);
|
void * (*allocTable)(void *pool, size_t size);
|
||||||
void (*freeTable)(void *pool, void *item, size_t size);
|
void (*freeTable)(void *pool, void *item);
|
||||||
JSHashEntry * (*allocEntry)(void *pool, const void *key);
|
JSHashEntry * (*allocEntry)(void *pool, const void *key);
|
||||||
void (*freeEntry)(void *pool, JSHashEntry *he, uintN flag);
|
void (*freeEntry)(void *pool, JSHashEntry *he, uintN flag);
|
||||||
} JSHashAllocOps;
|
} JSHashAllocOps;
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
|
|||||||
*
|
*
|
||||||
* So here, on first cache fill for this method, we brand
|
* So here, on first cache fill for this method, we brand
|
||||||
* the scope with a new shape and set the SCOPE_BRANDED
|
* the scope with a new shape and set the SCOPE_BRANDED
|
||||||
* flag. Once this scope flag is set, any write that adds
|
* flag. Once this scope flag is set, any write that adds
|
||||||
* or deletes a function-valued plain old property in
|
* or deletes a function-valued plain old property in
|
||||||
* scope->object will result in shape being regenerated.
|
* scope->object will result in shape being regenerated.
|
||||||
*/
|
*/
|
||||||
@@ -701,7 +701,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||||||
if (!js_GetCallObject(cx, fp))
|
if (!js_GetCallObject(cx, fp))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* We know we must clone everything on blockChain. */
|
/* We know we must clone everything on blockChain. */
|
||||||
limitBlock = limitClone = NULL;
|
limitBlock = limitClone = NULL;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@@ -715,7 +715,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||||||
limitClone = OBJ_GET_PARENT(cx, limitClone);
|
limitClone = OBJ_GET_PARENT(cx, limitClone);
|
||||||
JS_ASSERT(limitClone);
|
JS_ASSERT(limitClone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It may seem like we don't know enough about limitClone to be able
|
* It may seem like we don't know enough about limitClone to be able
|
||||||
* to just grab its prototype as we do here, but it's actually okay.
|
* to just grab its prototype as we do here, but it's actually okay.
|
||||||
*
|
*
|
||||||
@@ -743,7 +743,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||||||
/*
|
/*
|
||||||
* Special-case cloning the innermost block; this doesn't have enough in
|
* Special-case cloning the innermost block; this doesn't have enough in
|
||||||
* common with subsequent steps to include in the loop.
|
* common with subsequent steps to include in the loop.
|
||||||
*
|
*
|
||||||
* We pass fp->scopeChain and not null even if we override the parent slot
|
* We pass fp->scopeChain and not null even if we override the parent slot
|
||||||
* later as null triggers useless calculations of slot's value in
|
* later as null triggers useless calculations of slot's value in
|
||||||
* js_NewObject that js_CloneBlockObject calls.
|
* js_NewObject that js_CloneBlockObject calls.
|
||||||
@@ -785,8 +785,8 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
|||||||
* If we found a limit block belonging to this frame, then we should have
|
* If we found a limit block belonging to this frame, then we should have
|
||||||
* found it in blockChain.
|
* found it in blockChain.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT_IF(limitBlock &&
|
JS_ASSERT_IF(limitBlock &&
|
||||||
OBJ_GET_CLASS(cx, limitBlock) == &js_BlockClass &&
|
OBJ_GET_CLASS(cx, limitBlock) == &js_BlockClass &&
|
||||||
OBJ_GET_PRIVATE(cx, limitClone) == fp,
|
OBJ_GET_PRIVATE(cx, limitClone) == fp,
|
||||||
sharedBlock);
|
sharedBlock);
|
||||||
|
|
||||||
@@ -2485,16 +2485,16 @@ JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(INT_TO_JSVAL(JSVAL_INT_MAX)));
|
|||||||
JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
|
JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
|
||||||
JS_STATIC_ASSERT(JSOP_GETGVAR_LENGTH == JSOP_CALLGVAR_LENGTH);
|
JS_STATIC_ASSERT(JSOP_GETGVAR_LENGTH == JSOP_CALLGVAR_LENGTH);
|
||||||
JS_STATIC_ASSERT(JSOP_GETUPVAR_LENGTH == JSOP_CALLUPVAR_LENGTH);
|
JS_STATIC_ASSERT(JSOP_GETUPVAR_LENGTH == JSOP_CALLUPVAR_LENGTH);
|
||||||
JS_STATIC_ASSERT(JSOP_GETDSLOT_LENGTH == JSOP_CALLDSLOT_LENGTH);
|
|
||||||
JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
|
JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
|
||||||
JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
|
JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
|
||||||
JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
|
JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
|
* Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
|
||||||
* remain distinct for the decompiler.
|
* remain distinct for the decompiler. Ditto for JSOP_NULL{,THIS}.
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
|
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
|
||||||
|
JS_STATIC_ASSERT(JSOP_NULL_LENGTH == JSOP_NULLTHIS_LENGTH);
|
||||||
|
|
||||||
/* See TRY_BRANCH_AFTER_COND. */
|
/* See TRY_BRANCH_AFTER_COND. */
|
||||||
JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
|
JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
|
||||||
@@ -2665,8 +2665,7 @@ js_Interpret(JSContext *cx)
|
|||||||
/* We had better not be entering the interpreter from JIT-compiled code. */
|
/* We had better not be entering the interpreter from JIT-compiled code. */
|
||||||
TraceRecorder *tr = TRACE_RECORDER(cx);
|
TraceRecorder *tr = TRACE_RECORDER(cx);
|
||||||
SET_TRACE_RECORDER(cx, NULL);
|
SET_TRACE_RECORDER(cx, NULL);
|
||||||
|
/* If a recorder is pending and we try to re-enter the interpreter, flag
|
||||||
/* If a recorder is pending and we try to re-enter the interpreter, flag
|
|
||||||
the recorder to be destroyed when we return. */
|
the recorder to be destroyed when we return. */
|
||||||
if (tr) {
|
if (tr) {
|
||||||
if (tr->wasDeepAborted())
|
if (tr->wasDeepAborted())
|
||||||
@@ -2787,8 +2786,8 @@ js_Interpret(JSContext *cx)
|
|||||||
js_SetVersion(cx, currentVersion);
|
js_SetVersion(cx, currentVersion);
|
||||||
|
|
||||||
/* Update the static-link display. */
|
/* Update the static-link display. */
|
||||||
if (script->staticLevel < JS_DISPLAY_SIZE) {
|
if (script->staticDepth < JS_DISPLAY_SIZE) {
|
||||||
JSStackFrame **disp = &cx->display[script->staticLevel];
|
JSStackFrame **disp = &cx->display[script->staticDepth];
|
||||||
fp->displaySave = *disp;
|
fp->displaySave = *disp;
|
||||||
*disp = fp;
|
*disp = fp;
|
||||||
}
|
}
|
||||||
@@ -3064,8 +3063,8 @@ js_Interpret(JSContext *cx)
|
|||||||
JS_ASSERT(!fp->blockChain);
|
JS_ASSERT(!fp->blockChain);
|
||||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
||||||
|
|
||||||
if (script->staticLevel < JS_DISPLAY_SIZE)
|
if (script->staticDepth < JS_DISPLAY_SIZE)
|
||||||
cx->display[script->staticLevel] = fp->displaySave;
|
cx->display[script->staticDepth] = fp->displaySave;
|
||||||
|
|
||||||
if (hookData) {
|
if (hookData) {
|
||||||
JSInterpreterHook hook;
|
JSInterpreterHook hook;
|
||||||
@@ -3393,7 +3392,7 @@ js_Interpret(JSContext *cx)
|
|||||||
STORE_OPND(-1, lval);
|
STORE_OPND(-1, lval);
|
||||||
STORE_OPND(-2, rval);
|
STORE_OPND(-2, rval);
|
||||||
END_CASE(JSOP_SWAP)
|
END_CASE(JSOP_SWAP)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_PICK)
|
BEGIN_CASE(JSOP_PICK)
|
||||||
i = regs.pc[1];
|
i = regs.pc[1];
|
||||||
JS_ASSERT(regs.sp - (i+1) >= StackBase(fp));
|
JS_ASSERT(regs.sp - (i+1) >= StackBase(fp));
|
||||||
@@ -4846,13 +4845,13 @@ js_Interpret(JSContext *cx)
|
|||||||
regs.sp = vp + 1;
|
regs.sp = vp + 1;
|
||||||
CHECK_INTERRUPT_HANDLER();
|
CHECK_INTERRUPT_HANDLER();
|
||||||
END_CASE(JSOP_NEW)
|
END_CASE(JSOP_NEW)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_CALL)
|
BEGIN_CASE(JSOP_CALL)
|
||||||
BEGIN_CASE(JSOP_EVAL)
|
BEGIN_CASE(JSOP_EVAL)
|
||||||
BEGIN_CASE(JSOP_APPLY)
|
BEGIN_CASE(JSOP_APPLY)
|
||||||
argc = GET_ARGC(regs.pc);
|
argc = GET_ARGC(regs.pc);
|
||||||
vp = regs.sp - (argc + 2);
|
vp = regs.sp - (argc + 2);
|
||||||
|
|
||||||
lval = *vp;
|
lval = *vp;
|
||||||
if (VALUE_IS_FUNCTION(cx, lval)) {
|
if (VALUE_IS_FUNCTION(cx, lval)) {
|
||||||
obj = JSVAL_TO_OBJECT(lval);
|
obj = JSVAL_TO_OBJECT(lval);
|
||||||
@@ -4954,8 +4953,8 @@ js_Interpret(JSContext *cx)
|
|||||||
newifp->frame.dormantNext = NULL;
|
newifp->frame.dormantNext = NULL;
|
||||||
newifp->frame.xmlNamespace = NULL;
|
newifp->frame.xmlNamespace = NULL;
|
||||||
newifp->frame.blockChain = NULL;
|
newifp->frame.blockChain = NULL;
|
||||||
if (script->staticLevel < JS_DISPLAY_SIZE) {
|
if (script->staticDepth < JS_DISPLAY_SIZE) {
|
||||||
JSStackFrame **disp = &cx->display[script->staticLevel];
|
JSStackFrame **disp = &cx->display[script->staticDepth];
|
||||||
newifp->frame.displaySave = *disp;
|
newifp->frame.displaySave = *disp;
|
||||||
*disp = &newifp->frame;
|
*disp = &newifp->frame;
|
||||||
}
|
}
|
||||||
@@ -5406,6 +5405,7 @@ js_Interpret(JSContext *cx)
|
|||||||
END_CASE(JSOP_ONE)
|
END_CASE(JSOP_ONE)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_NULL)
|
BEGIN_CASE(JSOP_NULL)
|
||||||
|
BEGIN_CASE(JSOP_NULLTHIS)
|
||||||
PUSH_OPND(JSVAL_NULL);
|
PUSH_OPND(JSVAL_NULL);
|
||||||
END_CASE(JSOP_NULL)
|
END_CASE(JSOP_NULL)
|
||||||
|
|
||||||
@@ -5647,13 +5647,11 @@ js_Interpret(JSContext *cx)
|
|||||||
uva = JS_SCRIPT_UPVARS(script);
|
uva = JS_SCRIPT_UPVARS(script);
|
||||||
JS_ASSERT(index < uva->length);
|
JS_ASSERT(index < uva->length);
|
||||||
skip = UPVAR_FRAME_SKIP(uva->vector[index]);
|
skip = UPVAR_FRAME_SKIP(uva->vector[index]);
|
||||||
fp2 = cx->display[script->staticLevel - skip];
|
fp2 = cx->display[script->staticDepth - skip];
|
||||||
JS_ASSERT(fp2->script);
|
JS_ASSERT(fp2->fun && fp2->script);
|
||||||
|
|
||||||
slot = UPVAR_FRAME_SLOT(uva->vector[index]);
|
slot = UPVAR_FRAME_SLOT(uva->vector[index]);
|
||||||
if (!fp2->fun) {
|
if (slot < fp2->fun->nargs) {
|
||||||
vp = fp2->slots + fp2->script->nfixed;
|
|
||||||
} else if (slot < fp2->fun->nargs) {
|
|
||||||
vp = fp2->argv;
|
vp = fp2->argv;
|
||||||
} else {
|
} else {
|
||||||
slot -= fp2->fun->nargs;
|
slot -= fp2->fun->nargs;
|
||||||
@@ -5667,22 +5665,6 @@ js_Interpret(JSContext *cx)
|
|||||||
}
|
}
|
||||||
END_CASE(JSOP_GETUPVAR)
|
END_CASE(JSOP_GETUPVAR)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_GETDSLOT)
|
|
||||||
BEGIN_CASE(JSOP_CALLDSLOT)
|
|
||||||
obj = fp->callee;
|
|
||||||
JS_ASSERT(obj);
|
|
||||||
JS_ASSERT(obj->dslots);
|
|
||||||
|
|
||||||
index = GET_UINT16(regs.pc);
|
|
||||||
JS_ASSERT(JS_INITIAL_NSLOTS + index < jsatomid(obj->dslots[-1]));
|
|
||||||
JS_ASSERT_IF(OBJ_SCOPE(obj)->object == obj,
|
|
||||||
JS_INITIAL_NSLOTS + index < obj->map->freeslot);
|
|
||||||
|
|
||||||
PUSH_OPND(obj->dslots[index]);
|
|
||||||
if (op == JSOP_CALLDSLOT)
|
|
||||||
PUSH_OPND(JSVAL_NULL);
|
|
||||||
END_CASE(JSOP_GETDSLOT)
|
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_GETGVAR)
|
BEGIN_CASE(JSOP_GETGVAR)
|
||||||
BEGIN_CASE(JSOP_CALLGVAR)
|
BEGIN_CASE(JSOP_CALLGVAR)
|
||||||
slot = GET_SLOTNO(regs.pc);
|
slot = GET_SLOTNO(regs.pc);
|
||||||
@@ -5809,40 +5791,25 @@ js_Interpret(JSContext *cx)
|
|||||||
* function body).
|
* function body).
|
||||||
*/
|
*/
|
||||||
LOAD_FUNCTION(0);
|
LOAD_FUNCTION(0);
|
||||||
obj = FUN_OBJECT(fun);
|
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun)) {
|
if (!fp->blockChain) {
|
||||||
/*
|
|
||||||
* Even a null closure needs a parent for principals finding.
|
|
||||||
* FIXME: bug 476950, although debugger users may also demand
|
|
||||||
* some kind of scope link for debugger-assisted eval-in-frame.
|
|
||||||
*/
|
|
||||||
obj2 = fp->scopeChain;
|
obj2 = fp->scopeChain;
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
|
obj2 = js_GetScopeChain(cx, fp);
|
||||||
|
if (!obj2)
|
||||||
/*
|
goto error;
|
||||||
* Inline js_GetScopeChain a bit to optimize for the case of a
|
|
||||||
* top-level function.
|
|
||||||
*/
|
|
||||||
if (!fp->blockChain) {
|
|
||||||
obj2 = fp->scopeChain;
|
|
||||||
} else {
|
|
||||||
obj2 = js_GetScopeChain(cx, fp);
|
|
||||||
if (!obj2)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If static link is not current scope, clone fun's object to link
|
* If static link is not current scope, clone fun's object to link
|
||||||
* to the current scope via parent. We do this to enable sharing of
|
* to the current scope via parent. This clause exists to enable
|
||||||
* compiled functions among multiple equivalent scopes, amortizing
|
* sharing of compiled functions among multiple equivalent scopes,
|
||||||
* the cost of compilation over a number of executions. Examples
|
* splitting the cost of compilation evenly among the scopes and
|
||||||
* include XUL scripts and event handlers shared among Firefox or
|
* amortizing it over a number of executions. Examples include XUL
|
||||||
* other Mozilla app chrome windows, and user-defined JS functions
|
* scripts and event handlers shared among Mozilla chrome windows,
|
||||||
* precompiled and then shared among requests in server-side JS.
|
* and server-side JS user-defined functions shared among requests.
|
||||||
*/
|
*/
|
||||||
|
obj = FUN_OBJECT(fun);
|
||||||
if (OBJ_GET_PARENT(cx, obj) != obj2) {
|
if (OBJ_GET_PARENT(cx, obj) != obj2) {
|
||||||
obj = js_CloneFunctionObject(cx, fun, obj2);
|
obj = js_CloneFunctionObject(cx, fun, obj2);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
@@ -5856,7 +5823,6 @@ js_Interpret(JSContext *cx)
|
|||||||
*/
|
*/
|
||||||
MUST_FLOW_THROUGH("restore_scope");
|
MUST_FLOW_THROUGH("restore_scope");
|
||||||
fp->scopeChain = obj;
|
fp->scopeChain = obj;
|
||||||
|
|
||||||
rval = OBJECT_TO_JSVAL(obj);
|
rval = OBJECT_TO_JSVAL(obj);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -5951,144 +5917,133 @@ js_Interpret(JSContext *cx)
|
|||||||
}
|
}
|
||||||
END_CASE(JSOP_DEFFUN)
|
END_CASE(JSOP_DEFFUN)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_DEFFUN_FC)
|
|
||||||
LOAD_FUNCTION(0);
|
|
||||||
|
|
||||||
obj = js_NewFlatClosure(cx, fun);
|
|
||||||
if (!obj)
|
|
||||||
goto error;
|
|
||||||
rval = OBJECT_TO_JSVAL(obj);
|
|
||||||
|
|
||||||
attrs = (fp->flags & JSFRAME_EVAL)
|
|
||||||
? JSPROP_ENUMERATE
|
|
||||||
: JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
|
||||||
|
|
||||||
flags = JSFUN_GSFLAG2ATTR(fun->flags);
|
|
||||||
if (flags) {
|
|
||||||
attrs |= flags | JSPROP_SHARED;
|
|
||||||
rval = JSVAL_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent = fp->varobj;
|
|
||||||
JS_ASSERT(parent);
|
|
||||||
|
|
||||||
id = ATOM_TO_JSID(fun->atom);
|
|
||||||
ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
|
|
||||||
if (ok) {
|
|
||||||
if (attrs == JSPROP_ENUMERATE) {
|
|
||||||
JS_ASSERT(fp->flags & JSFRAME_EVAL);
|
|
||||||
ok = OBJ_SET_PROPERTY(cx, parent, id, &rval);
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(attrs & JSPROP_PERMANENT);
|
|
||||||
|
|
||||||
ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval,
|
|
||||||
(flags & JSPROP_GETTER)
|
|
||||||
? JS_EXTENSION (JSPropertyOp) obj
|
|
||||||
: JS_PropertyStub,
|
|
||||||
(flags & JSPROP_SETTER)
|
|
||||||
? JS_EXTENSION (JSPropertyOp) obj
|
|
||||||
: JS_PropertyStub,
|
|
||||||
attrs,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
END_CASE(JSOP_DEFFUN_FC)
|
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_DEFLOCALFUN)
|
BEGIN_CASE(JSOP_DEFLOCALFUN)
|
||||||
|
LOAD_FUNCTION(SLOTNO_LEN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define a local function (i.e., one nested at the top level of
|
* Define a local function (i.e., one nested at the top level of
|
||||||
* another function), parented by the current scope chain, stored
|
* another function), parented by the current scope chain, and
|
||||||
* in a local variable slot that the compiler allocated. This is
|
* stored in a local variable slot that the compiler allocated.
|
||||||
* an optimization over JSOP_DEFFUN that avoids requiring a call
|
* This is an optimization over JSOP_DEFFUN that avoids requiring
|
||||||
* object for the outer function's activation.
|
* a call object for the outer function's activation.
|
||||||
*/
|
*/
|
||||||
LOAD_FUNCTION(SLOTNO_LEN);
|
slot = GET_SLOTNO(regs.pc);
|
||||||
JS_ASSERT(FUN_INTERPRETED(fun));
|
|
||||||
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
|
|
||||||
obj = FUN_OBJECT(fun);
|
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun)) {
|
parent = js_GetScopeChain(cx, fp);
|
||||||
obj = js_CloneFunctionObject(cx, fun, fp->scopeChain);
|
if (!parent)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
obj = FUN_OBJECT(fun);
|
||||||
|
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
||||||
|
#ifdef JS_TRACER
|
||||||
|
if (TRACE_RECORDER(cx))
|
||||||
|
js_AbortRecording(cx, "DEFLOCALFUN for closure");
|
||||||
|
#endif
|
||||||
|
obj = js_CloneFunctionObject(cx, fun, parent);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto error;
|
goto error;
|
||||||
} else {
|
|
||||||
parent = js_GetScopeChain(cx, fp);
|
|
||||||
if (!parent)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
if (TRACE_RECORDER(cx))
|
|
||||||
js_AbortRecording(cx, "DEFLOCALFUN for closure");
|
|
||||||
#endif
|
|
||||||
obj = js_CloneFunctionObject(cx, fun, parent);
|
|
||||||
if (!obj)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slot = GET_SLOTNO(regs.pc);
|
|
||||||
TRACE_2(DefLocalFunSetSlot, slot, obj);
|
TRACE_2(DefLocalFunSetSlot, slot, obj);
|
||||||
|
|
||||||
fp->slots[slot] = OBJECT_TO_JSVAL(obj);
|
fp->slots[slot] = OBJECT_TO_JSVAL(obj);
|
||||||
END_CASE(JSOP_DEFLOCALFUN)
|
END_CASE(JSOP_DEFLOCALFUN)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_DEFLOCALFUN_FC)
|
BEGIN_CASE(JSOP_ANONFUNOBJ)
|
||||||
LOAD_FUNCTION(SLOTNO_LEN);
|
|
||||||
|
|
||||||
obj = js_NewFlatClosure(cx, fun);
|
|
||||||
if (!obj)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
slot = GET_SLOTNO(regs.pc);
|
|
||||||
TRACE_2(DefLocalFunSetSlot, slot, obj);
|
|
||||||
|
|
||||||
fp->slots[slot] = OBJECT_TO_JSVAL(obj);
|
|
||||||
END_CASE(JSOP_DEFLOCALFUN_FC)
|
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_LAMBDA)
|
|
||||||
/* Load the specified function object literal. */
|
/* Load the specified function object literal. */
|
||||||
LOAD_FUNCTION(0);
|
LOAD_FUNCTION(0);
|
||||||
obj = FUN_OBJECT(fun);
|
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun)) {
|
/* If re-parenting, push a clone of the function object. */
|
||||||
obj = js_CloneFunctionObject(cx, fun, fp->scopeChain);
|
parent = js_GetScopeChain(cx, fp);
|
||||||
|
if (!parent)
|
||||||
|
goto error;
|
||||||
|
obj = FUN_OBJECT(fun);
|
||||||
|
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
||||||
|
obj = js_CloneFunctionObject(cx, fun, parent);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto error;
|
goto error;
|
||||||
} else {
|
|
||||||
parent = js_GetScopeChain(cx, fp);
|
|
||||||
if (!parent)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* If re-parenting, push a clone of the function object. */
|
|
||||||
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
|
||||||
obj = js_CloneFunctionObject(cx, fun, parent);
|
|
||||||
if (!obj)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||||
END_CASE(JSOP_LAMBDA)
|
END_CASE(JSOP_ANONFUNOBJ)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_LAMBDA_FC)
|
BEGIN_CASE(JSOP_NAMEDFUNOBJ)
|
||||||
LOAD_FUNCTION(0);
|
LOAD_FUNCTION(0);
|
||||||
|
|
||||||
obj = js_NewFlatClosure(cx, fun);
|
/*
|
||||||
|
* ECMA ed. 3 FunctionExpression: function Identifier [etc.].
|
||||||
|
*
|
||||||
|
* 1. Create a new object as if by the expression new Object().
|
||||||
|
* 2. Add Result(1) to the front of the scope chain.
|
||||||
|
*
|
||||||
|
* Step 2 is achieved by making the new object's parent be the
|
||||||
|
* current scope chain, and then making the new object the parent
|
||||||
|
* of the Function object clone.
|
||||||
|
*/
|
||||||
|
obj2 = js_GetScopeChain(cx, fp);
|
||||||
|
if (!obj2)
|
||||||
|
goto error;
|
||||||
|
parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2, 0);
|
||||||
|
if (!parent)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3. Create a new Function object as specified in section 13.2
|
||||||
|
* with [parameters and body specified by the function expression
|
||||||
|
* that was parsed by the compiler into a Function object, and
|
||||||
|
* saved in the script's atom map].
|
||||||
|
*
|
||||||
|
* Protect parent from the GC.
|
||||||
|
*/
|
||||||
|
fp->scopeChain = parent;
|
||||||
|
obj = js_CloneFunctionObject(cx, fun, parent);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
/*
|
||||||
END_CASE(JSOP_LAMBDA_FC)
|
* Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY. All
|
||||||
|
* paths from here must flow through the "Restore fp->scopeChain"
|
||||||
|
* code below the OBJ_DEFINE_PROPERTY call.
|
||||||
|
*/
|
||||||
|
MUST_FLOW_THROUGH("restore2");
|
||||||
|
fp->scopeChain = obj;
|
||||||
|
rval = OBJECT_TO_JSVAL(obj);
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_CALLEE)
|
/*
|
||||||
PUSH_OPND(OBJECT_TO_JSVAL(fp->callee));
|
* 4. Create a property in the object Result(1). The property's
|
||||||
END_CASE(JSOP_CALLEE)
|
* name is [fun->atom, the identifier parsed by the compiler],
|
||||||
|
* value is Result(3), and attributes are { DontDelete, ReadOnly }.
|
||||||
|
*/
|
||||||
|
attrs = JSFUN_GSFLAG2ATTR(fun->flags);
|
||||||
|
if (attrs) {
|
||||||
|
attrs |= JSPROP_SHARED;
|
||||||
|
rval = JSVAL_VOID;
|
||||||
|
}
|
||||||
|
ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
|
||||||
|
(attrs & JSPROP_GETTER)
|
||||||
|
? JS_EXTENSION (JSPropertyOp) obj
|
||||||
|
: JS_PropertyStub,
|
||||||
|
(attrs & JSPROP_SETTER)
|
||||||
|
? JS_EXTENSION (JSPropertyOp) obj
|
||||||
|
: JS_PropertyStub,
|
||||||
|
attrs |
|
||||||
|
JSPROP_ENUMERATE | JSPROP_PERMANENT |
|
||||||
|
JSPROP_READONLY,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Restore fp->scopeChain now that obj is defined in parent. */
|
||||||
|
MUST_FLOW_LABEL(restore2)
|
||||||
|
fp->scopeChain = obj2;
|
||||||
|
if (!ok) {
|
||||||
|
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 5. Remove Result(1) from the front of the scope chain [no-op].
|
||||||
|
* 6. Return Result(3).
|
||||||
|
*/
|
||||||
|
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||||
|
END_CASE(JSOP_NAMEDFUNOBJ)
|
||||||
|
|
||||||
#if JS_HAS_GETTER_SETTER
|
#if JS_HAS_GETTER_SETTER
|
||||||
BEGIN_CASE(JSOP_GETTER)
|
BEGIN_CASE(JSOP_GETTER)
|
||||||
@@ -6883,7 +6838,7 @@ js_Interpret(JSContext *cx)
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JS_ASSERT(OBJ_GET_CLASS(cx, fp->blockChain) == &js_BlockClass);
|
JS_ASSERT(OBJ_GET_CLASS(cx, fp->blockChain) == &js_BlockClass);
|
||||||
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain);
|
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain);
|
||||||
|
|
||||||
JS_ASSERT(blockDepth <= StackDepth(script));
|
JS_ASSERT(blockDepth <= StackDepth(script));
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
@@ -7024,6 +6979,15 @@ js_Interpret(JSContext *cx)
|
|||||||
L_JSOP_DEFXMLNS:
|
L_JSOP_DEFXMLNS:
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
L_JSOP_UNUSED203:
|
||||||
|
L_JSOP_UNUSED204:
|
||||||
|
L_JSOP_UNUSED205:
|
||||||
|
L_JSOP_UNUSED206:
|
||||||
|
L_JSOP_UNUSED207:
|
||||||
|
L_JSOP_UNUSED208:
|
||||||
|
L_JSOP_UNUSED209:
|
||||||
|
L_JSOP_UNUSED219:
|
||||||
|
|
||||||
#else /* !JS_THREADED_INTERP */
|
#else /* !JS_THREADED_INTERP */
|
||||||
default:
|
default:
|
||||||
#endif
|
#endif
|
||||||
@@ -7048,7 +7012,7 @@ js_Interpret(JSContext *cx)
|
|||||||
// To keep things simple, we hard-code imacro exception handlers here.
|
// To keep things simple, we hard-code imacro exception handlers here.
|
||||||
if (*fp->imacpc == JSOP_NEXTITER) {
|
if (*fp->imacpc == JSOP_NEXTITER) {
|
||||||
// pc may point to JSOP_DUP here due to bug 474854.
|
// pc may point to JSOP_DUP here due to bug 474854.
|
||||||
JS_ASSERT(*regs.pc == JSOP_CALL || *regs.pc == JSOP_DUP || *regs.pc == JSOP_TRUE);
|
JS_ASSERT(*regs.pc == JSOP_CALL || *regs.pc == JSOP_DUP);
|
||||||
if (js_ValueIsStopIteration(cx->exception)) {
|
if (js_ValueIsStopIteration(cx->exception)) {
|
||||||
cx->throwing = JS_FALSE;
|
cx->throwing = JS_FALSE;
|
||||||
cx->exception = JSVAL_VOID;
|
cx->exception = JSVAL_VOID;
|
||||||
@@ -7067,9 +7031,9 @@ js_Interpret(JSContext *cx)
|
|||||||
JS_ASSERT((size_t)((fp->imacpc ? fp->imacpc : regs.pc) - script->code) < script->length);
|
JS_ASSERT((size_t)((fp->imacpc ? fp->imacpc : regs.pc) - script->code) < script->length);
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
/*
|
/*
|
||||||
* This abort could be weakened to permit tracing through exceptions that
|
* This abort could be weakened to permit tracing through exceptions that
|
||||||
* are thrown and caught within a loop, with the co-operation of the tracer.
|
* are thrown and caught within a loop, with the co-operation of the tracer.
|
||||||
* For now just bail on any sign of trouble.
|
* For now just bail on any sign of trouble.
|
||||||
*/
|
*/
|
||||||
if (TRACE_RECORDER(cx))
|
if (TRACE_RECORDER(cx))
|
||||||
@@ -7271,8 +7235,8 @@ js_Interpret(JSContext *cx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Undo the remaining effects committed on entry to js_Interpret. */
|
/* Undo the remaining effects committed on entry to js_Interpret. */
|
||||||
if (script->staticLevel < JS_DISPLAY_SIZE)
|
if (script->staticDepth < JS_DISPLAY_SIZE)
|
||||||
cx->display[script->staticLevel] = fp->displaySave;
|
cx->display[script->staticDepth] = fp->displaySave;
|
||||||
JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
|
JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
|
||||||
if (cx->version == currentVersion && currentVersion != originalVersion)
|
if (cx->version == currentVersion && currentVersion != originalVersion)
|
||||||
js_SetVersion(cx, originalVersion);
|
js_SetVersion(cx, originalVersion);
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ struct JSStackFrame {
|
|||||||
JSStackFrame *dormantNext; /* next dormant frame chain */
|
JSStackFrame *dormantNext; /* next dormant frame chain */
|
||||||
JSObject *xmlNamespace; /* null or default xml namespace in E4X */
|
JSObject *xmlNamespace; /* null or default xml namespace in E4X */
|
||||||
JSStackFrame *displaySave; /* previous value of display entry for
|
JSStackFrame *displaySave; /* previous value of display entry for
|
||||||
script->staticLevel */
|
script->staticDepth */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
jsrefcount pcDisabledSave; /* for balanced property cache control */
|
jsrefcount pcDisabledSave; /* for balanced property cache control */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -676,7 +676,7 @@ generator_trace(JSTracer *trc, JSObject *obj)
|
|||||||
js_TraceStackFrame(trc, &gen->frame);
|
js_TraceStackFrame(trc, &gen->frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_DATA(JSClass) js_GeneratorClass = {
|
JSClass js_GeneratorClass = {
|
||||||
js_Generator_str,
|
js_Generator_str,
|
||||||
JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS |
|
JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS |
|
||||||
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator),
|
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator),
|
||||||
|
|||||||
@@ -121,9 +121,9 @@ js_NewGenerator(JSContext *cx, JSStackFrame *fp);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern JS_FRIEND_API(JSClass) js_GeneratorClass;
|
extern JSClass js_GeneratorClass;
|
||||||
extern JSClass js_IteratorClass;
|
extern JSClass js_IteratorClass;
|
||||||
extern JSClass js_StopIterationClass;
|
extern JSClass js_StopIterationClass;
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
js_ValueIsStopIteration(jsval v)
|
js_ValueIsStopIteration(jsval v)
|
||||||
|
|||||||
@@ -136,10 +136,10 @@ struct JSTitle {
|
|||||||
|
|
||||||
#ifdef JS_DEBUG_TITLE_LOCKS
|
#ifdef JS_DEBUG_TITLE_LOCKS
|
||||||
|
|
||||||
#define JS_SET_OBJ_INFO(obj_, file_, line_) \
|
#define JS_SET_OBJ_INFO(obj_, file_, line_) \
|
||||||
JS_SET_SCOPE_INFO(OBJ_SCOPE(obj_), file_, line_)
|
JS_SET_SCOPE_INFO(OBJ_SCOPE(obj_), file_, line_)
|
||||||
|
|
||||||
#define JS_SET_SCOPE_INFO(scope_, file_, line_) \
|
#define JS_SET_SCOPE_INFO(scope_, file_, line_) \
|
||||||
js_SetScopeInfo(scope_, file_, line_)
|
js_SetScopeInfo(scope_, file_, line_)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -157,25 +157,25 @@ struct JSTitle {
|
|||||||
* are for optimizations above the JSObjectOps layer, under which object locks
|
* are for optimizations above the JSObjectOps layer, under which object locks
|
||||||
* normally hide.
|
* normally hide.
|
||||||
*/
|
*/
|
||||||
#define JS_LOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \
|
#define JS_LOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \
|
||||||
? (void)0 \
|
? (void)0 \
|
||||||
: (js_LockObj(cx, obj), \
|
: (js_LockObj(cx, obj), \
|
||||||
JS_SET_OBJ_INFO(obj,__FILE__,__LINE__)))
|
JS_SET_OBJ_INFO(obj,__FILE__,__LINE__)))
|
||||||
#define JS_UNLOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \
|
#define JS_UNLOCK_OBJ(cx,obj) ((OBJ_SCOPE(obj)->title.ownercx == (cx)) \
|
||||||
? (void)0 : js_UnlockObj(cx, obj))
|
? (void)0 : js_UnlockObj(cx, obj))
|
||||||
|
|
||||||
#define JS_LOCK_TITLE(cx,title) \
|
#define JS_LOCK_TITLE(cx,title) \
|
||||||
((title)->ownercx == (cx) ? (void)0 \
|
((title)->ownercx == (cx) ? (void)0 \
|
||||||
: (js_LockTitle(cx, (title)), \
|
: (js_LockTitle(cx, (title)), \
|
||||||
JS_SET_TITLE_INFO(title,__FILE__,__LINE__)))
|
JS_SET_TITLE_INFO(title,__FILE__,__LINE__)))
|
||||||
|
|
||||||
#define JS_UNLOCK_TITLE(cx,title) ((title)->ownercx == (cx) ? (void)0 \
|
#define JS_UNLOCK_TITLE(cx,title) ((title)->ownercx == (cx) ? (void)0 \
|
||||||
: js_UnlockTitle(cx, title))
|
: js_UnlockTitle(cx, title))
|
||||||
|
|
||||||
#define JS_LOCK_SCOPE(cx,scope) JS_LOCK_TITLE(cx,&(scope)->title)
|
#define JS_LOCK_SCOPE(cx,scope) JS_LOCK_TITLE(cx,&(scope)->title)
|
||||||
#define JS_UNLOCK_SCOPE(cx,scope) JS_UNLOCK_TITLE(cx,&(scope)->title)
|
#define JS_UNLOCK_SCOPE(cx,scope) JS_UNLOCK_TITLE(cx,&(scope)->title)
|
||||||
|
|
||||||
#define JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope) \
|
#define JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope) \
|
||||||
js_TransferTitle(cx, &scope->title, &newscope->title)
|
js_TransferTitle(cx, &scope->title, &newscope->title)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1375,7 +1375,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
|
|
||||||
tcflags = TCF_COMPILE_N_GO;
|
tcflags = TCF_COMPILE_N_GO;
|
||||||
if (caller) {
|
if (caller) {
|
||||||
tcflags |= TCF_PUT_STATIC_LEVEL(caller->script->staticLevel + 1);
|
tcflags |= TCF_PUT_STATIC_DEPTH(caller->script->staticDepth + 1);
|
||||||
principals = JS_EvalFramePrincipals(cx, fp, caller);
|
principals = JS_EvalFramePrincipals(cx, fp, caller);
|
||||||
file = js_ComputeFilename(cx, caller, principals, &line);
|
file = js_ComputeFilename(cx, caller, principals, &line);
|
||||||
} else {
|
} else {
|
||||||
@@ -1402,7 +1402,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
script->principals->subsume(script->principals, principals)))) {
|
script->principals->subsume(script->principals, principals)))) {
|
||||||
/*
|
/*
|
||||||
* Get the prior (cache-filling) eval's saved caller function.
|
* Get the prior (cache-filling) eval's saved caller function.
|
||||||
* See JSCompiler::compileScript in jsparse.cpp.
|
* See js_CompileScript in jsparse.cpp.
|
||||||
*/
|
*/
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
JS_GET_SCRIPT_FUNCTION(script, 0, fun);
|
JS_GET_SCRIPT_FUNCTION(script, 0, fun);
|
||||||
@@ -1410,7 +1410,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
if (fun == caller->fun) {
|
if (fun == caller->fun) {
|
||||||
/*
|
/*
|
||||||
* Get the source string passed for safekeeping in the
|
* Get the source string passed for safekeeping in the
|
||||||
* atom map by the prior eval to JSCompiler::compileScript.
|
* atom map by the prior eval to js_CompileScript.
|
||||||
*/
|
*/
|
||||||
JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]);
|
JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]);
|
||||||
|
|
||||||
@@ -1454,9 +1454,9 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!script) {
|
if (!script) {
|
||||||
script = JSCompiler::compileScript(cx, scopeobj, caller, principals, tcflags,
|
script = js_CompileScript(cx, scopeobj, caller, principals, tcflags,
|
||||||
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||||
NULL, file, line, str);
|
NULL, file, line, str);
|
||||||
if (!script) {
|
if (!script) {
|
||||||
ok = JS_FALSE;
|
ok = JS_FALSE;
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@@ -151,41 +151,37 @@ struct JSObjectMap {
|
|||||||
#define JS_INITIAL_NSLOTS 5
|
#define JS_INITIAL_NSLOTS 5
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSObject struct, with members sized to fit in 32 bytes on 32-bit targets,
|
* When JSObject.dslots is not null, JSObject.dslots[-1] records the number of
|
||||||
* 64 bytes on 64-bit systems. The JSFunction struct is an extension of this
|
* available slots.
|
||||||
* struct allocated from a larger GC size-class.
|
|
||||||
*
|
|
||||||
* The classword member stores the JSClass pointer for this object, with the
|
|
||||||
* least two bits encoding whether this object is a "delegate" or a "system"
|
|
||||||
* object.
|
|
||||||
*
|
|
||||||
* An object is a delegate if it is on another object's prototype (linked by
|
|
||||||
* JSSLOT_PROTO) or scope (JSSLOT_PARENT) chain, and therefore the delegate
|
|
||||||
* might be asked implicitly to get or set a property on behalf of another
|
|
||||||
* object. Delegates may be accessed directly too, as may any object, but only
|
|
||||||
* those objects linked after the head of any prototype or scope chain are
|
|
||||||
* flagged as delegates. This definition helps to optimize shape-based property
|
|
||||||
* cache invalidation (see Purge{Scope,Proto}Chain in jsobj.cpp).
|
|
||||||
*
|
|
||||||
* The meaning of the system object bit is defined by the API client. It is
|
|
||||||
* set in JS_NewSystemObject and is queried by JS_IsSystemObject (jsdbgapi.h),
|
|
||||||
* but it has no intrinsic meaning to SpiderMonkey. Further, JSFILENAME_SYSTEM
|
|
||||||
* and JS_FlagScriptFilenamePrefix (also exported via jsdbgapi.h) are intended
|
|
||||||
* to be complementary to this bit, but it is up to the API client to implement
|
|
||||||
* any such association.
|
|
||||||
*
|
|
||||||
* Both these classword tag bits are initially zero; they may be set or queried
|
|
||||||
* using the STOBJ_(IS|SET)_(DELEGATE|SYSTEM) macros.
|
|
||||||
*
|
|
||||||
* The dslots member is null or a pointer into a dynamically allocated vector
|
|
||||||
* of jsvals for reserved and dynamic slots. If dslots is not null, dslots[-1]
|
|
||||||
* records the number of available slots.
|
|
||||||
*/
|
*/
|
||||||
struct JSObject {
|
struct JSObject {
|
||||||
JSObjectMap *map; /* propery map, see jsscope.h */
|
JSObjectMap *map;
|
||||||
jsuword classword; /* classword, see above */
|
|
||||||
jsval fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */
|
/*
|
||||||
jsval *dslots; /* dynamically allocated slots */
|
* Stores the JSClass* for this object, with the two lowest bits encoding
|
||||||
|
* whether this object is a delegate or a system object.
|
||||||
|
*
|
||||||
|
* A delegate is an object linked on another object's prototype
|
||||||
|
* (JSSLOT_PROTO) or scope (JSSLOT_PARENT) chain, which might be implicitly
|
||||||
|
* asked to get or set a property on behalf of another object. Delegates
|
||||||
|
* may be accessed directly too, as might any object, but only those
|
||||||
|
* objects linked after the head of a prototype or scope chain are
|
||||||
|
* delegates. This definition helps to optimize shape-based property cache
|
||||||
|
* purging (see Purge{Scope,Proto}Chain in jsobj.cpp).
|
||||||
|
*
|
||||||
|
* The meaning of the system object bit is defined by the API client. It is
|
||||||
|
* set in JS_NewSystemObject and is queried by JS_IsSystemObject, but it
|
||||||
|
* has no intrinsic meaning to SpiderMonkey. Further, JSFILENAME_SYSTEM and
|
||||||
|
* JS_FlagScriptFilenamePrefix are intended to be complementary to this
|
||||||
|
* bit, but it is up to the API client to implement any such association.
|
||||||
|
*
|
||||||
|
* Both bits are initially zero and may be set or queried using the
|
||||||
|
* STOBJ_(IS|SET)_(DELEGATE|SYSTEM) macros.
|
||||||
|
*/
|
||||||
|
jsuword classword;
|
||||||
|
|
||||||
|
jsval fslots[JS_INITIAL_NSLOTS];
|
||||||
|
jsval *dslots; /* dynamically allocated slots */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define JSSLOT_PROTO 0
|
#define JSSLOT_PROTO 0
|
||||||
|
|||||||
@@ -266,49 +266,35 @@ js_DumpScript(JSContext *cx, JSScript *script)
|
|||||||
const char *
|
const char *
|
||||||
ToDisassemblySource(JSContext *cx, jsval v)
|
ToDisassemblySource(JSContext *cx, jsval v)
|
||||||
{
|
{
|
||||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
JSObject *obj;
|
||||||
JSObject *obj = JSVAL_TO_OBJECT(v);
|
JSScopeProperty *sprop;
|
||||||
JSClass *clasp = OBJ_GET_CLASS(cx, obj);
|
char *source;
|
||||||
|
const char *bytes;
|
||||||
|
JSString *str;
|
||||||
|
|
||||||
if (clasp == &js_BlockClass) {
|
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||||
char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj));
|
obj = JSVAL_TO_OBJECT(v);
|
||||||
for (JSScopeProperty *sprop = OBJ_SCOPE(obj)->lastProp;
|
if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
|
||||||
sprop;
|
source = JS_sprintf_append(NULL, "depth %d {",
|
||||||
|
OBJ_BLOCK_DEPTH(cx, obj));
|
||||||
|
for (sprop = OBJ_SCOPE(obj)->lastProp; sprop;
|
||||||
sprop = sprop->parent) {
|
sprop = sprop->parent) {
|
||||||
const char *bytes = js_AtomToPrintableString(cx, JSID_TO_ATOM(sprop->id));
|
bytes = js_AtomToPrintableString(cx, JSID_TO_ATOM(sprop->id));
|
||||||
if (!bytes)
|
if (!bytes)
|
||||||
return NULL;
|
return NULL;
|
||||||
source = JS_sprintf_append(source, "%s: %d%s",
|
source = JS_sprintf_append(source, "%s: %d%s",
|
||||||
bytes, sprop->shortid,
|
bytes, sprop->shortid,
|
||||||
sprop->parent ? ", " : "");
|
sprop->parent ? ", " : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
source = JS_sprintf_append(source, "}");
|
source = JS_sprintf_append(source, "}");
|
||||||
if (!source)
|
if (!source)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
str = JS_NewString(cx, source, strlen(source));
|
||||||
JSString *str = JS_NewString(cx, source, strlen(source));
|
|
||||||
if (!str)
|
if (!str)
|
||||||
return NULL;
|
return NULL;
|
||||||
return js_GetStringBytes(cx, str);
|
return js_GetStringBytes(cx, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clasp == &js_FunctionClass) {
|
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
|
|
||||||
JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
|
|
||||||
if (!str)
|
|
||||||
return NULL;
|
|
||||||
return js_GetStringBytes(cx, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clasp == &js_RegExpClass) {
|
|
||||||
JSAutoTempValueRooter tvr(cx);
|
|
||||||
if (!js_regexp_toString(cx, obj, tvr.addr()))
|
|
||||||
return NULL;
|
|
||||||
return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return js_ValueToPrintableSource(cx, v);
|
return js_ValueToPrintableSource(cx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2802,14 +2788,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSOP_GETUPVAR:
|
|
||||||
case JSOP_CALLUPVAR:
|
case JSOP_CALLUPVAR:
|
||||||
case JSOP_GETDSLOT:
|
case JSOP_GETUPVAR:
|
||||||
case JSOP_CALLDSLOT:
|
JS_ASSERT(jp->script->flags & JSSF_SAVED_CALLER_FUN);
|
||||||
if (!jp->fun) {
|
|
||||||
JS_ASSERT(jp->script->flags & JSSF_SAVED_CALLER_FUN);
|
if (!jp->fun)
|
||||||
JS_GET_SCRIPT_FUNCTION(jp->script, 0, jp->fun);
|
JS_GET_SCRIPT_FUNCTION(jp->script, 0, jp->fun);
|
||||||
}
|
|
||||||
|
|
||||||
if (!jp->localNames)
|
if (!jp->localNames)
|
||||||
jp->localNames = js_GetLocalNameArray(cx, jp->fun, &jp->pool);
|
jp->localNames = js_GetLocalNameArray(cx, jp->fun, &jp->pool);
|
||||||
@@ -2961,7 +2945,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
: SprintCString(&ss->sprinter, js_yield_str);
|
: SprintCString(&ss->sprinter, js_yield_str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JS_HAS_GENERATOR_EXPRS
|
#if JS_HAS_GENERATOR_EXPRS
|
||||||
LOCAL_ASSERT(SN_TYPE(sn) == SRC_HIDDEN);
|
LOCAL_ASSERT(SN_TYPE(sn) == SRC_HIDDEN);
|
||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
@@ -3008,6 +2991,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
break;
|
break;
|
||||||
--pos;
|
--pos;
|
||||||
}
|
}
|
||||||
|
JS_ASSERT_IF(saveop == JSOP_ARRAYPUSH,
|
||||||
|
jp->script->nfixed + pos == GET_UINT16(pc));
|
||||||
|
|
||||||
#if JS_HAS_GENERATOR_EXPRS
|
#if JS_HAS_GENERATOR_EXPRS
|
||||||
if (saveop == JSOP_YIELD) {
|
if (saveop == JSOP_YIELD) {
|
||||||
@@ -3035,9 +3020,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
* Array comprehension: retract the sprinter to the beginning
|
* Array comprehension: retract the sprinter to the beginning
|
||||||
* of the array initialiser and decompile "[<rval> for ...]".
|
* of the array initialiser and decompile "[<rval> for ...]".
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(jp->script->nfixed + pos == GET_UINT16(pc));
|
|
||||||
LOCAL_ASSERT(ss->opcodes[pos] == JSOP_NEWINIT);
|
LOCAL_ASSERT(ss->opcodes[pos] == JSOP_NEWINIT);
|
||||||
|
|
||||||
start = ss->offsets[pos];
|
start = ss->offsets[pos];
|
||||||
LOCAL_ASSERT(ss->sprinter.base[start] == '[' ||
|
LOCAL_ASSERT(ss->sprinter.base[start] == '[' ||
|
||||||
ss->sprinter.base[start] == '#');
|
ss->sprinter.base[start] == '#');
|
||||||
@@ -3053,7 +3036,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
todo = -2;
|
todo = -2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* JS_HAS_GENERATORS */
|
#endif
|
||||||
|
|
||||||
case JSOP_THROWING:
|
case JSOP_THROWING:
|
||||||
todo = -2;
|
todo = -2;
|
||||||
@@ -3105,12 +3088,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
JS_ASSERT(pc[cond] == JSOP_NEXTITER);
|
JS_ASSERT(pc[cond] == JSOP_NEXTITER);
|
||||||
DECOMPILE_CODE(pc + oplen, next - oplen);
|
DECOMPILE_CODE(pc + oplen, next - oplen);
|
||||||
lval = POP_STR();
|
lval = POP_STR();
|
||||||
LOCAL_ASSERT(ss->top >= 2);
|
|
||||||
|
|
||||||
if (ss->inArrayInit || ss->inGenExp) {
|
if (ss->inArrayInit || ss->inGenExp) {
|
||||||
(void) PopOff(ss, JSOP_NOP);
|
(void) PopOff(ss, JSOP_NOP);
|
||||||
rval = TOP_STR();
|
rval = TOP_STR();
|
||||||
if (ss->top >= 2 && ss->opcodes[ss->top - 2] == JSOP_FORLOCAL) {
|
LOCAL_ASSERT(ss->top >= 2);
|
||||||
|
if (ss->opcodes[ss->top - 2] == JSOP_FORLOCAL) {
|
||||||
ss->sprinter.offset = ss->offsets[ss->top - 1] - PAREN_SLOP;
|
ss->sprinter.offset = ss->offsets[ss->top - 1] - PAREN_SLOP;
|
||||||
if (Sprint(&ss->sprinter, " %s (%s in %s)",
|
if (Sprint(&ss->sprinter, " %s (%s in %s)",
|
||||||
foreach ? js_for_each_str : js_for_str,
|
foreach ? js_for_each_str : js_for_str,
|
||||||
@@ -3126,6 +3108,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
*/
|
*/
|
||||||
todo = ss->offsets[ss->top - 1];
|
todo = ss->offsets[ss->top - 1];
|
||||||
} else {
|
} else {
|
||||||
|
LOCAL_ASSERT(ss->opcodes[ss->top - 2] == JSOP_ENTERBLOCK);
|
||||||
todo = Sprint(&ss->sprinter, " %s (%s in %s)",
|
todo = Sprint(&ss->sprinter, " %s (%s in %s)",
|
||||||
foreach ? js_for_each_str : js_for_str,
|
foreach ? js_for_each_str : js_for_str,
|
||||||
lval, rval);
|
lval, rval);
|
||||||
@@ -3147,7 +3130,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
jp->indent -= 4;
|
jp->indent -= 4;
|
||||||
js_printf(jp, "\t}\n");
|
js_printf(jp, "\t}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
pc += tail;
|
pc += tail;
|
||||||
LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);
|
LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);
|
||||||
len = js_CodeSpec[*pc].length;
|
len = js_CodeSpec[*pc].length;
|
||||||
@@ -3969,39 +3951,26 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
todo = STR2OFF(&ss->sprinter, rval);
|
todo = STR2OFF(&ss->sprinter, rval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_LAMBDA:
|
case JSOP_ANONFUNOBJ:
|
||||||
case JSOP_LAMBDA_FC:
|
|
||||||
#if JS_HAS_GENERATOR_EXPRS
|
#if JS_HAS_GENERATOR_EXPRS
|
||||||
sn = js_GetSrcNote(jp->script, pc);
|
sn = js_GetSrcNote(jp->script, pc);
|
||||||
if (sn && SN_TYPE(sn) == SRC_GENEXP) {
|
if (sn && SN_TYPE(sn) == SRC_GENEXP) {
|
||||||
void *mark;
|
|
||||||
jsuword *innerLocalNames, *outerLocalNames;
|
|
||||||
JSScript *inner, *outer;
|
JSScript *inner, *outer;
|
||||||
|
void *mark;
|
||||||
SprintStack ss2;
|
SprintStack ss2;
|
||||||
JSFunction *outerfun;
|
|
||||||
|
|
||||||
LOAD_FUNCTION(0);
|
LOAD_FUNCTION(0);
|
||||||
|
inner = fun->u.i.script;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All allocation when decompiling is LIFO, using malloc
|
* All allocation when decompiling is LIFO, using malloc
|
||||||
* or, more commonly, arena-allocating from cx->tempPool.
|
* or, more commonly, arena-allocating from cx->tempPool.
|
||||||
* Therefore after InitSprintStack succeeds, we must
|
* After InitSprintStack succeeds, we must release to mark
|
||||||
* release to mark before returning.
|
* before returning.
|
||||||
*/
|
*/
|
||||||
mark = JS_ARENA_MARK(&cx->tempPool);
|
mark = JS_ARENA_MARK(&cx->tempPool);
|
||||||
uintN n = JS_GET_LOCAL_NAME_COUNT(fun);
|
if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner)))
|
||||||
if (n == 0) {
|
|
||||||
innerLocalNames = NULL;
|
|
||||||
} else {
|
|
||||||
innerLocalNames = js_GetLocalNameArray(cx, fun, &cx->tempPool);
|
|
||||||
if (!innerLocalNames)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
inner = fun->u.i.script;
|
|
||||||
if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner))) {
|
|
||||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
ss2.inGenExp = JS_TRUE;
|
ss2.inGenExp = JS_TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -4012,27 +3981,20 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
* string pushed on ss2.
|
* string pushed on ss2.
|
||||||
*/
|
*/
|
||||||
outer = jp->script;
|
outer = jp->script;
|
||||||
outerfun = jp->fun;
|
|
||||||
outerLocalNames = jp->localNames;
|
|
||||||
LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length);
|
LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length);
|
||||||
jp->script = inner;
|
jp->script = inner;
|
||||||
jp->fun = fun;
|
if (!Decompile(&ss2, inner->code, inner->length, JSOP_NOP)) {
|
||||||
jp->localNames = innerLocalNames;
|
|
||||||
ok = Decompile(&ss2, inner->code, inner->length, JSOP_NOP) != NULL;
|
|
||||||
jp->script = outer;
|
|
||||||
jp->fun = outerfun;
|
|
||||||
jp->localNames = outerLocalNames;
|
|
||||||
if (!ok) {
|
|
||||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
jp->script = outer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Advance over this op and its global |this| push, and
|
* Advance over this op and its global |this| push, and
|
||||||
* arrange to advance over the call to this lambda.
|
* arrange to advance over the call to this lambda.
|
||||||
*/
|
*/
|
||||||
pc += len;
|
pc += len;
|
||||||
LOCAL_ASSERT(*pc == JSOP_NULL);
|
LOCAL_ASSERT(*pc == JSOP_NULL || *pc == JSOP_NULLTHIS);
|
||||||
pc += JSOP_NULL_LENGTH;
|
pc += JSOP_NULL_LENGTH;
|
||||||
LOCAL_ASSERT(*pc == JSOP_CALL);
|
LOCAL_ASSERT(*pc == JSOP_CALL);
|
||||||
LOCAL_ASSERT(GET_ARGC(pc) == 0);
|
LOCAL_ASSERT(GET_ARGC(pc) == 0);
|
||||||
@@ -4073,7 +4035,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
* anonymous function, so it doesn't get decompiled as
|
* anonymous function, so it doesn't get decompiled as
|
||||||
* a generator function in a getter or setter context.
|
* a generator function in a getter or setter context.
|
||||||
* The precedence level is the same for JSOP_NAME and
|
* The precedence level is the same for JSOP_NAME and
|
||||||
* JSOP_LAMBDA.
|
* JSOP_ANONFUNOBJ.
|
||||||
*/
|
*/
|
||||||
LOCAL_ASSERT(js_CodeSpec[JSOP_NAME].prec ==
|
LOCAL_ASSERT(js_CodeSpec[JSOP_NAME].prec ==
|
||||||
js_CodeSpec[saveop].prec);
|
js_CodeSpec[saveop].prec);
|
||||||
@@ -4096,6 +4058,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
#endif /* JS_HAS_GENERATOR_EXPRS */
|
#endif /* JS_HAS_GENERATOR_EXPRS */
|
||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
|
|
||||||
|
case JSOP_NAMEDFUNOBJ:
|
||||||
LOAD_FUNCTION(0);
|
LOAD_FUNCTION(0);
|
||||||
{
|
{
|
||||||
uintN indent = JS_DONT_PRETTY_PRINT;
|
uintN indent = JS_DONT_PRETTY_PRINT;
|
||||||
@@ -4104,7 +4067,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
* Always parenthesize expression closures. We can't force
|
* Always parenthesize expression closures. We can't force
|
||||||
* saveop to a low-precedence op to arrange for auto-magic
|
* saveop to a low-precedence op to arrange for auto-magic
|
||||||
* parenthesization without confusing getter/setter code
|
* parenthesization without confusing getter/setter code
|
||||||
* that checks for JSOP_LAMBDA.
|
* that checks for JSOP_ANONFUNOBJ and JSOP_NAMEDFUNOBJ.
|
||||||
*/
|
*/
|
||||||
if (!(fun->flags & JSFUN_EXPR_CLOSURE))
|
if (!(fun->flags & JSFUN_EXPR_CLOSURE))
|
||||||
indent |= JS_IN_GROUP_CONTEXT;
|
indent |= JS_IN_GROUP_CONTEXT;
|
||||||
@@ -4116,11 +4079,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
todo = SprintString(&ss->sprinter, str);
|
todo = SprintString(&ss->sprinter, str);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_CALLEE:
|
|
||||||
JS_ASSERT(jp->fun && jp->fun->atom);
|
|
||||||
todo = SprintString(&ss->sprinter, ATOM_TO_STRING(jp->fun->atom));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSOP_OBJECT:
|
case JSOP_OBJECT:
|
||||||
LOAD_OBJECT(0);
|
LOAD_OBJECT(0);
|
||||||
LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
|
LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
|
||||||
@@ -4336,7 +4294,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case JSOP_DEFFUN:
|
case JSOP_DEFFUN:
|
||||||
case JSOP_DEFFUN_FC:
|
|
||||||
LOAD_FUNCTION(0);
|
LOAD_FUNCTION(0);
|
||||||
todo = -2;
|
todo = -2;
|
||||||
goto do_function;
|
goto do_function;
|
||||||
@@ -4508,8 +4465,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
!ATOM_IS_STRING(atom) ||
|
!ATOM_IS_STRING(atom) ||
|
||||||
!ATOM_IS_IDENTIFIER(atom) ||
|
!ATOM_IS_IDENTIFIER(atom) ||
|
||||||
ATOM_IS_KEYWORD(atom) ||
|
ATOM_IS_KEYWORD(atom) ||
|
||||||
(ss->opcodes[ss->top+1] != JSOP_LAMBDA &&
|
(ss->opcodes[ss->top+1] != JSOP_ANONFUNOBJ &&
|
||||||
ss->opcodes[ss->top+1] != JSOP_LAMBDA_FC)) {
|
ss->opcodes[ss->top+1] != JSOP_NAMEDFUNOBJ)) {
|
||||||
todo = Sprint(&ss->sprinter, "%s%s%s %s: %s",
|
todo = Sprint(&ss->sprinter, "%s%s%s %s: %s",
|
||||||
lval,
|
lval,
|
||||||
maybeComma,
|
maybeComma,
|
||||||
|
|||||||
@@ -65,13 +65,13 @@ typedef enum JSOp {
|
|||||||
*/
|
*/
|
||||||
#define JOF_BYTE 0 /* single bytecode, no immediates */
|
#define JOF_BYTE 0 /* single bytecode, no immediates */
|
||||||
#define JOF_JUMP 1 /* signed 16-bit jump offset immediate */
|
#define JOF_JUMP 1 /* signed 16-bit jump offset immediate */
|
||||||
#define JOF_ATOM 2 /* unsigned 16-bit constant index */
|
#define JOF_ATOM 2 /* unsigned 16-bit constant pool index */
|
||||||
#define JOF_UINT16 3 /* unsigned 16-bit immediate operand */
|
#define JOF_UINT16 3 /* unsigned 16-bit immediate operand */
|
||||||
#define JOF_TABLESWITCH 4 /* table switch */
|
#define JOF_TABLESWITCH 4 /* table switch */
|
||||||
#define JOF_LOOKUPSWITCH 5 /* lookup switch */
|
#define JOF_LOOKUPSWITCH 5 /* lookup switch */
|
||||||
#define JOF_QARG 6 /* quickened get/set function argument ops */
|
#define JOF_QARG 6 /* quickened get/set function argument ops */
|
||||||
#define JOF_LOCAL 7 /* var or block-local variable */
|
#define JOF_LOCAL 7 /* var or block-local variable */
|
||||||
#define JOF_SLOTATOM 8 /* uint16 slot + constant index */
|
#define JOF_SLOTATOM 8 /* uint16 slot index + constant pool index */
|
||||||
#define JOF_JUMPX 9 /* signed 32-bit jump offset immediate */
|
#define JOF_JUMPX 9 /* signed 32-bit jump offset immediate */
|
||||||
#define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */
|
#define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */
|
||||||
#define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */
|
#define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */
|
||||||
@@ -79,11 +79,10 @@ typedef enum JSOp {
|
|||||||
#define JOF_UINT8 13 /* uint8 immediate, e.g. top 8 bits of 24-bit
|
#define JOF_UINT8 13 /* uint8 immediate, e.g. top 8 bits of 24-bit
|
||||||
atom index */
|
atom index */
|
||||||
#define JOF_INT32 14 /* int32 immediate operand */
|
#define JOF_INT32 14 /* int32 immediate operand */
|
||||||
#define JOF_OBJECT 15 /* unsigned 16-bit object index */
|
#define JOF_OBJECT 15 /* unsigned 16-bit object pool index */
|
||||||
#define JOF_SLOTOBJECT 16 /* uint16 slot index + object index */
|
#define JOF_SLOTOBJECT 16 /* uint16 slot index + object pool index */
|
||||||
#define JOF_REGEXP 17 /* unsigned 16-bit regexp index */
|
#define JOF_REGEXP 17 /* unsigned 16-bit regexp pool index */
|
||||||
#define JOF_INT8 18 /* int8 immediate operand */
|
#define JOF_INT8 18 /* int8 immediate operand */
|
||||||
#define JOF_ATOMOBJECT 19 /* uint16 constant index + object index */
|
|
||||||
#define JOF_TYPEMASK 0x001f /* mask for above immediate types */
|
#define JOF_TYPEMASK 0x001f /* mask for above immediate types */
|
||||||
|
|
||||||
#define JOF_NAME (1U<<5) /* name operation */
|
#define JOF_NAME (1U<<5) /* name operation */
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
* 17 new JSOP_NEW
|
* 17 new JSOP_NEW
|
||||||
* 18 x.y, f(), etc. JSOP_GETPROP, JSOP_CALL, etc.
|
* 18 x.y, f(), etc. JSOP_GETPROP, JSOP_CALL, etc.
|
||||||
* 19 x, null, JSOP_NAME, JSOP_NULL, etc.;
|
* 19 x, null, JSOP_NAME, JSOP_NULL, etc.;
|
||||||
* function (...) ... and JSOP_LAMBDA
|
* function (...) ... and JSOP_ANONFUNOBJ, JSOP_NAMEDFUNOBJ
|
||||||
*
|
*
|
||||||
* The push-numeric-constant operators, JSOP_ZERO, JSOP_DOUBLE, etc., have
|
* The push-numeric-constant operators, JSOP_ZERO, JSOP_DOUBLE, etc., have
|
||||||
* lower precedence than the member operators emitted for the . operator, to
|
* lower precedence than the member operators emitted for the . operator, to
|
||||||
@@ -197,11 +197,8 @@ OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL, -1, 1, 0, 0, JOF_LOOKUP
|
|||||||
OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
||||||
OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
||||||
|
|
||||||
/*
|
/* Variant of JSOP_NULL for default (global) |this| parameter pushing. */
|
||||||
* Host object extension: given 'o.item(i) = j', the left-hand side compiles
|
OPDEF(JSOP_NULLTHIS, 74, "nullthis", "nullthis", 1, 0, 1, 19, JOF_BYTE)
|
||||||
* JSOP_SETCALL, rather than JSOP_CALL.
|
|
||||||
*/
|
|
||||||
OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 3, -1, 2, 18, JOF_UINT16|JOF_SET)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits
|
* JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits
|
||||||
@@ -328,11 +325,11 @@ OPDEF(JSOP_DEFFUN, 125,"deffun", NULL, 3, 0, 0, 0, JOF_OBJECT
|
|||||||
OPDEF(JSOP_DEFCONST, 126,"defconst", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING)
|
OPDEF(JSOP_DEFCONST, 126,"defconst", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING)
|
||||||
OPDEF(JSOP_DEFVAR, 127,"defvar", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING)
|
OPDEF(JSOP_DEFVAR, 127,"defvar", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING)
|
||||||
|
|
||||||
/* Push a closure for a named or anonymous function expression. */
|
/* Auto-clone (if needed due to re-parenting) and push an anonymous function. */
|
||||||
OPDEF(JSOP_LAMBDA, 128, "lambda", NULL, 3, 0, 1, 19, JOF_OBJECT)
|
OPDEF(JSOP_ANONFUNOBJ, 128, "anonfunobj", NULL, 3, 0, 1, 19, JOF_OBJECT)
|
||||||
|
|
||||||
/* Used for named function expression self-naming, if lightweight. */
|
/* ECMA ed. 3 named function expression. */
|
||||||
OPDEF(JSOP_CALLEE, 129, "callee", NULL, 1, 0, 1, 19, JOF_BYTE)
|
OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 19, JOF_OBJECT)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Like JSOP_SETLOCAL, but specialized to avoid requiring JSOP_POP immediately
|
* Like JSOP_SETLOCAL, but specialized to avoid requiring JSOP_POP immediately
|
||||||
@@ -340,23 +337,28 @@ OPDEF(JSOP_CALLEE, 129, "callee", NULL, 1, 0, 1, 19, JOF_BYTE)
|
|||||||
*/
|
*/
|
||||||
OPDEF(JSOP_SETLOCALPOP, 130, "setlocalpop", NULL, 3, 1, 0, 3, JOF_LOCAL|JOF_NAME|JOF_SET)
|
OPDEF(JSOP_SETLOCALPOP, 130, "setlocalpop", NULL, 3, 1, 0, 3, JOF_LOCAL|JOF_NAME|JOF_SET)
|
||||||
|
|
||||||
/* Pick an element from the stack. */
|
/* Jump to target if top of stack value is of primitive type. */
|
||||||
OPDEF(JSOP_PICK, 131, "pick", NULL, 2, 0, 0, 0, JOF_UINT8)
|
OPDEF(JSOP_IFPRIMTOP, 131, "ifprimtop", NULL, 3, 1, 1, 0, JOF_JUMP|JOF_DETECTING)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Host object extension: given 'o.item(i) = j', the left-hand side compiles
|
||||||
|
* JSOP_SETCALL, rather than JSOP_CALL.
|
||||||
|
*/
|
||||||
|
OPDEF(JSOP_SETCALL, 132, "setcall", NULL, 3, -1, 2, 18, JOF_UINT16|JOF_SET)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exception handling no-op, for more economical byte-coding than SRC_TRYFIN
|
* Exception handling no-op, for more economical byte-coding than SRC_TRYFIN
|
||||||
* srcnote-annotated JSOP_NOPs and to simply stack balance handling.
|
* srcnote-annotated JSOP_NOPs and to simply stack balance handling.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_TRY, 132,"try", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_TRY, 133,"try", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
OPDEF(JSOP_FINALLY, 133,"finally", NULL, 1, 0, 2, 0, JOF_BYTE)
|
OPDEF(JSOP_FINALLY, 134,"finally", NULL, 1, 0, 2, 0, JOF_BYTE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a dynamic slot from an object known to have at least one greater than
|
* Ensure that the value on the top of the stack is an object. The one
|
||||||
* the slot index number of values at obj->dslots. The CALL variant computes
|
* argument is an error message, defined in js.msg, that takes one parameter
|
||||||
* the callee and this-object in preparation for a JSOP_CALL.
|
* (the decompilation of the primitive value).
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_GETDSLOT, 134,"getdslot", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME)
|
OPDEF(JSOP_OBJTOP, 135,"objtop", NULL, 3, 0, 0, 0, JOF_UINT16)
|
||||||
OPDEF(JSOP_CALLDSLOT, 135,"calldslot", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bytecodes that avoid making an arguments object in most cases:
|
* Bytecodes that avoid making an arguments object in most cases:
|
||||||
@@ -432,12 +434,12 @@ OPDEF(JSOP_XMLCDATA, 181,"xmlcdata", NULL, 3, 0, 1, 19, JOF_ATOM)
|
|||||||
OPDEF(JSOP_XMLCOMMENT, 182,"xmlcomment", NULL, 3, 0, 1, 19, JOF_ATOM)
|
OPDEF(JSOP_XMLCOMMENT, 182,"xmlcomment", NULL, 3, 0, 1, 19, JOF_ATOM)
|
||||||
OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 3, 1, 1, 19, JOF_ATOM)
|
OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 3, 1, 1, 19, JOF_ATOM)
|
||||||
OPDEF(JSOP_CALLPROP, 184,"callprop", NULL, 3, 1, 2, 18, JOF_ATOM|JOF_PROP|JOF_CALLOP)
|
OPDEF(JSOP_CALLPROP, 184,"callprop", NULL, 3, 1, 2, 18, JOF_ATOM|JOF_PROP|JOF_CALLOP)
|
||||||
|
OPDEF(JSOP_GETFUNNS, 185,"getfunns", NULL, 1, 0, 1, 19, JOF_BYTE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a display (free) variable from the closure's reserved slots.
|
* Get a display (free) variable from the closure's reserved slots.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_GETUPVAR, 185,"getupvar", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME)
|
OPDEF(JSOP_GETUPVAR, 186,"getupvar", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME)
|
||||||
OPDEF(JSOP_CALLUPVAR, 186,"callupvar", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP)
|
|
||||||
|
|
||||||
OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 15, JOF_BYTE|JOF_ELEM|JOF_DEL)
|
OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 15, JOF_BYTE|JOF_ELEM|JOF_DEL)
|
||||||
|
|
||||||
@@ -489,65 +491,76 @@ OPDEF(JSOP_TYPEOFEXPR, 198,"typeofexpr", NULL, 1, 1, 1, 15, JOF_BYTE|J
|
|||||||
OPDEF(JSOP_ENTERBLOCK, 199,"enterblock", NULL, 3, 0, -1, 0, JOF_OBJECT)
|
OPDEF(JSOP_ENTERBLOCK, 199,"enterblock", NULL, 3, 0, -1, 0, JOF_OBJECT)
|
||||||
OPDEF(JSOP_LEAVEBLOCK, 200,"leaveblock", NULL, 3, -1, 0, 0, JOF_UINT16)
|
OPDEF(JSOP_LEAVEBLOCK, 200,"leaveblock", NULL, 3, -1, 0, 0, JOF_UINT16)
|
||||||
|
|
||||||
/* Jump to target if top of stack value is of primitive type. */
|
/*
|
||||||
OPDEF(JSOP_IFPRIMTOP, 201,"ifprimtop", NULL, 3, 1, 1, 0, JOF_JUMP|JOF_DETECTING)
|
* Pick an element from the stack.
|
||||||
|
*/
|
||||||
|
OPDEF(JSOP_PICK, 201,"pick", NULL, 2, 0, 0, 0, JOF_UINT8)
|
||||||
|
|
||||||
/* Throws a TypeError if the value at the top of the stack is not primitive. */
|
/* Throws a TypeError if the value at the top of the stack is not primitive. */
|
||||||
OPDEF(JSOP_PRIMTOP, 202,"primtop", NULL, 1, 1, 1, 0, JOF_BYTE)
|
OPDEF(JSOP_PRIMTOP, 202, "primtop", NULL, 1, 1, 1, 0, JOF_BYTE)
|
||||||
|
|
||||||
|
OPDEF(JSOP_UNUSED203, 203,"unused203", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED204, 204,"unused204", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED205, 205,"unused205", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED206, 206,"unused206", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED207, 207,"unused207", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED208, 208,"unused208", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED209, 209,"unused209", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generator and array comprehension support.
|
* Generator and array comprehension support.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_GENERATOR, 203,"generator", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_GENERATOR, 210,"generator", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
OPDEF(JSOP_YIELD, 204,"yield", NULL, 1, 1, 1, 1, JOF_BYTE)
|
OPDEF(JSOP_YIELD, 211,"yield", NULL, 1, 1, 1, 1, JOF_BYTE)
|
||||||
OPDEF(JSOP_ARRAYPUSH, 205,"arraypush", NULL, 3, 1, 0, 3, JOF_LOCAL)
|
OPDEF(JSOP_ARRAYPUSH, 212,"arraypush", NULL, 3, 1, 0, 3, JOF_LOCAL)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the built-in function::foo namespace and push it.
|
* In the forthcoming great opcode reorg, this should go next to JSOP_GETUPVAR.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_GETFUNNS, 206,"getfunns", NULL, 1, 0, 1, 19, JOF_BYTE)
|
OPDEF(JSOP_CALLUPVAR, 213, "callupvar", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variant of JSOP_ENUMELEM for destructuring const (const [a, b] = ...).
|
* Variant of JSOP_ENUMELEM for destructuring const (const [a, b] = ...).
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_ENUMCONSTELEM, 207,"enumconstelem",NULL, 1, 3, 0, 3, JOF_BYTE|JOF_SET)
|
OPDEF(JSOP_ENUMCONSTELEM, 214,"enumconstelem",NULL, 1, 3, 0, 3, JOF_BYTE|JOF_SET)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variant of JSOP_LEAVEBLOCK has a result on the stack above the locals,
|
* Variant of JSOP_LEAVEBLOCK has a result on the stack above the locals,
|
||||||
* which must be moved down when the block pops.
|
* which must be moved down when the block pops.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_LEAVEBLOCKEXPR,208,"leaveblockexpr",NULL, 3, -1, 1, 3, JOF_UINT16)
|
OPDEF(JSOP_LEAVEBLOCKEXPR,215,"leaveblockexpr",NULL, 3, -1, 1, 3, JOF_UINT16)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optimize common JSOP_{THIS,GET{ARG,LOCAL}} -> JSOP_GETPROP cliches.
|
* Optimize common JSOP_{THIS,GET{ARG,LOCAL}} -> JSOP_GETPROP cliches.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_GETTHISPROP, 209,"getthisprop", NULL, 3, 0, 1, 18, JOF_ATOM|JOF_VARPROP)
|
OPDEF(JSOP_GETTHISPROP, 216,"getthisprop", NULL, 3, 0, 1, 18, JOF_ATOM|JOF_VARPROP)
|
||||||
OPDEF(JSOP_GETARGPROP, 210,"getargprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP)
|
OPDEF(JSOP_GETARGPROP, 217,"getargprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP)
|
||||||
OPDEF(JSOP_GETLOCALPROP, 211,"getlocalprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP)
|
OPDEF(JSOP_GETLOCALPROP, 218,"getlocalprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP)
|
||||||
|
OPDEF(JSOP_UNUSED219, 219,"unused219", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optimize atom segments 1-3. These must be followed by JSOP_RESETBASE0 after
|
* Optimize atom segments 1-3. These must be followed by JSOP_RESETBASE0 after
|
||||||
* the opcode that they prefix.
|
* the opcode that they prefix.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_INDEXBASE1, 212,"atombase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
OPDEF(JSOP_INDEXBASE1, 220,"atombase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||||
OPDEF(JSOP_INDEXBASE2, 213,"atombase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
OPDEF(JSOP_INDEXBASE2, 221,"atombase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||||
OPDEF(JSOP_INDEXBASE3, 214,"atombase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
OPDEF(JSOP_INDEXBASE3, 222,"atombase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||||
|
|
||||||
OPDEF(JSOP_CALLGVAR, 215, "callgvar", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP)
|
OPDEF(JSOP_CALLGVAR, 223, "callgvar", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP)
|
||||||
OPDEF(JSOP_CALLLOCAL, 216, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP)
|
OPDEF(JSOP_CALLLOCAL, 224, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP)
|
||||||
OPDEF(JSOP_CALLARG, 217, "callarg", NULL, 3, 0, 2, 19, JOF_QARG |JOF_NAME|JOF_CALLOP)
|
OPDEF(JSOP_CALLARG, 225, "callarg", NULL, 3, 0, 2, 19, JOF_QARG |JOF_NAME|JOF_CALLOP)
|
||||||
OPDEF(JSOP_CALLBUILTIN, 218, "callbuiltin", NULL, 3, 0, 2, 0, JOF_UINT16)
|
OPDEF(JSOP_CALLBUILTIN, 226, "callbuiltin", NULL, 3, 0, 2, 0, JOF_UINT16)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opcodes to hold 8-bit and 32-bit immediate integer operands.
|
* Opcodes to hold 8-bit and 32-bit immediate integer operands.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_INT8, 219, "int8", NULL, 2, 0, 1, 16, JOF_INT8)
|
OPDEF(JSOP_INT8, 227, "int8", NULL, 2, 0, 1, 16, JOF_INT8)
|
||||||
OPDEF(JSOP_INT32, 220, "int32", NULL, 5, 0, 1, 16, JOF_INT32)
|
OPDEF(JSOP_INT32, 228, "int32", NULL, 5, 0, 1, 16, JOF_INT32)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the value of the 'length' property from a stacked object.
|
* Get the value of the 'length' property from a stacked object.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_LENGTH, 221, "length", NULL, 1, 1, 1, 18, JOF_BYTE|JOF_PROP)
|
OPDEF(JSOP_LENGTH, 229, "length", NULL, 1, 1, 1, 18, JOF_BYTE|JOF_PROP)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a new dense array whose contents are the values provided on the
|
* Construct a new dense array whose contents are the values provided on the
|
||||||
@@ -556,27 +569,13 @@ OPDEF(JSOP_LENGTH, 221, "length", NULL, 1, 1, 1, 18, JOF_BYTE|J
|
|||||||
* bottommost value is the first value in the array; the array length is a
|
* bottommost value is the first value in the array; the array length is a
|
||||||
* 24-bit immediate operand to the instruction.
|
* 24-bit immediate operand to the instruction.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_NEWARRAY, 222, "newarray", NULL, 4, -1, 1, 19, JOF_UINT24)
|
OPDEF(JSOP_NEWARRAY, 230, "newarray", NULL, 4, -1, 1, 19, JOF_UINT24)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Push a JSVAL_HOLE value onto the stack, representing an omitted property in
|
* Push a JSVAL_HOLE value onto the stack, representing an omitted property in
|
||||||
* an array literal (e.g. property 0 in the array [, 1]). This opcode is used
|
* an array literal (e.g. property 0 in the array [, 1]). This opcode is used
|
||||||
* with the JSOP_NEWARRAY and JSOP_NEWINIT opcodes.
|
* with the JSOP_NEWARRAY and JSOP_NEWINIT opcodes.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_HOLE, 223, "hole", NULL, 1, 0, 1, 0, JOF_BYTE)
|
OPDEF(JSOP_HOLE, 231, "hole", NULL, 1, 0, 1, 0, JOF_BYTE)
|
||||||
|
|
||||||
/*
|
OPDEF(JSOP_LOOP, 232, "loop", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
* Variants of JSOP_{DEF{,LOCAL}FUN,LAMBDA} optimized for the flat closure case.
|
|
||||||
*/
|
|
||||||
OPDEF(JSOP_DEFFUN_FC, 224,"deffun_fc", NULL, 3, 0, 0, 0, JOF_OBJECT|JOF_DECLARING)
|
|
||||||
OPDEF(JSOP_DEFLOCALFUN_FC,225,"deflocalfun_fc",NULL, 5, 0, 0, 0, JOF_SLOTOBJECT|JOF_DECLARING)
|
|
||||||
OPDEF(JSOP_LAMBDA_FC, 226,"lambda_fc", NULL, 3, 0, 1, 19, JOF_OBJECT)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure that the value on the top of the stack is an object. The one
|
|
||||||
* argument is an error message, defined in js.msg, that takes one parameter
|
|
||||||
* (the decompilation of the primitive value).
|
|
||||||
*/
|
|
||||||
OPDEF(JSOP_OBJTOP, 227,"objtop", NULL, 3, 0, 0, 0, JOF_UINT16)
|
|
||||||
|
|
||||||
OPDEF(JSOP_LOOP, 228, "loop", NULL, 1, 0, 0, 0, JOF_BYTE)
|
|
||||||
|
|||||||
3963
js/src/jsparse.cpp
3963
js/src/jsparse.cpp
File diff suppressed because it is too large
Load Diff
705
js/src/jsparse.h
705
js/src/jsparse.h
@@ -46,7 +46,6 @@
|
|||||||
#include "jsversion.h"
|
#include "jsversion.h"
|
||||||
#include "jsprvtd.h"
|
#include "jsprvtd.h"
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
#include "jsatom.h"
|
|
||||||
#include "jsscan.h"
|
#include "jsscan.h"
|
||||||
|
|
||||||
JS_BEGIN_EXTERN_C
|
JS_BEGIN_EXTERN_C
|
||||||
@@ -62,25 +61,13 @@ JS_BEGIN_EXTERN_C
|
|||||||
* Label Variant Members
|
* Label Variant Members
|
||||||
* ----- ------- -------
|
* ----- ------- -------
|
||||||
* <Definitions>
|
* <Definitions>
|
||||||
* TOK_FUNCTION name pn_funbox: ptr to JSFunctionBox holding function
|
* TOK_FUNCTION func pn_funpob: JSParsedObjectBox holding function
|
||||||
* object containing arg and var properties. We
|
* object containing arg and var properties. We
|
||||||
* create the function object at parse (not emit)
|
* create the function object at parse (not emit)
|
||||||
* time to specialize arg and var bytecodes early.
|
* time to specialize arg and var bytecodes early.
|
||||||
* pn_body: TOK_UPVARS if the function's source body
|
* pn_body: TOK_LC node for function body statements
|
||||||
* depends on outer names, else TOK_ARGSBODY
|
* pn_flags: TCF_FUN_* flags (see jsemit.h) collected
|
||||||
* if formal parameters, else TOK_LC node for
|
* while parsing the function's body
|
||||||
* function body statements
|
|
||||||
* pn_cookie: static level and var index for function
|
|
||||||
* pn_dflags: PND_* definition/use flags (see below)
|
|
||||||
* pn_blockid: block id number
|
|
||||||
* TOK_ARGSBODY list list of formal parameters followed by TOK_LC node
|
|
||||||
* for function body statements as final element
|
|
||||||
* pn_count: 1 + number of formal parameters
|
|
||||||
* TOK_UPVARS nameset pn_names: lexical dependencies (JSDefinitions)
|
|
||||||
* defined in enclosing scopes, or ultimately not
|
|
||||||
* defined (free variables, either global property
|
|
||||||
* references or reference errors).
|
|
||||||
* pn_argsbody: TOK_ARGSBODY or TOK_LC node
|
|
||||||
*
|
*
|
||||||
* <Statements>
|
* <Statements>
|
||||||
* TOK_LC list pn_head: list of pn_count statements
|
* TOK_LC list pn_head: list of pn_count statements
|
||||||
@@ -99,7 +86,7 @@ JS_BEGIN_EXTERN_C
|
|||||||
* TOK_FOR binary pn_left: either
|
* TOK_FOR binary pn_left: either
|
||||||
* for/in loop: a binary TOK_IN node with
|
* for/in loop: a binary TOK_IN node with
|
||||||
* pn_left: TOK_VAR or TOK_NAME to left of 'in'
|
* pn_left: TOK_VAR or TOK_NAME to left of 'in'
|
||||||
* if TOK_VAR, its pn_xflags may have PNX_POPVAR
|
* if TOK_VAR, its pn_extra may have PNX_POPVAR
|
||||||
* and PNX_FORINVAR bits set
|
* and PNX_FORINVAR bits set
|
||||||
* pn_right: object expr to right of 'in'
|
* pn_right: object expr to right of 'in'
|
||||||
* for(;;) loop: a ternary TOK_RESERVED node with
|
* for(;;) loop: a ternary TOK_RESERVED node with
|
||||||
@@ -121,15 +108,10 @@ JS_BEGIN_EXTERN_C
|
|||||||
* TOK_BREAK name pn_atom: label or null
|
* TOK_BREAK name pn_atom: label or null
|
||||||
* TOK_CONTINUE name pn_atom: label or null
|
* TOK_CONTINUE name pn_atom: label or null
|
||||||
* TOK_WITH binary pn_left: head expr, pn_right: body
|
* TOK_WITH binary pn_left: head expr, pn_right: body
|
||||||
* TOK_VAR list pn_head: list of TOK_NAME or TOK_ASSIGN nodes
|
* TOK_VAR list pn_head: list of pn_count TOK_NAME nodes
|
||||||
* each name node has
|
* each name node has
|
||||||
* pn_used: false
|
|
||||||
* pn_atom: variable name
|
* pn_atom: variable name
|
||||||
* pn_expr: initializer or null
|
* pn_expr: initializer or null
|
||||||
* each assignment node has
|
|
||||||
* pn_left: TOK_NAME with pn_used true and
|
|
||||||
* pn_lexdef (NOT pn_expr) set
|
|
||||||
* pn_right: initializer
|
|
||||||
* TOK_RETURN unary pn_kid: return expr or null
|
* TOK_RETURN unary pn_kid: return expr or null
|
||||||
* TOK_SEMI unary pn_kid: expr or null statement
|
* TOK_SEMI unary pn_kid: expr or null statement
|
||||||
* TOK_COLON name pn_atom: label, pn_expr: labeled statement
|
* TOK_COLON name pn_atom: label, pn_expr: labeled statement
|
||||||
@@ -154,12 +136,12 @@ JS_BEGIN_EXTERN_C
|
|||||||
* TOK_SHOP binary pn_left: left-assoc SH expr, pn_right: ADD expr
|
* TOK_SHOP binary pn_left: left-assoc SH expr, pn_right: ADD expr
|
||||||
* pn_op: JSOP_LSH, JSOP_RSH, JSOP_URSH
|
* pn_op: JSOP_LSH, JSOP_RSH, JSOP_URSH
|
||||||
* TOK_PLUS, binary pn_left: left-assoc ADD expr, pn_right: MUL expr
|
* TOK_PLUS, binary pn_left: left-assoc ADD expr, pn_right: MUL expr
|
||||||
* pn_xflags: if a left-associated binary TOK_PLUS
|
* pn_extra: if a left-associated binary TOK_PLUS
|
||||||
* tree has been flattened into a list (see above
|
* tree has been flattened into a list (see above
|
||||||
* under <Expressions>), pn_xflags will contain
|
* under <Expressions>), pn_extra will contain
|
||||||
* PNX_STRCAT if at least one list element is a
|
* PNX_STRCAT if at least one list element is a
|
||||||
* string literal (TOK_STRING); if such a list has
|
* string literal (TOK_STRING); if such a list has
|
||||||
* any non-string, non-number term, pn_xflags will
|
* any non-string, non-number term, pn_extra will
|
||||||
* contain PNX_CANTFOLD.
|
* contain PNX_CANTFOLD.
|
||||||
* pn_
|
* pn_
|
||||||
* TOK_MINUS pn_op: JSOP_ADD, JSOP_SUB
|
* TOK_MINUS pn_op: JSOP_ADD, JSOP_SUB
|
||||||
@@ -182,12 +164,12 @@ JS_BEGIN_EXTERN_C
|
|||||||
* call is a MEMBER expr naming a callable object
|
* call is a MEMBER expr naming a callable object
|
||||||
* TOK_RB list pn_head: list of pn_count array element exprs
|
* TOK_RB list pn_head: list of pn_count array element exprs
|
||||||
* [,,] holes are represented by TOK_COMMA nodes
|
* [,,] holes are represented by TOK_COMMA nodes
|
||||||
* pn_xflags: PN_ENDCOMMA if extra comma at end
|
* pn_extra: PN_ENDCOMMA if extra comma at end
|
||||||
* TOK_RC list pn_head: list of pn_count TOK_COLON nodes where
|
* TOK_RC list pn_head: list of pn_count TOK_COLON nodes where
|
||||||
* each has pn_left: property id, pn_right: value
|
* each has pn_left: property id, pn_right: value
|
||||||
* var {x} = object destructuring shorthand shares
|
* var {x} = object destructuring shorthand shares
|
||||||
* PN_NAME node for x on left and right of TOK_COLON
|
* PN_NAME node for x on left and right of TOK_COLON
|
||||||
* node in TOK_RC's list, has PNX_DESTRUCT flag
|
* node in TOK_RC's list, has PNX_SHORTHAND flag
|
||||||
* TOK_DEFSHARP unary pn_num: jsint value of n in #n=
|
* TOK_DEFSHARP unary pn_num: jsint value of n in #n=
|
||||||
* pn_kid: primary function, paren, name, object or
|
* pn_kid: primary function, paren, name, object or
|
||||||
* array literal expressions
|
* array literal expressions
|
||||||
@@ -197,11 +179,7 @@ JS_BEGIN_EXTERN_C
|
|||||||
* TOK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or
|
* TOK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or
|
||||||
* JSOP_REGEXP
|
* JSOP_REGEXP
|
||||||
* TOK_REGEXP If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
|
* TOK_REGEXP If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
|
||||||
* with pn_cookie telling (staticLevel, slot) (see
|
* with pn_slot >= 0 and pn_const telling const-ness
|
||||||
* jsscript.h's UPVAR macros) and pn_dflags telling
|
|
||||||
* const-ness and static analysis results
|
|
||||||
* TOK_NAME name If pn_used, TOK_NAME uses the lexdef member instead
|
|
||||||
* of the expr member it overlays
|
|
||||||
* TOK_NUMBER dval pn_dval: double value of numeric literal
|
* TOK_NUMBER dval pn_dval: double value of numeric literal
|
||||||
* TOK_PRIMARY nullary pn_op: JSOp bytecode
|
* TOK_PRIMARY nullary pn_op: JSOp bytecode
|
||||||
*
|
*
|
||||||
@@ -264,49 +242,44 @@ JS_BEGIN_EXTERN_C
|
|||||||
* Label Variant Members
|
* Label Variant Members
|
||||||
* ----- ------- -------
|
* ----- ------- -------
|
||||||
* TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
|
* TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
|
||||||
* pn_objbox: block object in JSObjectBox holder
|
* pn_pob: block object
|
||||||
* pn_expr: block body
|
* pn_expr: block body
|
||||||
* TOK_ARRAYCOMP list pn_head: list of pn_count (1 or 2) elements
|
* TOK_ARRAYCOMP list pn_head: list of pn_count (1 or 2) elements
|
||||||
* if pn_count is 2, first element is #n=[...]
|
* if pn_count is 2, first element is #n=[...]
|
||||||
* last element is block enclosing for loop(s)
|
* last element is block enclosing for loop(s)
|
||||||
* and optionally if-guarded TOK_ARRAYPUSH
|
* and optionally if-guarded TOK_ARRAYPUSH
|
||||||
|
* pn_extra: stack slot, used during code gen
|
||||||
* TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
|
* TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
|
||||||
* pn_kid: array comprehension expression
|
* pn_kid: array comprehension expression
|
||||||
*/
|
*/
|
||||||
typedef enum JSParseNodeArity {
|
typedef enum JSParseNodeArity {
|
||||||
PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
|
PN_FUNC = -3,
|
||||||
PN_UNARY, /* one kid, plus a couple of scalars */
|
PN_LIST = -2,
|
||||||
PN_BINARY, /* two kids, plus a couple of scalars */
|
PN_TERNARY = 3,
|
||||||
PN_TERNARY, /* three kids */
|
PN_BINARY = 2,
|
||||||
PN_FUNC, /* function definition node */
|
PN_UNARY = 1,
|
||||||
PN_LIST, /* generic singly linked list */
|
PN_NAME = -1,
|
||||||
PN_NAME, /* name use or definition node */
|
PN_NULLARY = 0
|
||||||
PN_NAMESET /* JSAtomList + JSParseNode ptr */
|
|
||||||
} JSParseNodeArity;
|
} JSParseNodeArity;
|
||||||
|
|
||||||
struct JSDefinition;
|
|
||||||
|
|
||||||
struct JSParseNode {
|
struct JSParseNode {
|
||||||
uint32 pn_type:16, /* TOK_* type, see jsscan.h */
|
uint16 pn_type;
|
||||||
pn_op:8, /* see JSOp enum and jsopcode.tbl */
|
uint8 pn_op;
|
||||||
pn_arity:6, /* see JSParseNodeArity enum */
|
int8 pn_arity;
|
||||||
pn_used:1, /* name node is on a use-chain */
|
JSTokenPos pn_pos;
|
||||||
pn_defn:1; /* this node is a JSDefinition */
|
ptrdiff_t pn_offset; /* first generated bytecode offset */
|
||||||
|
|
||||||
#define PN_OP(pn) ((JSOp)(pn)->pn_op)
|
|
||||||
#define PN_TYPE(pn) ((JSTokenType)(pn)->pn_type)
|
|
||||||
|
|
||||||
JSTokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
|
|
||||||
int32 pn_offset; /* first generated bytecode offset */
|
|
||||||
JSParseNode *pn_next; /* intrinsic link in parent PN_LIST */
|
|
||||||
JSParseNode *pn_link; /* def/use link (alignment freebie) */
|
|
||||||
union {
|
union {
|
||||||
|
struct { /* TOK_FUNCTION node */
|
||||||
|
JSParsedObjectBox *funpob; /* function object */
|
||||||
|
JSParseNode *body; /* TOK_LC list of statements */
|
||||||
|
uint16 flags; /* accumulated tree context flags */
|
||||||
|
uint32 index; /* emitter's index */
|
||||||
|
} func;
|
||||||
struct { /* list of next-linked nodes */
|
struct { /* list of next-linked nodes */
|
||||||
JSParseNode *head; /* first node in list */
|
JSParseNode *head; /* first node in list */
|
||||||
JSParseNode **tail; /* ptr to ptr to last node in list */
|
JSParseNode **tail; /* ptr to ptr to last node in list */
|
||||||
uint32 count; /* number of nodes in list */
|
uint32 count; /* number of nodes in list */
|
||||||
uint32 xflags:12, /* extra flags, see below */
|
uint32 extra; /* extra flags, see below */
|
||||||
blockid:20; /* see name variant below */
|
|
||||||
} list;
|
} list;
|
||||||
struct { /* ternary: if, for(;;), ?: */
|
struct { /* ternary: if, for(;;), ?: */
|
||||||
JSParseNode *kid1; /* condition, discriminant, etc. */
|
JSParseNode *kid1; /* condition, discriminant, etc. */
|
||||||
@@ -325,44 +298,36 @@ struct JSParseNode {
|
|||||||
JSBool hidden; /* hidden genexp-induced JSOP_YIELD */
|
JSBool hidden; /* hidden genexp-induced JSOP_YIELD */
|
||||||
} unary;
|
} unary;
|
||||||
struct { /* name, labeled statement, etc. */
|
struct { /* name, labeled statement, etc. */
|
||||||
union {
|
JSAtom *atom; /* name or label atom, null if slot */
|
||||||
JSAtom *atom; /* lexical name or label atom */
|
JSParseNode *expr; /* object or initializer */
|
||||||
JSFunctionBox *funbox; /* function object */
|
jsint slot; /* -1 or arg or local var slot */
|
||||||
JSObjectBox *objbox; /* block or regexp object */
|
JSBool isconst; /* true for const names */
|
||||||
};
|
|
||||||
union {
|
|
||||||
JSParseNode *expr; /* function body, var initializer, or
|
|
||||||
base object of TOK_DOT */
|
|
||||||
JSDefinition *lexdef; /* lexical definition for this use */
|
|
||||||
};
|
|
||||||
uint32 cookie; /* upvar cookie with absolute frame
|
|
||||||
level (not relative skip), possibly
|
|
||||||
in current frame */
|
|
||||||
uint32 dflags:12, /* definition/use flags, see below */
|
|
||||||
blockid:20; /* block number, for subset dominance
|
|
||||||
computation */
|
|
||||||
} name;
|
} name;
|
||||||
struct { /* lexical dependencies + sub-tree */
|
struct { /* lexical scope. */
|
||||||
JSAtomSet names; /* set of names with JSDefinitions */
|
JSParsedObjectBox *pob; /* block object */
|
||||||
JSParseNode *tree; /* sub-tree containing name uses */
|
JSParseNode *expr; /* object or initializer */
|
||||||
} nameset;
|
jsint slot; /* -1 or arg or local var slot */
|
||||||
struct { /* PN_NULLARY variant for E4X */
|
} lexical;
|
||||||
|
struct {
|
||||||
JSAtom *atom; /* first atom in pair */
|
JSAtom *atom; /* first atom in pair */
|
||||||
JSAtom *atom2; /* second atom in pair or null */
|
JSAtom *atom2; /* second atom in pair or null */
|
||||||
} apair;
|
} apair;
|
||||||
|
struct { /* object literal */
|
||||||
|
JSParsedObjectBox *pob;
|
||||||
|
} object;
|
||||||
jsdouble dval; /* aligned numeric literal value */
|
jsdouble dval; /* aligned numeric literal value */
|
||||||
} pn_u;
|
} pn_u;
|
||||||
|
JSParseNode *pn_next; /* to align dval and pn_u on RISCs */
|
||||||
|
};
|
||||||
|
|
||||||
#define pn_funbox pn_u.name.funbox
|
#define pn_funpob pn_u.func.funpob
|
||||||
#define pn_body pn_u.name.expr
|
#define pn_body pn_u.func.body
|
||||||
#define pn_cookie pn_u.name.cookie
|
#define pn_flags pn_u.func.flags
|
||||||
#define pn_dflags pn_u.name.dflags
|
#define pn_index pn_u.func.index
|
||||||
#define pn_blockid pn_u.name.blockid
|
|
||||||
#define pn_index pn_u.name.blockid /* reuse as object table index */
|
|
||||||
#define pn_head pn_u.list.head
|
#define pn_head pn_u.list.head
|
||||||
#define pn_tail pn_u.list.tail
|
#define pn_tail pn_u.list.tail
|
||||||
#define pn_count pn_u.list.count
|
#define pn_count pn_u.list.count
|
||||||
#define pn_xflags pn_u.list.xflags
|
#define pn_extra pn_u.list.extra
|
||||||
#define pn_kid1 pn_u.ternary.kid1
|
#define pn_kid1 pn_u.ternary.kid1
|
||||||
#define pn_kid2 pn_u.ternary.kid2
|
#define pn_kid2 pn_u.ternary.kid2
|
||||||
#define pn_kid3 pn_u.ternary.kid3
|
#define pn_kid3 pn_u.ternary.kid3
|
||||||
@@ -374,50 +339,14 @@ struct JSParseNode {
|
|||||||
#define pn_num pn_u.unary.num
|
#define pn_num pn_u.unary.num
|
||||||
#define pn_hidden pn_u.unary.hidden
|
#define pn_hidden pn_u.unary.hidden
|
||||||
#define pn_atom pn_u.name.atom
|
#define pn_atom pn_u.name.atom
|
||||||
#define pn_objbox pn_u.name.objbox
|
|
||||||
#define pn_expr pn_u.name.expr
|
#define pn_expr pn_u.name.expr
|
||||||
#define pn_lexdef pn_u.name.lexdef
|
#define pn_slot pn_u.name.slot
|
||||||
#define pn_names pn_u.nameset.names
|
#define pn_const pn_u.name.isconst
|
||||||
#define pn_tree pn_u.nameset.tree
|
|
||||||
#define pn_dval pn_u.dval
|
#define pn_dval pn_u.dval
|
||||||
#define pn_atom2 pn_u.apair.atom2
|
#define pn_atom2 pn_u.apair.atom2
|
||||||
|
#define pn_pob pn_u.object.pob
|
||||||
|
|
||||||
/*
|
/* PN_LIST pn_extra flags. */
|
||||||
* The pn_expr and lexdef members are arms of an unsafe union. Unless you
|
|
||||||
* know exactly what you're doing, use only the following methods to access
|
|
||||||
* them. For less overhead and assertions for protection, use pn->expr()
|
|
||||||
* and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef().
|
|
||||||
*/
|
|
||||||
JSParseNode *expr() const {
|
|
||||||
JS_ASSERT(!pn_used);
|
|
||||||
JS_ASSERT(pn_arity == PN_NAME || pn_arity == PN_FUNC);
|
|
||||||
return pn_expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSDefinition *lexdef() const {
|
|
||||||
JS_ASSERT(pn_used);
|
|
||||||
JS_ASSERT(pn_arity == PN_NAME);
|
|
||||||
return pn_lexdef;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSParseNode *maybeExpr() { return pn_used ? NULL : expr(); }
|
|
||||||
JSDefinition *maybeLexDef() { return pn_used ? lexdef() : NULL; }
|
|
||||||
|
|
||||||
/* PN_FUNC and PN_NAME pn_dflags bits. */
|
|
||||||
#define PND_LET 0x01 /* let (block-scoped) binding */
|
|
||||||
#define PND_CONST 0x02 /* const binding (orthogonal to let) */
|
|
||||||
#define PND_INITIALIZED 0x04 /* initialized declaration */
|
|
||||||
#define PND_ASSIGNED 0x08 /* set if ever LHS of assignment */
|
|
||||||
#define PND_TOPLEVEL 0x10 /* function at top of body or prog */
|
|
||||||
#define PND_BLOCKCHILD 0x20 /* use or def is direct block child */
|
|
||||||
#define PND_FORWARD 0x40 /* forward referenced definition */
|
|
||||||
#define PND_PLACEHOLDER 0x80 /* placeholder definition for lexdep */
|
|
||||||
#define PND_FUNARG 0x100 /* downward or upward funarg usage */
|
|
||||||
#define PND_BOUND 0x200 /* bound to a stack or global slot */
|
|
||||||
#define PND_GVAR 0x400 /* gvar binding, can't close over
|
|
||||||
because it could be deleted */
|
|
||||||
|
|
||||||
/* PN_LIST pn_xflags bits. */
|
|
||||||
#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */
|
#define PNX_STRCAT 0x01 /* TOK_PLUS list has string term */
|
||||||
#define PNX_CANTFOLD 0x02 /* TOK_PLUS list has unfoldable term */
|
#define PNX_CANTFOLD 0x02 /* TOK_PLUS list has unfoldable term */
|
||||||
#define PNX_POPVAR 0x04 /* TOK_VAR last result needs popping */
|
#define PNX_POPVAR 0x04 /* TOK_VAR last result needs popping */
|
||||||
@@ -429,435 +358,151 @@ struct JSParseNode {
|
|||||||
#define PNX_NEEDBRACES 0x80 /* braces necessary due to closure */
|
#define PNX_NEEDBRACES 0x80 /* braces necessary due to closure */
|
||||||
#define PNX_FUNCDEFS 0x100 /* contains top-level function
|
#define PNX_FUNCDEFS 0x100 /* contains top-level function
|
||||||
statements */
|
statements */
|
||||||
#define PNX_DESTRUCT 0x200 /* destructuring special cases:
|
#define PNX_SHORTHAND 0x200 /* shorthand syntax used, at present
|
||||||
1. shorthand syntax used, at present
|
object destructuring ({x,y}) only */
|
||||||
object destructuring ({x,y}) only;
|
#define PNX_DESTRARGS 0x400 /* the first child is node defining
|
||||||
2. the first child of function body
|
destructuring arguments */
|
||||||
is code evaluating destructuring
|
|
||||||
arguments */
|
|
||||||
|
|
||||||
uintN frameLevel() const {
|
|
||||||
JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
|
|
||||||
return UPVAR_FRAME_SKIP(pn_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintN frameSlot() const {
|
|
||||||
JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
|
|
||||||
return UPVAR_FRAME_SLOT(pn_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool test(uintN flag) const {
|
|
||||||
JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
|
|
||||||
return !!(pn_dflags & flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLet() const { return test(PND_LET); }
|
|
||||||
bool isConst() const { return test(PND_CONST); }
|
|
||||||
bool isInitialized() const { return test(PND_INITIALIZED); }
|
|
||||||
bool isTopLevel() const { return test(PND_TOPLEVEL); }
|
|
||||||
bool isBlockChild() const { return test(PND_BLOCKCHILD); }
|
|
||||||
bool isForward() const { return test(PND_FORWARD); }
|
|
||||||
bool isPlaceholder() const { return test(PND_PLACEHOLDER); }
|
|
||||||
|
|
||||||
/* Defined below, see after struct JSDefinition. */
|
|
||||||
bool isAssigned() const;
|
|
||||||
bool isFunArg() const;
|
|
||||||
|
|
||||||
void become(JSParseNode *pn2);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/* True if pn is a parsenode representing a literal constant. */
|
|
||||||
bool isLiteral() const {
|
|
||||||
return PN_TYPE(this) == TOK_NUMBER ||
|
|
||||||
PN_TYPE(this) == TOK_STRING ||
|
|
||||||
(PN_TYPE(this) == TOK_PRIMARY && PN_OP(this) != JSOP_THIS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute a pointer to the last element in a singly-linked list. NB: list
|
|
||||||
* must be non-empty for correct PN_LAST usage -- this is asserted!
|
|
||||||
*/
|
|
||||||
JSParseNode *last() const {
|
|
||||||
JS_ASSERT(pn_arity == PN_LIST);
|
|
||||||
JS_ASSERT(pn_count != 0);
|
|
||||||
return (JSParseNode *)((char *)pn_tail - offsetof(JSParseNode, pn_next));
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeEmpty() {
|
|
||||||
JS_ASSERT(pn_arity == PN_LIST);
|
|
||||||
pn_head = NULL;
|
|
||||||
pn_tail = &pn_head;
|
|
||||||
pn_count = 0;
|
|
||||||
pn_xflags = 0;
|
|
||||||
pn_blockid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initList(JSParseNode *pn) {
|
|
||||||
JS_ASSERT(pn_arity == PN_LIST);
|
|
||||||
pn_head = pn;
|
|
||||||
pn_tail = &pn->pn_next;
|
|
||||||
pn_count = 1;
|
|
||||||
pn_xflags = 0;
|
|
||||||
pn_blockid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(JSParseNode *pn) {
|
|
||||||
JS_ASSERT(pn_arity == PN_LIST);
|
|
||||||
*pn_tail = pn;
|
|
||||||
pn_tail = &pn->pn_next;
|
|
||||||
pn_count++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSDefinition is a degenerate subtype of the PN_FUNC and PN_NAME variants of
|
* Move pn2 into pn, preserving pn->pn_pos and pn->pn_offset and handing off
|
||||||
* JSParseNode, allocated only for function, var, const, and let declarations
|
* any kids in pn2->pn_u, by clearing pn2.
|
||||||
* that define truly lexical bindings. This means that a child of a TOK_VAR
|
|
||||||
* list may be a JSDefinition instead of a JSParseNode. The pn_defn bit is set
|
|
||||||
* for all JSDefinitions, clear otherwise.
|
|
||||||
*
|
|
||||||
* Note that not all var declarations are definitions: JS allows multiple var
|
|
||||||
* declarations in a function or script, but only the first creates the hoisted
|
|
||||||
* binding. JS programmers do redeclare variables for good refactoring reasons,
|
|
||||||
* for example:
|
|
||||||
*
|
|
||||||
* function foo() {
|
|
||||||
* ...
|
|
||||||
* for (var i ...) ...;
|
|
||||||
* ...
|
|
||||||
* for (var i ...) ...;
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Not all definitions bind lexical variables, alas. In global and eval code
|
|
||||||
* var may re-declare a pre-existing property having any attributes, with or
|
|
||||||
* without JSPROP_PERMANENT. In eval code, indeed, ECMA-262 Editions 1 through
|
|
||||||
* 3 require function and var to bind deletable bindings. Global vars thus are
|
|
||||||
* properties of the global object, so they can be aliased even if they can't
|
|
||||||
* be deleted.
|
|
||||||
*
|
|
||||||
* Only bindings within function code may be treated as lexical, of course with
|
|
||||||
* the caveat that hoisting means use before initialization is allowed. We deal
|
|
||||||
* with use before declaration in one pass as follows (error checking elided):
|
|
||||||
*
|
|
||||||
* for (each use of unqualified name x in parse order) {
|
|
||||||
* if (this use of x is a declaration) {
|
|
||||||
* if (x in tc->decls) { // redeclaring
|
|
||||||
* pn = allocate a PN_NAME JSParseNode;
|
|
||||||
* } else { // defining
|
|
||||||
* dn = lookup x in tc->lexdeps;
|
|
||||||
* if (dn) { // use before def
|
|
||||||
* remove x from tc->lexdeps;
|
|
||||||
* } else { // def before use
|
|
||||||
* dn = allocate a PN_NAME JSDefinition;
|
|
||||||
* map x to dn via tc->decls;
|
|
||||||
* }
|
|
||||||
* pn = dn;
|
|
||||||
* }
|
|
||||||
* insert pn into its parent TOK_VAR list;
|
|
||||||
* } else {
|
|
||||||
* pn = allocate a JSParseNode for this reference to x;
|
|
||||||
* dn = lookup x in tc's lexical scope chain;
|
|
||||||
* if (!dn) {
|
|
||||||
* dn = lookup x in tc->lexdeps;
|
|
||||||
* if (!dn) {
|
|
||||||
* dn = pre-allocate a JSDefinition for x;
|
|
||||||
* map x to dn in tc->lexdeps;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* append pn to dn's use chain;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* See jsemit.h for JSTreeContext and its top*Stmt, decls, and lexdeps members.
|
|
||||||
*
|
|
||||||
* Notes:
|
|
||||||
*
|
|
||||||
* 0. To avoid bloating JSParseNode, we steal a bit from pn_arity for pn_defn
|
|
||||||
* and set it on a JSParseNode instead of allocating a JSDefinition.
|
|
||||||
*
|
|
||||||
* 1. Due to hoisting, a definition cannot be eliminated even if its "Variable
|
|
||||||
* statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in
|
|
||||||
* jsparse.cpp will not recycle a node whose pn_defn bit is set.
|
|
||||||
*
|
|
||||||
* 2. "lookup x in tc's lexical scope chain" gives up on def/use chaining if a
|
|
||||||
* with statement is found along the the scope chain, which includes tc,
|
|
||||||
* tc->parent, etc. Thus we eagerly connect an inner function's use of an
|
|
||||||
* outer's var x if the var x was parsed before the inner function.
|
|
||||||
*
|
|
||||||
* 3. A use may be eliminated as dead by the constant folder, which therefore
|
|
||||||
* must remove the dead name node from its singly-linked use chain, which
|
|
||||||
* would mean hashing to find the definition node and searching to update
|
|
||||||
* the pn_link pointing at the use to be removed. This is costly, so as for
|
|
||||||
* dead definitions, we do not recycle dead pn_used nodes.
|
|
||||||
*
|
|
||||||
* At the end of parsing a function body or global or eval program, tc->lexdeps
|
|
||||||
* holds the lexical dependencies of the parsed unit. The name to def/use chain
|
|
||||||
* mappings are then merged into the parent tc->lexdeps.
|
|
||||||
*
|
|
||||||
* Thus if a later var x is parsed in the outer function satisfying an earlier
|
|
||||||
* inner function's use of x, we will remove dn from tc->lexdeps and re-use it
|
|
||||||
* as the new definition node in the outer function's parse tree.
|
|
||||||
*
|
|
||||||
* When the compiler unwinds from the outermost tc, tc->lexdeps contains the
|
|
||||||
* definition nodes with use chains for all free variables. These are either
|
|
||||||
* global variables or reference errors.
|
|
||||||
*
|
|
||||||
* We analyze whether a binding is initialized, whether the bound names is ever
|
|
||||||
* assigned apart from its initializer, and if the bound name definition or use
|
|
||||||
* is in a direct child of a block. These PND_* flags allow a subset dominance
|
|
||||||
* computation telling whether an initialized var dominates its uses. An inner
|
|
||||||
* function using only such outer vars (and formal parameters) can be optimized
|
|
||||||
* into a flat closure. See JSOP_{GET,CALL}DSLOT.
|
|
||||||
*
|
|
||||||
* Another important subset dominance relation: ... { var x = ...; ... x ... }
|
|
||||||
* where x is not assigned after initialization and not used outside the block.
|
|
||||||
* This style is common in the absence of 'let'. Even though the var x is not
|
|
||||||
* at top level, we can tell its initialization dominates all uses cheaply,
|
|
||||||
* because the above one-pass algorithm sees the definition before any uses,
|
|
||||||
* and because all uses are contained in the same block as the definition.
|
|
||||||
*
|
|
||||||
* We also analyze function uses to flag upward/downward funargs, optimizing
|
|
||||||
* Algol-like (not passed as funargs, only ever called) lightweight functions
|
|
||||||
* using cx->display. See JSOP_{GET,CALL}UPVAR.
|
|
||||||
*
|
|
||||||
* This means that closure optimizations may be frustrated by with, eval, or
|
|
||||||
* assignment to an outer var. Such hard cases require heavyweight functions
|
|
||||||
* and JSOP_NAME, etc.
|
|
||||||
*/
|
*/
|
||||||
#define dn_uses pn_link
|
#define PN_MOVE_NODE(pn, pn2) \
|
||||||
|
JS_BEGIN_MACRO \
|
||||||
|
(pn)->pn_type = (pn2)->pn_type; \
|
||||||
|
(pn)->pn_op = (pn2)->pn_op; \
|
||||||
|
(pn)->pn_arity = (pn2)->pn_arity; \
|
||||||
|
(pn)->pn_u = (pn2)->pn_u; \
|
||||||
|
PN_CLEAR_NODE(pn2); \
|
||||||
|
JS_END_MACRO
|
||||||
|
|
||||||
struct JSDefinition : public JSParseNode
|
#define PN_CLEAR_NODE(pn) \
|
||||||
{
|
JS_BEGIN_MACRO \
|
||||||
/*
|
(pn)->pn_type = TOK_EOF; \
|
||||||
* We store definition pointers in PN_NAMESET JSAtomLists in the AST, but
|
(pn)->pn_op = JSOP_NOP; \
|
||||||
* due to redefinition these nodes may become uses of other definitions.
|
(pn)->pn_arity = PN_NULLARY; \
|
||||||
* This is unusual, so we simply chase the pn_lexdef link to find the final
|
JS_END_MACRO
|
||||||
* definition node. See methods called from JSCompiler::analyzeFunctions.
|
|
||||||
*
|
|
||||||
* FIXME: MakeAssignment mutates for want of a parent link...
|
|
||||||
*/
|
|
||||||
JSDefinition *resolve() {
|
|
||||||
JSParseNode *pn = this;
|
|
||||||
while (!pn->pn_defn) {
|
|
||||||
if (pn->pn_type == TOK_ASSIGN) {
|
|
||||||
pn = pn->pn_left;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pn = pn->lexdef();
|
|
||||||
}
|
|
||||||
return (JSDefinition *) pn;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool test(uintN flag) const {
|
/* True if pn is a parsenode representing a literal constant. */
|
||||||
JS_ASSERT(pn_defn);
|
#define PN_IS_CONSTANT(pn) \
|
||||||
if (pn_dflags & flag)
|
((pn)->pn_type == TOK_NUMBER || \
|
||||||
return true;
|
(pn)->pn_type == TOK_STRING || \
|
||||||
#ifdef DEBUG
|
((pn)->pn_type == TOK_PRIMARY && (pn)->pn_op != JSOP_THIS))
|
||||||
for (JSParseNode *pn = dn_uses; pn; pn = pn->pn_link) {
|
|
||||||
JS_ASSERT(!pn->pn_defn);
|
|
||||||
JS_ASSERT(!(pn->pn_dflags & flag));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isAssigned() const {
|
#define PN_OP(pn) ((JSOp)(pn)->pn_op)
|
||||||
return test(PND_ASSIGNED);
|
#define PN_TYPE(pn) ((JSTokenType)(pn)->pn_type)
|
||||||
}
|
|
||||||
|
|
||||||
bool isFunArg() const {
|
|
||||||
return test(PND_FUNARG);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFreeVar() const {
|
|
||||||
JS_ASSERT(pn_defn);
|
|
||||||
return pn_cookie == FREE_UPVAR_COOKIE || test(PND_GVAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grr, windows.h or something under it #defines CONST...
|
|
||||||
#ifdef CONST
|
|
||||||
# undef CONST
|
|
||||||
#endif
|
|
||||||
enum Kind { VAR, CONST, LET, FUNCTION, ARG, UNKNOWN };
|
|
||||||
|
|
||||||
bool isBindingForm() { return int(kind()) <= int(LET); }
|
|
||||||
|
|
||||||
static const char *kindString(Kind kind);
|
|
||||||
|
|
||||||
Kind kind() {
|
|
||||||
if (PN_TYPE(this) == TOK_FUNCTION)
|
|
||||||
return FUNCTION;
|
|
||||||
JS_ASSERT(PN_TYPE(this) == TOK_NAME);
|
|
||||||
if (PN_OP(this) == JSOP_NOP)
|
|
||||||
return UNKNOWN;
|
|
||||||
if (PN_OP(this) == JSOP_GETARG)
|
|
||||||
return ARG;
|
|
||||||
if (isConst())
|
|
||||||
return CONST;
|
|
||||||
if (isLet())
|
|
||||||
return LET;
|
|
||||||
return VAR;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These two are overridden by JSDefinition and we cannot afford virtual
|
* Compute a pointer to the last JSParseNode element in a singly-linked list.
|
||||||
* methods -- so we use the mighty 'if' statement!
|
* NB: list must be non-empty for correct PN_LAST usage!
|
||||||
*/
|
*/
|
||||||
inline bool
|
#define PN_LAST(list) \
|
||||||
JSParseNode::isAssigned() const
|
((JSParseNode *)((char *)(list)->pn_tail - offsetof(JSParseNode, pn_next)))
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (pn_defn)
|
|
||||||
return ((JSDefinition *)this)->isAssigned();
|
|
||||||
#endif
|
|
||||||
return test(PND_ASSIGNED);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
#define PN_INIT_LIST(list) \
|
||||||
JSParseNode::isFunArg() const
|
JS_BEGIN_MACRO \
|
||||||
{
|
(list)->pn_head = NULL; \
|
||||||
#ifdef DEBUG
|
(list)->pn_tail = &(list)->pn_head; \
|
||||||
if (pn_defn)
|
(list)->pn_count = (list)->pn_extra = 0; \
|
||||||
return ((JSDefinition *)this)->isFunArg();
|
JS_END_MACRO
|
||||||
#endif
|
|
||||||
return test(PND_FUNARG);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct JSObjectBox {
|
#define PN_INIT_LIST_1(list, pn) \
|
||||||
JSObjectBox *traceLink;
|
JS_BEGIN_MACRO \
|
||||||
JSObjectBox *emitLink;
|
(list)->pn_head = (pn); \
|
||||||
|
(list)->pn_tail = &(pn)->pn_next; \
|
||||||
|
(list)->pn_count = 1; \
|
||||||
|
(list)->pn_extra = 0; \
|
||||||
|
JS_END_MACRO
|
||||||
|
|
||||||
|
#define PN_APPEND(list, pn) \
|
||||||
|
JS_BEGIN_MACRO \
|
||||||
|
*(list)->pn_tail = (pn); \
|
||||||
|
(list)->pn_tail = &(pn)->pn_next; \
|
||||||
|
(list)->pn_count++; \
|
||||||
|
JS_END_MACRO
|
||||||
|
|
||||||
|
struct JSParsedObjectBox {
|
||||||
|
JSParsedObjectBox *traceLink;
|
||||||
|
JSParsedObjectBox *emitLink;
|
||||||
JSObject *object;
|
JSObject *object;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JSFunctionBox : public JSObjectBox
|
struct JSParseContext {
|
||||||
{
|
|
||||||
JSParseNode *node;
|
|
||||||
JSFunctionBox *siblings;
|
|
||||||
JSFunctionBox *kids;
|
|
||||||
JSFunctionBox *parent;
|
|
||||||
uint16 level;
|
|
||||||
uint16 tcflags;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct JSFunctionBoxQueue {
|
|
||||||
JSFunctionBox **vector;
|
|
||||||
size_t head, tail, length;
|
|
||||||
|
|
||||||
JSFunctionBoxQueue(uint32 count)
|
|
||||||
: vector(new JSFunctionBox*[count]), head(0), tail(0), length(count) { }
|
|
||||||
|
|
||||||
~JSFunctionBoxQueue() { delete[] vector; }
|
|
||||||
|
|
||||||
void push(JSFunctionBox *funbox) {
|
|
||||||
if (head == length)
|
|
||||||
head = 0;
|
|
||||||
vector[head++] = funbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSFunctionBox *pull() {
|
|
||||||
if (tail == head)
|
|
||||||
return NULL;
|
|
||||||
if (tail == length)
|
|
||||||
tail = 0;
|
|
||||||
JS_ASSERT(tail != head);
|
|
||||||
return vector[tail++];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NUM_TEMP_FREELISTS 6U /* 32 to 2048 byte size classes (32 bit) */
|
|
||||||
|
|
||||||
struct JSCompiler {
|
|
||||||
JSContext *context;
|
|
||||||
JSAtomListElement *aleFreeList;
|
|
||||||
void *tempFreeList[NUM_TEMP_FREELISTS];
|
|
||||||
JSTokenStream tokenStream;
|
JSTokenStream tokenStream;
|
||||||
void *tempPoolMark; /* initial JSContext.tempPool mark */
|
void *tempPoolMark; /* initial JSContext.tempPool mark */
|
||||||
JSPrincipals *principals; /* principals associated with source */
|
JSPrincipals *principals; /* principals associated with source */
|
||||||
JSStackFrame *callerFrame; /* scripted caller frame for eval and dbgapi */
|
JSStackFrame *callerFrame; /* scripted caller frame for eval and
|
||||||
JSParseNode *nodeList; /* list of recyclable parse-node structs */
|
debug scripts */
|
||||||
uint32 functionCount; /* number of functions in current unit */
|
JSParseNode *nodeList; /* list of recyclable parse-node
|
||||||
JSObjectBox *traceListHead; /* list of parsed object for GC tracing */
|
structs */
|
||||||
|
JSParsedObjectBox *traceListHead; /* list of parsed object for GC
|
||||||
|
tracing */
|
||||||
JSTempValueRooter tempRoot; /* root to trace traceListHead */
|
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)
|
|
||||||
{
|
|
||||||
memset(tempFreeList, 0, sizeof tempFreeList);
|
|
||||||
setPrincipals(prin);
|
|
||||||
JS_ASSERT_IF(cfp, cfp->script);
|
|
||||||
}
|
|
||||||
|
|
||||||
~JSCompiler();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize a compiler. Parameters are passed on to js_InitTokenStream.
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
bool init(const jschar *base, size_t length,
|
|
||||||
FILE *fp, const char *filename, uintN lineno);
|
|
||||||
|
|
||||||
void setPrincipals(JSPrincipals *prin);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse a top-level JS script.
|
|
||||||
*/
|
|
||||||
JSParseNode *parse(JSObject *chain);
|
|
||||||
|
|
||||||
#if JS_HAS_XML_SUPPORT
|
|
||||||
JSParseNode *parseXMLText(JSObject *chain, bool allowList);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate a new parsed object or function container from cx->tempPool.
|
|
||||||
*/
|
|
||||||
JSObjectBox *newObjectBox(JSObject *obj);
|
|
||||||
|
|
||||||
JSFunctionBox *newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a new function object given tree context (tc), optional name
|
|
||||||
* (atom may be null) and lambda flag (JSFUN_LAMBDA or 0).
|
|
||||||
*/
|
|
||||||
JSFunction *newFunction(JSTreeContext *tc, JSAtom *atom, uintN lambda);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Analyze the tree of functions nested within a single compilation unit,
|
|
||||||
* starting at funbox, recursively walking its kids, then following its
|
|
||||||
* siblings, their kids, etc.
|
|
||||||
*/
|
|
||||||
void analyzeFunctions(JSFunctionBox *funbox, uint16& tcflags);
|
|
||||||
void markFunArgs(JSFunctionBox *funbox, uintN tcflags);
|
|
||||||
void setFunctionKinds(JSFunctionBox *funbox, uint16& tcflags);
|
|
||||||
|
|
||||||
void trace(JSTracer *trc);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
|
|
||||||
const jschar *chars, size_t length,
|
|
||||||
const char *filename, uintN lineno);
|
|
||||||
|
|
||||||
static JSScript *
|
|
||||||
compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
|
|
||||||
JSPrincipals *principals, uint32 tcflags,
|
|
||||||
const jschar *chars, size_t length,
|
|
||||||
FILE *file, const char *filename, uintN lineno,
|
|
||||||
JSString *source = NULL);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convenience macro to access JSCompiler.tokenStream as a pointer.
|
* Convenience macro to access JSParseContext.tokenStream as a pointer.
|
||||||
*/
|
*/
|
||||||
#define TS(jsc) (&(jsc)->tokenStream)
|
#define TS(pc) (&(pc)->tokenStream)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a top-level JS script.
|
||||||
|
*/
|
||||||
|
extern JSParseNode *
|
||||||
|
js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc);
|
||||||
|
|
||||||
|
extern JSScript *
|
||||||
|
js_CompileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
|
||||||
|
JSPrincipals *principals, uint32 tcflags,
|
||||||
|
const jschar *chars, size_t length,
|
||||||
|
FILE *file, const char *filename, uintN lineno,
|
||||||
|
JSString *source = NULL);
|
||||||
|
|
||||||
|
extern JSBool
|
||||||
|
js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
|
||||||
|
const jschar *chars, size_t length,
|
||||||
|
const char *filename, uintN lineno);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc,
|
js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc,
|
||||||
bool inCond = false);
|
bool inCond = false);
|
||||||
|
|
||||||
|
#if JS_HAS_XML_SUPPORT
|
||||||
|
JS_FRIEND_API(JSParseNode *)
|
||||||
|
js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc,
|
||||||
|
JSBool allowList);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a parse context. All parameters after pc are passed to
|
||||||
|
* js_InitTokenStream.
|
||||||
|
*
|
||||||
|
* The parse context 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 js_FinishParseContext.
|
||||||
|
*/
|
||||||
|
extern JSBool
|
||||||
|
js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals,
|
||||||
|
JSStackFrame *callerFrame,
|
||||||
|
const jschar *base, size_t length, FILE *fp,
|
||||||
|
const char *filename, uintN lineno);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
js_FinishParseContext(JSContext *cx, JSParseContext *pc);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
js_InitCompilePrincipals(JSContext *cx, JSParseContext *pc,
|
||||||
|
JSPrincipals *principals);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a new parseed object node from cx->tempPool.
|
||||||
|
*/
|
||||||
|
extern JSParsedObjectBox *
|
||||||
|
js_NewParsedObjectBox(JSContext *cx, JSParseContext *pc, JSObject *obj);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
js_TraceParseContext(JSTracer *trc, JSParseContext *pc);
|
||||||
|
|
||||||
JS_END_EXTERN_C
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
#endif /* jsparse_h___ */
|
#endif /* jsparse_h___ */
|
||||||
|
|||||||
@@ -94,9 +94,8 @@ typedef struct JSCodeGenerator JSCodeGenerator;
|
|||||||
typedef struct JSGCThing JSGCThing;
|
typedef struct JSGCThing JSGCThing;
|
||||||
typedef struct JSGenerator JSGenerator;
|
typedef struct JSGenerator JSGenerator;
|
||||||
typedef struct JSNativeEnumerator JSNativeEnumerator;
|
typedef struct JSNativeEnumerator JSNativeEnumerator;
|
||||||
typedef struct JSCompiler JSCompiler;
|
typedef struct JSParseContext JSParseContext;
|
||||||
typedef struct JSFunctionBox JSFunctionBox;
|
typedef struct JSParsedObjectBox JSParsedObjectBox;
|
||||||
typedef struct JSObjectBox JSObjectBox;
|
|
||||||
typedef struct JSParseNode JSParseNode;
|
typedef struct JSParseNode JSParseNode;
|
||||||
typedef struct JSPropCacheEntry JSPropCacheEntry;
|
typedef struct JSPropCacheEntry JSPropCacheEntry;
|
||||||
typedef struct JSProperty JSProperty;
|
typedef struct JSProperty JSProperty;
|
||||||
@@ -244,7 +243,7 @@ typedef union JSTempValueUnion {
|
|||||||
JSTempValueTrace trace;
|
JSTempValueTrace trace;
|
||||||
JSScopeProperty *sprop;
|
JSScopeProperty *sprop;
|
||||||
JSWeakRoots *weakRoots;
|
JSWeakRoots *weakRoots;
|
||||||
JSCompiler *compiler;
|
JSParseContext *parseContext;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
jsval *array;
|
jsval *array;
|
||||||
} JSTempValueUnion;
|
} JSTempValueUnion;
|
||||||
|
|||||||
@@ -137,10 +137,6 @@ typedef enum JSTokenType {
|
|||||||
TOK_SEQ = 82, /* synthetic sequence of statements,
|
TOK_SEQ = 82, /* synthetic sequence of statements,
|
||||||
not a block */
|
not a block */
|
||||||
TOK_FORHEAD = 83, /* head of for(;;)-style loop */
|
TOK_FORHEAD = 83, /* head of for(;;)-style loop */
|
||||||
TOK_ARGSBODY = 84, /* formal args in list + body at end */
|
|
||||||
TOK_UPVARS = 85, /* lexical dependencies as JSAtomList
|
|
||||||
of definitions paired with a parse
|
|
||||||
tree full of uses of those names */
|
|
||||||
TOK_RESERVED, /* reserved keywords */
|
TOK_RESERVED, /* reserved keywords */
|
||||||
TOK_LIMIT /* domain size */
|
TOK_LIMIT /* domain size */
|
||||||
} JSTokenType;
|
} JSTokenType;
|
||||||
@@ -194,45 +190,11 @@ js_AppendJSString(JSStringBuffer *sb, JSString *str);
|
|||||||
struct JSTokenPtr {
|
struct JSTokenPtr {
|
||||||
uint16 index; /* index of char in physical line */
|
uint16 index; /* index of char in physical line */
|
||||||
uint16 lineno; /* physical line number */
|
uint16 lineno; /* physical line number */
|
||||||
|
|
||||||
bool operator <(const JSTokenPtr& bptr) {
|
|
||||||
return lineno < bptr.lineno ||
|
|
||||||
(lineno == bptr.lineno && index < bptr.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator <=(const JSTokenPtr& bptr) {
|
|
||||||
return lineno < bptr.lineno ||
|
|
||||||
(lineno == bptr.lineno && index <= bptr.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator >(const JSTokenPtr& bptr) {
|
|
||||||
return !(*this <= bptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator >=(const JSTokenPtr& bptr) {
|
|
||||||
return !(*this < bptr);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JSTokenPos {
|
struct JSTokenPos {
|
||||||
JSTokenPtr begin; /* first character and line of token */
|
JSTokenPtr begin; /* first character and line of token */
|
||||||
JSTokenPtr end; /* index 1 past last char, last line */
|
JSTokenPtr end; /* index 1 past last char, last line */
|
||||||
|
|
||||||
bool operator <(const JSTokenPos& bpos) {
|
|
||||||
return begin < bpos.begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator <=(const JSTokenPos& bpos) {
|
|
||||||
return begin <= bpos.begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator >(const JSTokenPos& bpos) {
|
|
||||||
return !(*this <= bpos);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator >=(const JSTokenPos& bpos) {
|
|
||||||
return !(*this < bpos);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JSToken {
|
struct JSToken {
|
||||||
@@ -336,9 +298,6 @@ struct JSTokenStream {
|
|||||||
/* Ignore keywords and return TOK_NAME instead to the parser. */
|
/* Ignore keywords and return TOK_NAME instead to the parser. */
|
||||||
#define TSF_KEYWORD_IS_NAME 0x4000
|
#define TSF_KEYWORD_IS_NAME 0x4000
|
||||||
|
|
||||||
/* Parsing a destructuring object or array initialiser pattern. */
|
|
||||||
#define TSF_DESTRUCTURING 0x8000
|
|
||||||
|
|
||||||
/* Unicode separators that are treated as line terminators, in addition to \n, \r */
|
/* Unicode separators that are treated as line terminators, in addition to \n, \r */
|
||||||
#define LINE_SEPARATOR 0x2028
|
#define LINE_SEPARATOR 0x2028
|
||||||
#define PARA_SEPARATOR 0x2029
|
#define PARA_SEPARATOR 0x2029
|
||||||
|
|||||||
@@ -263,9 +263,9 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||||||
* jsparse.c to optimize based on identity of run- and compile-time scope.
|
* jsparse.c to optimize based on identity of run- and compile-time scope.
|
||||||
*/
|
*/
|
||||||
tcflags = 0;
|
tcflags = 0;
|
||||||
script = JSCompiler::compileScript(cx, scopeobj, NULL, principals, tcflags,
|
script = js_CompileScript(cx, scopeobj, NULL, principals, tcflags,
|
||||||
STRING_CHARS(str), JSSTRING_LENGTH(str),
|
JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
|
||||||
NULL, file, line);
|
NULL, file, line);
|
||||||
if (!script)
|
if (!script)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
@@ -457,7 +457,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
|
|||||||
version = (uint32)script->version | (script->nfixed << 16);
|
version = (uint32)script->version | (script->nfixed << 16);
|
||||||
lineno = (uint32)script->lineno;
|
lineno = (uint32)script->lineno;
|
||||||
nslots = (uint32)script->nslots;
|
nslots = (uint32)script->nslots;
|
||||||
nslots = (uint32)((script->staticLevel << 16) | script->nslots);
|
nslots = (uint32)((script->staticDepth << 16) | script->nslots);
|
||||||
natoms = (uint32)script->atomMap.length;
|
natoms = (uint32)script->atomMap.length;
|
||||||
|
|
||||||
/* Count the srcnotes, keeping notes pointing at the first one. */
|
/* Count the srcnotes, keeping notes pointing at the first one. */
|
||||||
@@ -582,7 +582,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
|
|||||||
}
|
}
|
||||||
script->lineno = (uintN)lineno;
|
script->lineno = (uintN)lineno;
|
||||||
script->nslots = (uint16)nslots;
|
script->nslots = (uint16)nslots;
|
||||||
script->staticLevel = (uint16)(nslots >> 16);
|
script->staticDepth = (uint16)(nslots >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i != natoms; ++i) {
|
for (i = 0; i != natoms; ++i) {
|
||||||
@@ -983,7 +983,7 @@ js_alloc_table_space(void *priv, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
js_free_table_space(void *priv, void *item, size_t size)
|
js_free_table_space(void *priv, void *item)
|
||||||
{
|
{
|
||||||
free(item);
|
free(item);
|
||||||
}
|
}
|
||||||
@@ -1145,14 +1145,6 @@ SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags)
|
|||||||
sfp->flags |= flags;
|
sfp->flags |= flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JS_FUNCTION_METERING
|
|
||||||
size_t len = strlen(sfe->filename);
|
|
||||||
if (len >= sizeof rt->lastScriptFilename)
|
|
||||||
len = sizeof rt->lastScriptFilename - 1;
|
|
||||||
memcpy(rt->lastScriptFilename, sfe->filename, len);
|
|
||||||
rt->lastScriptFilename[len] = '\0';
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return sfe;
|
return sfe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1479,14 +1471,14 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||||||
script->main += prologLength;
|
script->main += prologLength;
|
||||||
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
|
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
|
||||||
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
|
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
|
||||||
nfixed = (cg->flags & TCF_IN_FUNCTION)
|
nfixed = (cg->treeContext.flags & TCF_IN_FUNCTION)
|
||||||
? cg->fun->u.i.nvars
|
? cg->treeContext.u.fun->u.i.nvars
|
||||||
: cg->ngvars + cg->regexpList.length;
|
: cg->treeContext.ngvars + cg->regexpList.length;
|
||||||
JS_ASSERT(nfixed < SLOTNO_LIMIT);
|
JS_ASSERT(nfixed < SLOTNO_LIMIT);
|
||||||
script->nfixed = (uint16) nfixed;
|
script->nfixed = (uint16) nfixed;
|
||||||
js_InitAtomMap(cx, &script->atomMap, &cg->atomList);
|
js_InitAtomMap(cx, &script->atomMap, &cg->atomList);
|
||||||
|
|
||||||
filename = cg->compiler->tokenStream.filename;
|
filename = cg->treeContext.parseContext->tokenStream.filename;
|
||||||
if (filename) {
|
if (filename) {
|
||||||
script->filename = js_SaveScriptFilename(cx, filename);
|
script->filename = js_SaveScriptFilename(cx, filename);
|
||||||
if (!script->filename)
|
if (!script->filename)
|
||||||
@@ -1499,8 +1491,8 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
script->nslots = script->nfixed + cg->maxStackDepth;
|
script->nslots = script->nfixed + cg->maxStackDepth;
|
||||||
script->staticLevel = cg->staticLevel;
|
script->staticDepth = cg->staticDepth;
|
||||||
script->principals = cg->compiler->principals;
|
script->principals = cg->treeContext.parseContext->principals;
|
||||||
if (script->principals)
|
if (script->principals)
|
||||||
JSPRINCIPALS_HOLD(cx, script->principals);
|
JSPRINCIPALS_HOLD(cx, script->principals);
|
||||||
|
|
||||||
@@ -1509,17 +1501,17 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||||||
if (cg->ntrynotes != 0)
|
if (cg->ntrynotes != 0)
|
||||||
js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script));
|
js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script));
|
||||||
if (cg->objectList.length != 0)
|
if (cg->objectList.length != 0)
|
||||||
cg->objectList.finish(JS_SCRIPT_OBJECTS(script));
|
FinishParsedObjects(&cg->objectList, JS_SCRIPT_OBJECTS(script));
|
||||||
if (cg->regexpList.length != 0)
|
if (cg->regexpList.length != 0)
|
||||||
cg->regexpList.finish(JS_SCRIPT_REGEXPS(script));
|
FinishParsedObjects(&cg->regexpList, JS_SCRIPT_REGEXPS(script));
|
||||||
if (cg->flags & TCF_NO_SCRIPT_RVAL)
|
if (cg->treeContext.flags & TCF_NO_SCRIPT_RVAL)
|
||||||
script->flags |= JSSF_NO_SCRIPT_RVAL;
|
script->flags |= JSSF_NO_SCRIPT_RVAL;
|
||||||
|
|
||||||
if (cg->upvarList.count != 0) {
|
if (cg->upvarList.count != 0) {
|
||||||
JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length);
|
JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length);
|
||||||
memcpy(JS_SCRIPT_UPVARS(script)->vector, cg->upvarMap.vector,
|
memcpy(JS_SCRIPT_UPVARS(script)->vector, cg->upvarMap.vector,
|
||||||
cg->upvarList.count * sizeof(uint32));
|
cg->upvarList.count * sizeof(uint32));
|
||||||
cg->upvarList.clear();
|
ATOM_LIST_INIT(&cg->upvarList);
|
||||||
JS_free(cx, cg->upvarMap.vector);
|
JS_free(cx, cg->upvarMap.vector);
|
||||||
cg->upvarMap.vector = NULL;
|
cg->upvarMap.vector = NULL;
|
||||||
}
|
}
|
||||||
@@ -1529,8 +1521,8 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||||||
* so that the debugger has a valid FUN_SCRIPT(fun).
|
* so that the debugger has a valid FUN_SCRIPT(fun).
|
||||||
*/
|
*/
|
||||||
fun = NULL;
|
fun = NULL;
|
||||||
if (cg->flags & TCF_IN_FUNCTION) {
|
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
|
||||||
fun = cg->fun;
|
fun = cg->treeContext.u.fun;
|
||||||
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
|
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
|
||||||
JS_ASSERT_IF(script->upvarsOffset != 0,
|
JS_ASSERT_IF(script->upvarsOffset != 0,
|
||||||
JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars);
|
JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars);
|
||||||
@@ -1540,7 +1532,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||||||
#ifdef CHECK_SCRIPT_OWNER
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
script->owner = NULL;
|
script->owner = NULL;
|
||||||
#endif
|
#endif
|
||||||
if (cg->flags & TCF_FUN_HEAVYWEIGHT)
|
if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)
|
||||||
fun->flags |= JSFUN_HEAVYWEIGHT;
|
fun->flags |= JSFUN_HEAVYWEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ typedef struct JSUpvarArray {
|
|||||||
uint32 length; /* count of indexed upvar cookies */
|
uint32 length; /* count of indexed upvar cookies */
|
||||||
} JSUpvarArray;
|
} JSUpvarArray;
|
||||||
|
|
||||||
#define FREE_UPVAR_COOKIE 0xffffffff
|
|
||||||
#define MAKE_UPVAR_COOKIE(skip,slot) ((skip) << 16 | (slot))
|
#define MAKE_UPVAR_COOKIE(skip,slot) ((skip) << 16 | (slot))
|
||||||
#define UPVAR_FRAME_SKIP(cookie) ((uint32)(cookie) >> 16)
|
#define UPVAR_FRAME_SKIP(cookie) ((uint32)(cookie) >> 16)
|
||||||
#define UPVAR_FRAME_SLOT(cookie) ((uint16)(cookie))
|
#define UPVAR_FRAME_SLOT(cookie) ((uint16)(cookie))
|
||||||
@@ -119,7 +118,7 @@ struct JSScript {
|
|||||||
const char *filename; /* source filename or null */
|
const char *filename; /* source filename or null */
|
||||||
uint32 lineno; /* base line number of script */
|
uint32 lineno; /* base line number of script */
|
||||||
uint16 nslots; /* vars plus maximum stack depth */
|
uint16 nslots; /* vars plus maximum stack depth */
|
||||||
uint16 staticLevel;/* static level for display maintenance */
|
uint16 staticDepth;/* static depth for display maintenance */
|
||||||
JSPrincipals *principals;/* principals for this script */
|
JSPrincipals *principals;/* principals for this script */
|
||||||
union {
|
union {
|
||||||
JSObject *object; /* optional Script-class object wrapper */
|
JSObject *object; /* optional Script-class object wrapper */
|
||||||
|
|||||||
@@ -3123,7 +3123,7 @@ js_CheckGlobalObjectShape(JSContext* cx, JSTraceMonitor* tm, JSObject* globalObj
|
|||||||
for (size_t i = 0; i < MONITOR_N_GLOBAL_STATES; ++i) {
|
for (size_t i = 0; i < MONITOR_N_GLOBAL_STATES; ++i) {
|
||||||
GlobalState &state = tm->globalStates[i];
|
GlobalState &state = tm->globalStates[i];
|
||||||
|
|
||||||
if (state.globalShape == uint32(-1)) {
|
if (state.globalShape == (uint32) -1) {
|
||||||
state.globalObj = globalObj;
|
state.globalObj = globalObj;
|
||||||
state.globalShape = globalShape;
|
state.globalShape = globalShape;
|
||||||
JS_ASSERT(state.globalSlots);
|
JS_ASSERT(state.globalSlots);
|
||||||
@@ -3315,8 +3315,8 @@ js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi)
|
|||||||
newifp->frame.regs->sp = newsp + script->nfixed;
|
newifp->frame.regs->sp = newsp + script->nfixed;
|
||||||
newifp->frame.imacpc = NULL;
|
newifp->frame.imacpc = NULL;
|
||||||
newifp->frame.slots = newsp;
|
newifp->frame.slots = newsp;
|
||||||
if (script->staticLevel < JS_DISPLAY_SIZE) {
|
if (script->staticDepth < JS_DISPLAY_SIZE) {
|
||||||
JSStackFrame **disp = &cx->display[script->staticLevel];
|
JSStackFrame **disp = &cx->display[script->staticDepth];
|
||||||
newifp->frame.displaySave = *disp;
|
newifp->frame.displaySave = *disp;
|
||||||
*disp = &newifp->frame;
|
*disp = &newifp->frame;
|
||||||
}
|
}
|
||||||
@@ -4252,7 +4252,7 @@ LeaveTree(InterpState& state, VMSideExit* lr)
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// Verify that our state restoration worked.
|
// Verify that our state restoration worked.
|
||||||
for (JSStackFrame* fp = cx->fp; fp; fp = fp->down) {
|
for (JSStackFrame* fp = cx->fp; fp; fp = fp->down) {
|
||||||
JS_ASSERT_IF(fp->callee, JSVAL_IS_OBJECT(fp->argv[-1]));
|
JS_ASSERT(!fp->callee || JSVAL_IS_OBJECT(fp->argv[-1]));
|
||||||
JS_ASSERT_IF(fp->callee && fp->thisp != JSVAL_TO_OBJECT(fp->argv[-1]),
|
JS_ASSERT_IF(fp->callee && fp->thisp != JSVAL_TO_OBJECT(fp->argv[-1]),
|
||||||
!(fp->flags & JSFRAME_COMPUTED_THIS) && !fp->thisp);
|
!(fp->flags & JSFRAME_COMPUTED_THIS) && !fp->thisp);
|
||||||
}
|
}
|
||||||
@@ -4394,7 +4394,9 @@ TraceRecorder::monitorRecording(JSContext* cx, TraceRecorder* tr, JSOp op)
|
|||||||
tr->pendingTraceableNative = NULL;
|
tr->pendingTraceableNative = NULL;
|
||||||
|
|
||||||
debug_only_v(js_Disassemble1(cx, cx->fp->script, cx->fp->regs->pc,
|
debug_only_v(js_Disassemble1(cx, cx->fp->script, cx->fp->regs->pc,
|
||||||
cx->fp->imacpc ? 0 : cx->fp->regs->pc - cx->fp->script->code,
|
(cx->fp->imacpc)
|
||||||
|
? 0
|
||||||
|
: cx->fp->regs->pc - cx->fp->script->code,
|
||||||
!cx->fp->imacpc, stdout);)
|
!cx->fp->imacpc, stdout);)
|
||||||
|
|
||||||
/* If op is not a break or a return from a loop, continue recording and follow the
|
/* If op is not a break or a return from a loop, continue recording and follow the
|
||||||
@@ -6095,20 +6097,15 @@ TraceRecorder::stobj_get_fslot(LIns* obj_ins, unsigned slot)
|
|||||||
return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval));
|
return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval));
|
||||||
}
|
}
|
||||||
|
|
||||||
LIns*
|
|
||||||
TraceRecorder::stobj_get_dslot(LIns* obj_ins, unsigned index, LIns*& dslots_ins)
|
|
||||||
{
|
|
||||||
if (!dslots_ins)
|
|
||||||
dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots));
|
|
||||||
return lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval));
|
|
||||||
}
|
|
||||||
|
|
||||||
LIns*
|
LIns*
|
||||||
TraceRecorder::stobj_get_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins)
|
TraceRecorder::stobj_get_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins)
|
||||||
{
|
{
|
||||||
if (slot < JS_INITIAL_NSLOTS)
|
if (slot < JS_INITIAL_NSLOTS)
|
||||||
return stobj_get_fslot(obj_ins, slot);
|
return stobj_get_fslot(obj_ins, slot);
|
||||||
return stobj_get_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins);
|
|
||||||
|
if (!dslots_ins)
|
||||||
|
dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots));
|
||||||
|
return lir->insLoad(LIR_ldp, dslots_ins, (slot - JS_INITIAL_NSLOTS) * sizeof(jsval));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -6123,7 +6120,7 @@ TraceRecorder::native_set(LIns* obj_ins, JSScopeProperty* sprop, LIns*& dslots_i
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
TraceRecorder::native_get(LIns* obj_ins, LIns* pobj_ins, JSScopeProperty* sprop,
|
TraceRecorder::native_get(LIns* obj_ins, LIns* pobj_ins, JSScopeProperty* sprop,
|
||||||
LIns*& dslots_ins, LIns*& v_ins)
|
LIns*& dslots_ins, LIns*& v_ins)
|
||||||
{
|
{
|
||||||
if (!SPROP_HAS_STUB_GETTER(sprop))
|
if (!SPROP_HAS_STUB_GETTER(sprop))
|
||||||
return false;
|
return false;
|
||||||
@@ -6274,17 +6271,13 @@ TraceRecorder::guardDenseArrayIndex(JSObject* obj, jsint idx, LIns* obj_ins,
|
|||||||
idx_ins,
|
idx_ins,
|
||||||
stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)),
|
stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
/* If dslots is NULL, stay on trace (and read value as undefined). */
|
/* If dslots is NULL, stay on trace (and read value as undefined). */
|
||||||
LIns* br2 = lir->insBranch(LIR_jt, lir->ins_eq0(dslots_ins), NULL);
|
LIns* br2 = lir->insBranch(LIR_jt, lir->ins_eq0(dslots_ins), NULL);
|
||||||
|
|
||||||
/* If not idx < capacity, stay on trace (and read value as undefined). */
|
/* If not idx < capacity, stay on trace (and read value as undefined). */
|
||||||
LIns* br3 = lir->insBranch(LIR_jf,
|
LIns* br3 = lir->insBranch(LIR_jf,
|
||||||
lir->ins2(LIR_ult,
|
lir->ins2(LIR_ult,
|
||||||
idx_ins,
|
idx_ins,
|
||||||
lir->insLoad(LIR_ldp,
|
lir->insLoad(LIR_ldp, dslots_ins, 0 - (int)sizeof(jsval))),
|
||||||
dslots_ins,
|
|
||||||
-(int)sizeof(jsval))),
|
|
||||||
NULL);
|
NULL);
|
||||||
lir->insGuard(LIR_x, lir->insImm(1), snapshot(exitType));
|
lir->insGuard(LIR_x, lir->insImm(1), snapshot(exitType));
|
||||||
LIns* label = lir->ins0(LIR_label);
|
LIns* label = lir->ins0(LIR_label);
|
||||||
@@ -6835,17 +6828,7 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
|
TraceRecorder::newArray(JSObject *ctor, uint32 argc, jsval *argv, jsval *rval)
|
||||||
{
|
|
||||||
JSObject* proto;
|
|
||||||
if (!js_GetClassPrototype(cx, globalObj, INT_TO_JSID(key), &proto))
|
|
||||||
return false;
|
|
||||||
proto_ins = INS_CONSTPTR(proto);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
|
|
||||||
{
|
{
|
||||||
LIns *proto_ins, *arr_ins;
|
LIns *proto_ins, *arr_ins;
|
||||||
if (!getClassPrototype(ctor, proto_ins))
|
if (!getClassPrototype(ctor, proto_ins))
|
||||||
@@ -7748,67 +7731,12 @@ TraceRecorder::record_JSOP_CALLNAME()
|
|||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_GETUPVAR()
|
TraceRecorder::record_JSOP_GETUPVAR()
|
||||||
{
|
{
|
||||||
uintN index = GET_UINT16(cx->fp->regs->pc);
|
return false;
|
||||||
JSScript *script = cx->fp->script;
|
|
||||||
|
|
||||||
JSUpvarArray* uva = JS_SCRIPT_UPVARS(script);
|
|
||||||
JS_ASSERT(index < uva->length);
|
|
||||||
|
|
||||||
uintN skip = UPVAR_FRAME_SKIP(uva->vector[index]);
|
|
||||||
if (skip > callDepth)
|
|
||||||
ABORT_TRACE("upvar out of reach");
|
|
||||||
|
|
||||||
JSStackFrame* fp2 = cx->display[script->staticLevel - skip];
|
|
||||||
JS_ASSERT(fp2->script);
|
|
||||||
|
|
||||||
uintN slot = UPVAR_FRAME_SLOT(uva->vector[index]);
|
|
||||||
jsval* vp;
|
|
||||||
if (!fp2->fun) {
|
|
||||||
vp = fp2->slots + fp2->script->nfixed;
|
|
||||||
} else if (slot < fp2->fun->nargs) {
|
|
||||||
vp = fp2->argv;
|
|
||||||
} else {
|
|
||||||
slot -= fp2->fun->nargs;
|
|
||||||
JS_ASSERT(slot < fp2->script->nslots);
|
|
||||||
vp = fp2->slots;
|
|
||||||
}
|
|
||||||
|
|
||||||
stack(0, get(&vp[slot]));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_CALLUPVAR()
|
TraceRecorder::record_JSOP_CALLUPVAR()
|
||||||
{
|
{
|
||||||
if (record_JSOP_GETUPVAR()) {
|
|
||||||
stack(1, INS_CONSTPTR(NULL));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
TraceRecorder::record_JSOP_GETDSLOT()
|
|
||||||
{
|
|
||||||
JSObject* callee = cx->fp->callee;
|
|
||||||
LIns* callee_ins = (callDepth == 0) ? get(&cx->fp->argv[-2]) : INS_CONSTPTR(callee);
|
|
||||||
|
|
||||||
unsigned index = GET_UINT16(cx->fp->regs->pc);
|
|
||||||
LIns* dslots_ins = NULL;
|
|
||||||
LIns* v_ins = stobj_get_dslot(callee_ins, index, dslots_ins);
|
|
||||||
|
|
||||||
unbox_jsval(callee->dslots[index], v_ins);
|
|
||||||
stack(0, v_ins);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
TraceRecorder::record_JSOP_CALLDSLOT()
|
|
||||||
{
|
|
||||||
if (record_JSOP_GETDSLOT()) {
|
|
||||||
stack(1, INS_CONSTPTR(NULL));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8522,12 +8450,13 @@ JS_REQUIRES_STACK bool
|
|||||||
TraceRecorder::record_JSOP_NEWINIT()
|
TraceRecorder::record_JSOP_NEWINIT()
|
||||||
{
|
{
|
||||||
JSProtoKey key = JSProtoKey(GET_INT8(cx->fp->regs->pc));
|
JSProtoKey key = JSProtoKey(GET_INT8(cx->fp->regs->pc));
|
||||||
LIns *proto_ins;
|
JSObject* obj;
|
||||||
if (!getClassPrototype(key, proto_ins))
|
const CallInfo *ci;
|
||||||
return false;
|
|
||||||
|
|
||||||
LIns* args[] = { proto_ins, cx_ins };
|
if (!js_GetClassPrototype(cx, globalObj, INT_TO_JSID(key), &obj))
|
||||||
const CallInfo *ci = (key == JSProto_Array) ? &js_FastNewArray_ci : &js_Object_tn_ci;
|
return false;
|
||||||
|
ci = (key == JSProto_Array) ? &js_FastNewArray_ci : &js_Object_tn_ci;
|
||||||
|
LIns* args[] = { INS_CONSTPTR(obj), cx_ins };
|
||||||
LIns* v_ins = lir->insCall(ci, args);
|
LIns* v_ins = lir->insCall(ci, args);
|
||||||
guard(false, lir->ins_eq0(v_ins), OOM_EXIT);
|
guard(false, lir->ins_eq0(v_ins), OOM_EXIT);
|
||||||
stack(0, v_ins);
|
stack(0, v_ins);
|
||||||
@@ -8895,12 +8824,6 @@ TraceRecorder::record_JSOP_DEFFUN()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
TraceRecorder::record_JSOP_DEFFUN_FC()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_DEFCONST()
|
TraceRecorder::record_JSOP_DEFCONST()
|
||||||
{
|
{
|
||||||
@@ -8913,46 +8836,38 @@ TraceRecorder::record_JSOP_DEFVAR()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsatomid
|
/*
|
||||||
TraceRecorder::getFullIndex(ptrdiff_t pcoff)
|
* XXX could hoist out to jsinterp.h and share with jsinterp.cpp, but
|
||||||
{
|
* XXX jsopcode.cpp has different definitions of same-named macros.
|
||||||
jsatomid index = GET_INDEX(cx->fp->regs->pc + pcoff);
|
*/
|
||||||
index += atoms - cx->fp->script->atomMap.vector;
|
#define GET_FULL_INDEX(PCOFF) \
|
||||||
return index;
|
(atoms - script->atomMap.vector + GET_INDEX(regs.pc + PCOFF))
|
||||||
}
|
|
||||||
|
#define LOAD_FUNCTION(PCOFF) \
|
||||||
|
JS_GET_SCRIPT_FUNCTION(script, GET_FULL_INDEX(PCOFF), fun)
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_LAMBDA()
|
TraceRecorder::record_JSOP_ANONFUNOBJ()
|
||||||
{
|
{
|
||||||
JSFunction* fun;
|
JSFunction* fun;
|
||||||
JS_GET_SCRIPT_FUNCTION(cx->fp->script, getFullIndex(), fun);
|
JSFrameRegs& regs = *cx->fp->regs;
|
||||||
|
JSScript* script = cx->fp->script;
|
||||||
|
LOAD_FUNCTION(0); // needs script, regs, fun
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun) && OBJ_GET_PARENT(cx, FUN_OBJECT(fun)) == globalObj) {
|
JSObject* obj = FUN_OBJECT(fun);
|
||||||
LIns *proto_ins;
|
if (OBJ_GET_PARENT(cx, obj) != cx->fp->scopeChain)
|
||||||
if (!getClassPrototype(JSProto_Function, proto_ins))
|
ABORT_TRACE("can't trace with activation object on scopeChain");
|
||||||
return false;
|
|
||||||
|
|
||||||
LIns* args[] = { INS_CONSTPTR(globalObj), proto_ins, INS_CONSTPTR(fun), cx_ins };
|
stack(0, INS_CONSTPTR(obj));
|
||||||
LIns* x = lir->insCall(&js_NewNullClosure_ci, args);
|
|
||||||
stack(0, x);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
TraceRecorder::record_JSOP_LAMBDA_FC()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
TraceRecorder::record_JSOP_CALLEE()
|
|
||||||
{
|
|
||||||
stack(0, INS_CONSTPTR(cx->fp->callee));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_REQUIRES_STACK bool
|
||||||
|
TraceRecorder::record_JSOP_NAMEDFUNOBJ()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_SETLOCALPOP()
|
TraceRecorder::record_JSOP_SETLOCALPOP()
|
||||||
{
|
{
|
||||||
@@ -9021,30 +8936,12 @@ TraceRecorder::record_JSOP_ARGCNT()
|
|||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj)
|
TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj)
|
||||||
{
|
{
|
||||||
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj);
|
var(slot, INS_CONSTPTR(obj));
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun) && OBJ_GET_PARENT(cx, FUN_OBJECT(fun)) == globalObj) {
|
|
||||||
LIns *proto_ins;
|
|
||||||
if (!getClassPrototype(JSProto_Function, proto_ins))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
LIns* args[] = { INS_CONSTPTR(globalObj), proto_ins, INS_CONSTPTR(fun), cx_ins };
|
|
||||||
LIns* x = lir->insCall(&js_NewNullClosure_ci, args);
|
|
||||||
var(slot, x);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
TraceRecorder::record_JSOP_DEFLOCALFUN()
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_DEFLOCALFUN_FC()
|
TraceRecorder::record_JSOP_DEFLOCALFUN()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -9566,8 +9463,10 @@ TraceRecorder::record_JSOP_TYPEOFEXPR()
|
|||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_ENTERBLOCK()
|
TraceRecorder::record_JSOP_ENTERBLOCK()
|
||||||
{
|
{
|
||||||
|
JSScript* script = cx->fp->script;
|
||||||
|
JSFrameRegs& regs = *cx->fp->regs;
|
||||||
JSObject* obj;
|
JSObject* obj;
|
||||||
JS_GET_SCRIPT_OBJECT(cx->fp->script, getFullIndex(0), obj);
|
JS_GET_SCRIPT_OBJECT(script, GET_FULL_INDEX(0), obj);
|
||||||
|
|
||||||
LIns* void_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
|
LIns* void_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
|
||||||
for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++)
|
for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++)
|
||||||
@@ -9838,6 +9737,13 @@ TraceRecorder::record_JSOP_CALLBUILTIN()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_REQUIRES_STACK bool
|
||||||
|
TraceRecorder::record_JSOP_NULLTHIS()
|
||||||
|
{
|
||||||
|
stack(0, INS_CONSTPTR(NULL));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_INT8()
|
TraceRecorder::record_JSOP_INT8()
|
||||||
{
|
{
|
||||||
@@ -9909,13 +9815,14 @@ TraceRecorder::record_JSOP_LENGTH()
|
|||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_NEWARRAY()
|
TraceRecorder::record_JSOP_NEWARRAY()
|
||||||
{
|
{
|
||||||
LIns *proto_ins;
|
JSObject* proto;
|
||||||
if (!getClassPrototype(JSProto_Array, proto_ins))
|
const CallInfo* ci = &js_NewUninitializedArray_ci;
|
||||||
|
if (!js_GetClassPrototype(cx, globalObj, INT_TO_JSID(JSProto_Array), &proto))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32 len = GET_UINT24(cx->fp->regs->pc);
|
uint32 len = GET_UINT24(cx->fp->regs->pc);
|
||||||
LIns* args[] = { lir->insImm(len), proto_ins, cx_ins };
|
LIns* args[] = { lir->insImm(len), INS_CONSTPTR(proto), cx_ins };
|
||||||
LIns* v_ins = lir->insCall(&js_NewUninitializedArray_ci, args);
|
LIns* v_ins = lir->insCall(ci, args);
|
||||||
guard(false, lir->ins_eq0(v_ins), OOM_EXIT);
|
guard(false, lir->ins_eq0(v_ins), OOM_EXIT);
|
||||||
|
|
||||||
LIns* dslots_ins = NULL;
|
LIns* dslots_ins = NULL;
|
||||||
@@ -9988,3 +9895,12 @@ js_DumpPeerStability(JSTraceMonitor* tm, const void* ip, JSObject* globalObj, ui
|
|||||||
JS_NOT_REACHED("JSOP_UNUSED" # n); \
|
JS_NOT_REACHED("JSOP_UNUSED" # n); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNUSED(203)
|
||||||
|
UNUSED(204)
|
||||||
|
UNUSED(205)
|
||||||
|
UNUSED(206)
|
||||||
|
UNUSED(207)
|
||||||
|
UNUSED(208)
|
||||||
|
UNUSED(209)
|
||||||
|
UNUSED(219)
|
||||||
|
|||||||
@@ -512,8 +512,6 @@ class TraceRecorder : public avmplus::GCObject {
|
|||||||
nanojit::LIns* v_ins, const char *name);
|
nanojit::LIns* v_ins, const char *name);
|
||||||
|
|
||||||
nanojit::LIns* stobj_get_fslot(nanojit::LIns* obj_ins, unsigned slot);
|
nanojit::LIns* stobj_get_fslot(nanojit::LIns* obj_ins, unsigned slot);
|
||||||
nanojit::LIns* stobj_get_dslot(nanojit::LIns* obj_ins, unsigned index,
|
|
||||||
nanojit::LIns*& dslots_ins);
|
|
||||||
nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot,
|
nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot,
|
||||||
nanojit::LIns*& dslots_ins);
|
nanojit::LIns*& dslots_ins);
|
||||||
bool native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop,
|
bool native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop,
|
||||||
@@ -543,7 +541,6 @@ class TraceRecorder : public avmplus::GCObject {
|
|||||||
void clearFrameSlotsFromCache();
|
void clearFrameSlotsFromCache();
|
||||||
JS_REQUIRES_STACK bool guardCallee(jsval& callee);
|
JS_REQUIRES_STACK bool guardCallee(jsval& callee);
|
||||||
JS_REQUIRES_STACK bool getClassPrototype(JSObject* ctor, nanojit::LIns*& proto_ins);
|
JS_REQUIRES_STACK bool getClassPrototype(JSObject* ctor, nanojit::LIns*& proto_ins);
|
||||||
JS_REQUIRES_STACK bool getClassPrototype(JSProtoKey key, nanojit::LIns*& proto_ins);
|
|
||||||
JS_REQUIRES_STACK bool newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* vp);
|
JS_REQUIRES_STACK bool newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* vp);
|
||||||
JS_REQUIRES_STACK bool newString(JSObject* ctor, jsval& arg, jsval* rval);
|
JS_REQUIRES_STACK bool newString(JSObject* ctor, jsval& arg, jsval* rval);
|
||||||
JS_REQUIRES_STACK bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
|
JS_REQUIRES_STACK bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
|
||||||
@@ -562,8 +559,6 @@ class TraceRecorder : public avmplus::GCObject {
|
|||||||
bool hasMethod(JSObject* obj, jsid id);
|
bool hasMethod(JSObject* obj, jsid id);
|
||||||
JS_REQUIRES_STACK bool hasIteratorMethod(JSObject* obj);
|
JS_REQUIRES_STACK bool hasIteratorMethod(JSObject* obj);
|
||||||
|
|
||||||
jsatomid getFullIndex(ptrdiff_t pcoff = 0);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JS_REQUIRES_STACK
|
JS_REQUIRES_STACK
|
||||||
TraceRecorder(JSContext* cx, VMSideExit*, nanojit::Fragment*, TreeInfo*,
|
TraceRecorder(JSContext* cx, VMSideExit*, nanojit::Fragment*, TreeInfo*,
|
||||||
@@ -613,10 +608,9 @@ public:
|
|||||||
#define TRACE_RECORDER(cx) (JS_TRACE_MONITOR(cx).recorder)
|
#define TRACE_RECORDER(cx) (JS_TRACE_MONITOR(cx).recorder)
|
||||||
#define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr))
|
#define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr))
|
||||||
|
|
||||||
#define JSOP_IN_RANGE(op,lo,hi) (uintN((op) - (lo)) <= uintN((hi) - (lo)))
|
#define JSOP_IS_BINARY(op) ((uintN)((op) - JSOP_BITOR) <= (uintN)(JSOP_MOD - JSOP_BITOR))
|
||||||
#define JSOP_IS_BINARY(op) JSOP_IN_RANGE(op, JSOP_BITOR, JSOP_MOD)
|
#define JSOP_IS_UNARY(op) ((uintN)((op) - JSOP_NEG) <= (uintN)(JSOP_POS - JSOP_NEG))
|
||||||
#define JSOP_IS_UNARY(op) JSOP_IN_RANGE(op, JSOP_NEG, JSOP_POS)
|
#define JSOP_IS_EQUALITY(op) ((uintN)((op) - JSOP_EQ) <= (uintN)(JSOP_NE - JSOP_EQ))
|
||||||
#define JSOP_IS_EQUALITY(op) JSOP_IN_RANGE(op, JSOP_EQ, JSOP_NE)
|
|
||||||
|
|
||||||
#define TRACE_ARGS_(x,args) \
|
#define TRACE_ARGS_(x,args) \
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
|||||||
* before deserialization of bytecode. If the saved version does not match
|
* before deserialization of bytecode. If the saved version does not match
|
||||||
* the current version, abort deserialization and invalidate the file.
|
* the current version, abort deserialization and invalidate the file.
|
||||||
*/
|
*/
|
||||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 43)
|
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 42)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Library-private functions.
|
* Library-private functions.
|
||||||
|
|||||||
@@ -1261,10 +1261,9 @@ static const char xml_namespace_str[] = "http://www.w3.org/XML/1998/namespace";
|
|||||||
static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/";
|
static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/";
|
||||||
|
|
||||||
static JSObject *
|
static JSObject *
|
||||||
ParseNodeToQName(JSCompiler *jsc, JSParseNode *pn,
|
ParseNodeToQName(JSContext *cx, JSParseContext *pc, JSParseNode *pn,
|
||||||
JSXMLArray *inScopeNSes, JSBool isAttributeName)
|
JSXMLArray *inScopeNSes, JSBool isAttributeName)
|
||||||
{
|
{
|
||||||
JSContext *cx = jsc->context;
|
|
||||||
JSString *str, *uri, *prefix, *localName;
|
JSString *str, *uri, *prefix, *localName;
|
||||||
size_t length, offset;
|
size_t length, offset;
|
||||||
const jschar *start, *limit, *colon;
|
const jschar *start, *limit, *colon;
|
||||||
@@ -1314,15 +1313,15 @@ ParseNodeToQName(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
js_ReportCompileErrorNumber(jsc->context, &jsc->tokenStream, pn,
|
js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn,
|
||||||
JSREPORT_ERROR,
|
JSREPORT_ERROR,
|
||||||
JSMSG_BAD_XML_NAMESPACE,
|
JSMSG_BAD_XML_NAMESPACE,
|
||||||
js_ValueToPrintableString(jsc->context,
|
js_ValueToPrintableString(cx,
|
||||||
STRING_TO_JSVAL(prefix)));
|
STRING_TO_JSVAL(prefix)));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
localName = js_NewStringCopyN(jsc->context, colon + 1, length - (offset + 1));
|
localName = js_NewStringCopyN(cx, colon + 1, length - (offset + 1));
|
||||||
if (!localName)
|
if (!localName)
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
@@ -1347,12 +1346,12 @@ ParseNodeToQName(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prefix = IS_EMPTY(uri) ? jsc->context->runtime->emptyString : NULL;
|
prefix = IS_EMPTY(uri) ? cx->runtime->emptyString : NULL;
|
||||||
}
|
}
|
||||||
localName = str;
|
localName = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewXMLQName(jsc->context, uri, prefix, localName);
|
return NewXMLQName(cx, uri, prefix, localName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSString *
|
static JSString *
|
||||||
@@ -1382,10 +1381,9 @@ ChompXMLWhitespace(JSContext *cx, JSString *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static JSXML *
|
static JSXML *
|
||||||
ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
ParseNodeToXML(JSContext *cx, JSParseContext *pc, JSParseNode *pn,
|
||||||
JSXMLArray *inScopeNSes, uintN flags)
|
JSXMLArray *inScopeNSes, uintN flags)
|
||||||
{
|
{
|
||||||
JSContext *cx = jsc->context;
|
|
||||||
JSXML *xml, *kid, *attr, *attrj;
|
JSXML *xml, *kid, *attr, *attrj;
|
||||||
JSString *str;
|
JSString *str;
|
||||||
uint32 length, n, i, j;
|
uint32 length, n, i, j;
|
||||||
@@ -1396,7 +1394,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
int stackDummy;
|
int stackDummy;
|
||||||
|
|
||||||
if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
|
if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
|
||||||
js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR,
|
js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn, JSREPORT_ERROR,
|
||||||
JSMSG_OVER_RECURSED);
|
JSMSG_OVER_RECURSED);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1415,7 +1413,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
case TOK_XMLELEM:
|
case TOK_XMLELEM:
|
||||||
length = inScopeNSes->length;
|
length = inScopeNSes->length;
|
||||||
pn2 = pn->pn_head;
|
pn2 = pn->pn_head;
|
||||||
xml = ParseNodeToXML(jsc, pn2, inScopeNSes, flags);
|
xml = ParseNodeToXML(cx, pc, pn2, inScopeNSes, flags);
|
||||||
if (!xml)
|
if (!xml)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@@ -1440,7 +1438,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
kid = ParseNodeToXML(jsc, pn2, inScopeNSes, flags);
|
kid = ParseNodeToXML(cx, pc, pn2, inScopeNSes, flags);
|
||||||
if (kid == PN2X_SKIP_CHILD) {
|
if (kid == PN2X_SKIP_CHILD) {
|
||||||
--n;
|
--n;
|
||||||
continue;
|
continue;
|
||||||
@@ -1491,7 +1489,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
kid = ParseNodeToXML(jsc, pn2, inScopeNSes, flags);
|
kid = ParseNodeToXML(cx, pc, pn2, inScopeNSes, flags);
|
||||||
if (kid == PN2X_SKIP_CHILD) {
|
if (kid == PN2X_SKIP_CHILD) {
|
||||||
--n;
|
--n;
|
||||||
continue;
|
continue;
|
||||||
@@ -1535,7 +1533,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
/* Enforce "Well-formedness constraint: Unique Att Spec". */
|
/* Enforce "Well-formedness constraint: Unique Att Spec". */
|
||||||
for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) {
|
for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) {
|
||||||
if (pn3->pn_atom == pn2->pn_atom) {
|
if (pn3->pn_atom == pn2->pn_atom) {
|
||||||
js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2,
|
js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn2,
|
||||||
JSREPORT_ERROR,
|
JSREPORT_ERROR,
|
||||||
JSMSG_DUPLICATE_XML_ATTR,
|
JSMSG_DUPLICATE_XML_ATTR,
|
||||||
js_ValueToPrintableString(cx,
|
js_ValueToPrintableString(cx,
|
||||||
@@ -1620,7 +1618,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
|
|
||||||
/* Second pass: process tag name and attributes, using namespaces. */
|
/* Second pass: process tag name and attributes, using namespaces. */
|
||||||
pn2 = pn->pn_head;
|
pn2 = pn->pn_head;
|
||||||
qn = ParseNodeToQName(jsc, pn2, inScopeNSes, JS_FALSE);
|
qn = ParseNodeToQName(cx, pc, pn2, inScopeNSes, JS_FALSE);
|
||||||
if (!qn)
|
if (!qn)
|
||||||
goto fail;
|
goto fail;
|
||||||
xml->name = qn;
|
xml->name = qn;
|
||||||
@@ -1631,7 +1629,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
for (i = 0; (pn2 = pn2->pn_next) != NULL; i++) {
|
for (i = 0; (pn2 = pn2->pn_next) != NULL; i++) {
|
||||||
qn = ParseNodeToQName(jsc, pn2, inScopeNSes, JS_TRUE);
|
qn = ParseNodeToQName(cx, pc, pn2, inScopeNSes, JS_TRUE);
|
||||||
if (!qn) {
|
if (!qn) {
|
||||||
xml->xml_attrs.length = i;
|
xml->xml_attrs.length = i;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -1646,7 +1644,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
attrjqn = attrj->name;
|
attrjqn = attrj->name;
|
||||||
if (js_EqualStrings(GetURI(attrjqn), GetURI(qn)) &&
|
if (js_EqualStrings(GetURI(attrjqn), GetURI(qn)) &&
|
||||||
js_EqualStrings(GetLocalName(attrjqn), GetLocalName(qn))) {
|
js_EqualStrings(GetLocalName(attrjqn), GetLocalName(qn))) {
|
||||||
js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn2,
|
js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn2,
|
||||||
JSREPORT_ERROR,
|
JSREPORT_ERROR,
|
||||||
JSMSG_DUPLICATE_XML_ATTR,
|
JSMSG_DUPLICATE_XML_ATTR,
|
||||||
js_ValueToPrintableString(cx,
|
js_ValueToPrintableString(cx,
|
||||||
@@ -1687,7 +1685,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
xml_class = JSXML_CLASS_COMMENT;
|
xml_class = JSXML_CLASS_COMMENT;
|
||||||
} else if (pn->pn_type == TOK_XMLPI) {
|
} else if (pn->pn_type == TOK_XMLPI) {
|
||||||
if (IS_XML(str)) {
|
if (IS_XML(str)) {
|
||||||
js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn,
|
js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn,
|
||||||
JSREPORT_ERROR,
|
JSREPORT_ERROR,
|
||||||
JSMSG_RESERVED_ID,
|
JSMSG_RESERVED_ID,
|
||||||
js_ValueToPrintableString(cx,
|
js_ValueToPrintableString(cx,
|
||||||
@@ -1698,7 +1696,7 @@ ParseNodeToXML(JSCompiler *jsc, JSParseNode *pn,
|
|||||||
if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS)
|
if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS)
|
||||||
goto skip_child;
|
goto skip_child;
|
||||||
|
|
||||||
qn = ParseNodeToQName(jsc, pn, inScopeNSes, JS_FALSE);
|
qn = ParseNodeToQName(cx, pc, pn, inScopeNSes, JS_FALSE);
|
||||||
if (!qn)
|
if (!qn)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@@ -1736,7 +1734,7 @@ skip_child:
|
|||||||
#undef PN2X_SKIP_CHILD
|
#undef PN2X_SKIP_CHILD
|
||||||
|
|
||||||
syntax:
|
syntax:
|
||||||
js_ReportCompileErrorNumber(cx, &jsc->tokenStream, pn, JSREPORT_ERROR,
|
js_ReportCompileErrorNumber(cx, &pc->tokenStream, pn, JSREPORT_ERROR,
|
||||||
JSMSG_BAD_XML_MARKUP);
|
JSMSG_BAD_XML_MARKUP);
|
||||||
fail:
|
fail:
|
||||||
js_LeaveLocalRootScope(cx);
|
js_LeaveLocalRootScope(cx);
|
||||||
@@ -1830,6 +1828,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
|||||||
jschar *chars;
|
jschar *chars;
|
||||||
const jschar *srcp, *endp;
|
const jschar *srcp, *endp;
|
||||||
JSXML *xml;
|
JSXML *xml;
|
||||||
|
JSParseContext pc;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
uintN lineno;
|
uintN lineno;
|
||||||
JSStackFrame *fp;
|
JSStackFrame *fp;
|
||||||
@@ -1892,19 +1891,20 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (!js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL,
|
||||||
JSCompiler jsc(cx);
|
filename, lineno))
|
||||||
if (jsc.init(chars, length, NULL, filename, lineno)) {
|
goto out;
|
||||||
pn = jsc.parseXMLText(js_GetTopStackFrame(cx)->scopeChain, false);
|
pn = js_ParseXMLText(cx, js_GetTopStackFrame(cx)->scopeChain, &pc,
|
||||||
if (pn && XMLArrayInit(cx, &nsarray, 1)) {
|
JS_FALSE);
|
||||||
if (GetXMLSettingFlags(cx, &flags))
|
if (pn && XMLArrayInit(cx, &nsarray, 1)) {
|
||||||
xml = ParseNodeToXML(&jsc, pn, &nsarray, flags);
|
if (GetXMLSettingFlags(cx, &flags))
|
||||||
|
xml = ParseNodeToXML(cx, &pc, pn, &nsarray, flags);
|
||||||
|
|
||||||
XMLArrayFinish(cx, &nsarray);
|
XMLArrayFinish(cx, &nsarray);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
js_FinishParseContext(cx, &pc);
|
||||||
|
|
||||||
|
out:
|
||||||
JS_free(cx, chars);
|
JS_free(cx, chars);
|
||||||
return xml;
|
return xml;
|
||||||
|
|
||||||
@@ -7433,24 +7433,24 @@ js_FinalizeXML(JSContext *cx, JSXML *xml)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
js_ParseNodeToXMLObject(JSCompiler *jsc, JSParseNode *pn)
|
js_ParseNodeToXMLObject(JSContext *cx, JSParseContext *pc, JSParseNode *pn)
|
||||||
{
|
{
|
||||||
jsval nsval;
|
jsval nsval;
|
||||||
JSObject *ns;
|
JSObject *ns;
|
||||||
JSXMLArray nsarray;
|
JSXMLArray nsarray;
|
||||||
JSXML *xml;
|
JSXML *xml;
|
||||||
|
|
||||||
if (!js_GetDefaultXMLNamespace(jsc->context, &nsval))
|
if (!js_GetDefaultXMLNamespace(cx, &nsval))
|
||||||
return NULL;
|
return NULL;
|
||||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval));
|
JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval));
|
||||||
ns = JSVAL_TO_OBJECT(nsval);
|
ns = JSVAL_TO_OBJECT(nsval);
|
||||||
|
|
||||||
if (!XMLArrayInit(jsc->context, &nsarray, 1))
|
if (!XMLArrayInit(cx, &nsarray, 1))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
XMLARRAY_APPEND(jsc->context, &nsarray, ns);
|
XMLARRAY_APPEND(cx, &nsarray, ns);
|
||||||
xml = ParseNodeToXML(jsc, pn, &nsarray, XSF_PRECOMPILED_ROOT);
|
xml = ParseNodeToXML(cx, pc, pn, &nsarray, XSF_PRECOMPILED_ROOT);
|
||||||
XMLArrayFinish(jsc->context, &nsarray);
|
XMLArrayFinish(cx, &nsarray);
|
||||||
if (!xml)
|
if (!xml)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ extern void
|
|||||||
js_FinalizeXML(JSContext *cx, JSXML *xml);
|
js_FinalizeXML(JSContext *cx, JSXML *xml);
|
||||||
|
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_ParseNodeToXMLObject(JSCompiler *jsc, JSParseNode *pn);
|
js_ParseNodeToXMLObject(JSContext *cx, JSParseContext *pc, JSParseNode *pn);
|
||||||
|
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_NewXMLObject(JSContext *cx, JSXMLClass xml_class);
|
js_NewXMLObject(JSContext *cx, JSXMLClass xml_class);
|
||||||
|
|||||||
@@ -62,7 +62,6 @@
|
|||||||
#include "jsemit.h"
|
#include "jsemit.h"
|
||||||
#include "jsfun.h"
|
#include "jsfun.h"
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
#include "jsiter.h"
|
|
||||||
#include "jslock.h"
|
#include "jslock.h"
|
||||||
#include "jsnum.h"
|
#include "jsnum.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
@@ -1349,31 +1348,22 @@ CountHeap(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
static JSScript *
|
static JSScript *
|
||||||
ValueToScript(JSContext *cx, jsval v)
|
ValueToScript(JSContext *cx, jsval v)
|
||||||
{
|
{
|
||||||
JSScript *script = NULL;
|
JSScript *script;
|
||||||
JSFunction *fun;
|
JSFunction *fun;
|
||||||
|
|
||||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
if (!JSVAL_IS_PRIMITIVE(v) &&
|
||||||
JSObject *obj = JSVAL_TO_OBJECT(v);
|
JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass) {
|
||||||
JSClass *clasp = JS_GET_CLASS(cx, obj);
|
script = (JSScript *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
|
||||||
|
} else {
|
||||||
if (clasp == &js_ScriptClass) {
|
|
||||||
script = (JSScript *) JS_GetPrivate(cx, obj);
|
|
||||||
} else if (clasp == &js_GeneratorClass) {
|
|
||||||
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
|
|
||||||
fun = gen->frame.fun;
|
|
||||||
script = FUN_SCRIPT(fun);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!script) {
|
|
||||||
fun = JS_ValueToFunction(cx, v);
|
fun = JS_ValueToFunction(cx, v);
|
||||||
if (!fun)
|
if (!fun)
|
||||||
return NULL;
|
return NULL;
|
||||||
script = FUN_SCRIPT(fun);
|
script = FUN_SCRIPT(fun);
|
||||||
if (!script) {
|
}
|
||||||
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
|
|
||||||
JSSMSG_SCRIPTS_ONLY);
|
if (!script) {
|
||||||
}
|
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
|
||||||
|
JSSMSG_SCRIPTS_ONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return script;
|
return script;
|
||||||
@@ -1716,7 +1706,7 @@ Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (VALUE_IS_FUNCTION(cx, argv[i])) {
|
if (VALUE_IS_FUNCTION(cx, argv[i])) {
|
||||||
JSFunction *fun = JS_ValueToFunction(cx, argv[i]);
|
JSFunction *fun = JS_ValueToFunction(cx, argv[i]);
|
||||||
if (fun && (fun->flags & ~7U)) {
|
if (fun && (fun->flags & JSFUN_FLAGS_MASK)) {
|
||||||
uint16 flags = fun->flags;
|
uint16 flags = fun->flags;
|
||||||
fputs("flags:", stdout);
|
fputs("flags:", stdout);
|
||||||
|
|
||||||
@@ -1731,14 +1721,9 @@ Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
SHOW_FLAG(THISP_NUMBER);
|
SHOW_FLAG(THISP_NUMBER);
|
||||||
SHOW_FLAG(THISP_BOOLEAN);
|
SHOW_FLAG(THISP_BOOLEAN);
|
||||||
SHOW_FLAG(EXPR_CLOSURE);
|
SHOW_FLAG(EXPR_CLOSURE);
|
||||||
SHOW_FLAG(TRACEABLE);
|
SHOW_FLAG(INTERPRETED);
|
||||||
|
|
||||||
#undef SHOW_FLAG
|
#undef SHOW_FLAG
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun))
|
|
||||||
fputs(" NULL_CLOSURE", stdout);
|
|
||||||
else if (FUN_FLAT_CLOSURE(fun))
|
|
||||||
fputs(" FLAT_CLOSURE", stdout);
|
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2266,16 +2251,13 @@ Intern(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
static JSBool
|
static JSBool
|
||||||
Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||||
{
|
{
|
||||||
|
JSFunction *fun;
|
||||||
JSObject *funobj, *parent, *clone;
|
JSObject *funobj, *parent, *clone;
|
||||||
|
|
||||||
if (VALUE_IS_FUNCTION(cx, argv[0])) {
|
fun = JS_ValueToFunction(cx, argv[0]);
|
||||||
funobj = JSVAL_TO_OBJECT(argv[0]);
|
if (!fun)
|
||||||
} else {
|
return JS_FALSE;
|
||||||
JSFunction *fun = JS_ValueToFunction(cx, argv[0]);
|
funobj = JS_GetFunctionObject(fun);
|
||||||
if (!fun)
|
|
||||||
return JS_FALSE;
|
|
||||||
funobj = JS_GetFunctionObject(fun);
|
|
||||||
}
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
if (!JS_ValueToObject(cx, argv[1], &parent))
|
if (!JS_ValueToObject(cx, argv[1], &parent))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|||||||
@@ -4490,36 +4490,36 @@ test(testString);
|
|||||||
|
|
||||||
function testToStringBeforeValueOf()
|
function testToStringBeforeValueOf()
|
||||||
{
|
{
|
||||||
var o = {toString: function() { return "s"; }, valueOf: function() { return "v"; } };
|
var o = {toString: function() { return "s"; }, valueOf: function() { return "v"; } };
|
||||||
var a = [];
|
var a = [];
|
||||||
for (var i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
a.push(String(o));
|
a.push(String(o));
|
||||||
return a.join(",");
|
return a.join(",");
|
||||||
}
|
}
|
||||||
testToStringBeforeValueOf.expected = "s,s,s,s,s,s,s,s,s,s";
|
testToStringBeforeValueOf.expected = "s,s,s,s,s,s,s,s,s,s";
|
||||||
testToStringBeforeValueOf.jitstats = {
|
testToStringBeforeValueOf.jitstats = {
|
||||||
recorderStarted: 1,
|
recorderStarted: 1,
|
||||||
sideExitIntoInterpreter: 1
|
sideExitIntoInterpreter: 1
|
||||||
};
|
};
|
||||||
test(testToStringBeforeValueOf);
|
test(testToStringBeforeValueOf);
|
||||||
|
|
||||||
function testNullToString()
|
function testNullToString()
|
||||||
{
|
{
|
||||||
var a = [];
|
var a = [];
|
||||||
for (var i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
a.push(String(null));
|
a.push(String(null));
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
var t = typeof a[i];
|
var t = typeof a[i];
|
||||||
if (t != "string")
|
if (t != "string")
|
||||||
a.push(t);
|
a.push(t);
|
||||||
}
|
}
|
||||||
return a.join(",");
|
return a.join(",");
|
||||||
}
|
}
|
||||||
testNullToString.expected = "null,null,null,null,null,null,null,null,null,null";
|
testNullToString.expected = "null,null,null,null,null,null,null,null,null,null";
|
||||||
testNullToString.jitstats = {
|
testNullToString.jitstats = {
|
||||||
recorderStarted: 2,
|
recorderStarted: 2,
|
||||||
sideExitIntoInterpreter: 2,
|
sideExitIntoInterpreter: 2,
|
||||||
recorderAborted: 0
|
recorderAborted: 0
|
||||||
};
|
};
|
||||||
test(testNullToString);
|
test(testNullToString);
|
||||||
|
|
||||||
@@ -4532,162 +4532,12 @@ function testAddNull()
|
|||||||
}
|
}
|
||||||
testAddNull.expected = "null,";
|
testAddNull.expected = "null,";
|
||||||
testAddNull.jitstats = {
|
testAddNull.jitstats = {
|
||||||
recorderStarted: 1,
|
recorderStarted: 1,
|
||||||
sideExitIntoInterpreter: 1,
|
sideExitIntoInterpreter: 1,
|
||||||
recorderAborted: 0
|
recorderAborted: 0
|
||||||
};
|
};
|
||||||
test(testAddNull);
|
test(testAddNull);
|
||||||
|
|
||||||
function testClosures()
|
|
||||||
{
|
|
||||||
function MyObject(id) {
|
|
||||||
var thisObject = this;
|
|
||||||
this.id = id;
|
|
||||||
this.toString = str;
|
|
||||||
|
|
||||||
function str() {
|
|
||||||
return "" + this.id + thisObject.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var a = [];
|
|
||||||
for (var i = 0; i < 5; i++)
|
|
||||||
a.push(new MyObject(i));
|
|
||||||
return a.toString();
|
|
||||||
}
|
|
||||||
testClosures.expected = "00,11,22,33,44";
|
|
||||||
test(testClosures);
|
|
||||||
|
|
||||||
function testLambdaInitedVar() {
|
|
||||||
var jQuery = function (a, b) {
|
|
||||||
return jQuery && jQuery.length;
|
|
||||||
}
|
|
||||||
return jQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
testLambdaInitedVar.expected = 2;
|
|
||||||
test(testLambdaInitedVar);
|
|
||||||
|
|
||||||
function testNestedEscapingLambdas()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return (function() {
|
|
||||||
var a = [], r = [];
|
|
||||||
function setTimeout(f, t) {
|
|
||||||
a.push(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
function runTimeouts() {
|
|
||||||
for (var i = 0; i < a.length; i++)
|
|
||||||
a[i]();
|
|
||||||
}
|
|
||||||
|
|
||||||
var $foo = "#nothiddendiv";
|
|
||||||
setTimeout(function(){
|
|
||||||
r.push($foo);
|
|
||||||
setTimeout(function(){
|
|
||||||
r.push($foo);
|
|
||||||
}, 100);
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
runTimeouts();
|
|
||||||
|
|
||||||
return r.join("");
|
|
||||||
})();
|
|
||||||
} catch (e) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
testNestedEscapingLambdas.expected = "#nothiddendiv#nothiddendiv";
|
|
||||||
test(testNestedEscapingLambdas);
|
|
||||||
|
|
||||||
function testPropagatedFunArgs()
|
|
||||||
{
|
|
||||||
var win = this;
|
|
||||||
var res = [], q = [];
|
|
||||||
function addEventListener(name, func, flag) {
|
|
||||||
q.push(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
var pageInfo, obs;
|
|
||||||
addEventListener("load", handleLoad, true);
|
|
||||||
|
|
||||||
var observer = {
|
|
||||||
observe: function(win, topic, data) {
|
|
||||||
// obs.removeObserver(observer, "page-info-dialog-loaded");
|
|
||||||
handlePageInfo();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function handleLoad() {
|
|
||||||
pageInfo = { toString: function() { return "pageInfo"; } };
|
|
||||||
obs = { addObserver: function (obs, topic, data) { obs.observe(win, topic, data); } };
|
|
||||||
obs.addObserver(observer, "page-info-dialog-loaded", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePageInfo() {
|
|
||||||
res.push(pageInfo);
|
|
||||||
function $(aId) { res.push(pageInfo); };
|
|
||||||
var feedTab = $("feedTab");
|
|
||||||
}
|
|
||||||
|
|
||||||
q[0]();
|
|
||||||
return res.join(',');
|
|
||||||
}
|
|
||||||
testPropagatedFunArgs.expected = "pageInfo,pageInfo";
|
|
||||||
test(testPropagatedFunArgs);
|
|
||||||
|
|
||||||
// Second testPropagatedFunArgs test -- this is a crash-test.
|
|
||||||
(function () {
|
|
||||||
var escapee;
|
|
||||||
|
|
||||||
function testPropagatedFunArgs()
|
|
||||||
{
|
|
||||||
const magic = 42;
|
|
||||||
|
|
||||||
var win = this;
|
|
||||||
var res = [], q = [];
|
|
||||||
function addEventListener(name, func, flag) {
|
|
||||||
q.push(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
var pageInfo = "pageInfo", obs;
|
|
||||||
addEventListener("load", handleLoad, true);
|
|
||||||
|
|
||||||
var observer = {
|
|
||||||
observe: function(win, topic, data) {
|
|
||||||
// obs.removeObserver(observer, "page-info-dialog-loaded");
|
|
||||||
handlePageInfo();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function handleLoad() {
|
|
||||||
//pageInfo = { toString: function() { return "pageInfo"; } };
|
|
||||||
obs = { addObserver: function (obs, topic, data) { obs.observe(win, topic, data); } };
|
|
||||||
obs.addObserver(observer, "page-info-dialog-loaded", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePageInfo() {
|
|
||||||
res.push(pageInfo);
|
|
||||||
function $(aId) {
|
|
||||||
function notSafe() {
|
|
||||||
return magic;
|
|
||||||
}
|
|
||||||
print(notSafe());
|
|
||||||
res.push(pageInfo);
|
|
||||||
};
|
|
||||||
var feedTab = $("feedTab");
|
|
||||||
}
|
|
||||||
|
|
||||||
escapee = q[0];
|
|
||||||
return res.join(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
testPropagatedFunArgs();
|
|
||||||
|
|
||||||
escapee();
|
|
||||||
})();
|
|
||||||
|
|
||||||
function testStringLengthNoTinyId()
|
function testStringLengthNoTinyId()
|
||||||
{
|
{
|
||||||
var x = "unset";
|
var x = "unset";
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ function test()
|
|||||||
var f;
|
var f;
|
||||||
|
|
||||||
f = function() { (function x() { }); return x; }
|
f = function() { (function x() { }); return x; }
|
||||||
expect = 'function() { return x; }';
|
expect = 'function() { (function x() { }); return x; }';
|
||||||
actual = f + '';
|
actual = f + '';
|
||||||
compareSource(expect, actual, summary);
|
compareSource(expect, actual, summary);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ function test()
|
|||||||
printBugNumber(BUGNUMBER);
|
printBugNumber(BUGNUMBER);
|
||||||
printStatus (summary);
|
printStatus (summary);
|
||||||
|
|
||||||
expect = '1';
|
expect = '2';
|
||||||
|
|
||||||
// ------- Comment #74 From Jesse Ruderman
|
// ------- Comment #74 From Jesse Ruderman
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ function test()
|
|||||||
printBugNumber(BUGNUMBER);
|
printBugNumber(BUGNUMBER);
|
||||||
printStatus (summary);
|
printStatus (summary);
|
||||||
|
|
||||||
expect = '1';
|
expect = '2';
|
||||||
|
|
||||||
// ------- Comment #77 From Brendan Eich
|
// ------- Comment #77 From Brendan Eich
|
||||||
|
|
||||||
|
|||||||
@@ -57,11 +57,7 @@ function test()
|
|||||||
|
|
||||||
// Does not require -j:
|
// Does not require -j:
|
||||||
// =====
|
// =====
|
||||||
try {
|
({ set x x () { for(x in function(){}){}} })
|
||||||
eval("({ set x x () { for(x in function(){}){}} })");
|
|
||||||
} catch (e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assertion failure: JOF_OPTYPE(op) == JOF_ATOM, at ../jsemit.cpp:1710
|
// Assertion failure: JOF_OPTYPE(op) == JOF_ATOM, at ../jsemit.cpp:1710
|
||||||
// =====
|
// =====
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ js1_5/Regress/regress-312588.js
|
|||||||
js1_5/Regress/regress-314401.js
|
js1_5/Regress/regress-314401.js
|
||||||
js1_5/Regress/regress-329530.js
|
js1_5/Regress/regress-329530.js
|
||||||
js1_5/Regress/regress-3649-n.js
|
js1_5/Regress/regress-3649-n.js
|
||||||
|
js1_5/Regress/regress-451322.js
|
||||||
js1_6/extensions/regress-455464-04.js
|
js1_6/extensions/regress-455464-04.js
|
||||||
js1_6/extensions/regress-456826.js
|
js1_6/extensions/regress-456826.js
|
||||||
js1_7/extensions/regress-455982-01.js
|
js1_7/extensions/regress-455982-01.js
|
||||||
|
|||||||
Reference in New Issue
Block a user