Make __noSuchMethod__ work with E4X (312196, r/sr=mrbkap/shaver).

This commit is contained in:
brendan%mozilla.org 2005-10-15 07:30:59 +00:00
parent d0872eefe9
commit 3689f9d650
8 changed files with 96 additions and 24 deletions

View File

@ -970,6 +970,7 @@ struct JSObjectOps {
struct JSXMLObjectOps {
JSObjectOps base;
JSGetMethodOp getMethod;
JSSetMethodOp setMethod;
JSEnumerateValuesOp enumerateValues;
JSEqualityOp equality;
JSConcatenateOp concatenate;

View File

@ -4451,10 +4451,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* First, emit code for the left operand to evaluate the callable or
* constructable object expression.
*
* For E4X, if calling rather than constructing (TOK_LP), and if this
* expression is a member reference, select JSOP_GETMETHOD instead of
* JSOP_GETPROP. ECMA-357 separates XML method lookup from the normal
* property lookup done for native objects.
* For E4X, if this expression is a dotted member reference, select
* JSOP_GETMETHOD instead of JSOP_GETPROP. ECMA-357 separates XML
* method lookup from the normal property id lookup done for native
* objects.
*/
pn2 = pn->pn_head;
#if JS_HAS_XML_SUPPORT

View File

@ -890,6 +890,7 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
*/
if (JSVAL_IS_PRIMITIVE(v)) {
#if JS_HAS_NO_SUCH_METHOD
jsid id;
jsbytecode *pc;
jsatomid atomIndex;
JSAtom *atom;
@ -918,10 +919,20 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
goto out2;
thisp = frame.thisp;
ok = OBJ_GET_PROPERTY(cx, thisp,
ATOM_TO_JSID(cx->runtime->atomState
.noSuchMethodAtom),
&v);
id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
if (OBJECT_IS_XML(cx, thisp)) {
JSXMLObjectOps *ops;
ops = (JSXMLObjectOps *) thisp->map->ops;
thisp = ops->getMethod(cx, thisp, id, &v);
if (!thisp) {
ok = JS_FALSE;
goto out2;
}
vp[1] = OBJECT_TO_JSVAL(thisp);
} else {
ok = OBJ_GET_PROPERTY(cx, thisp, id, &v);
}
if (!ok)
goto out2;
if (JSVAL_IS_PRIMITIVE(v))
@ -3641,6 +3652,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
#endif
#if JS_HAS_XML_SUPPORT
case JSOP_GETMETHOD: goto do_JSOP_GETMETHOD;
case JSOP_SETMETHOD: goto do_JSOP_SETMETHOD;
#endif
case JSOP_INITCATCHVAR: goto do_JSOP_INITCATCHVAR;
case JSOP_NAMEDFUNOBJ: goto do_JSOP_NAMEDFUNOBJ;
@ -5219,6 +5231,28 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
STORE_OPND(-1, rval);
END_LITOPX_CASE
BEGIN_LITOPX_CASE(JSOP_SETMETHOD, 0)
/* Get an immediate atom naming the property. */
id = ATOM_TO_JSID(atom);
rval = FETCH_OPND(-1);
FETCH_OBJECT(cx, -2, lval, obj);
SAVE_SP(fp);
/* Special-case XML object method lookup, per ECMA-357. */
if (OBJECT_IS_XML(cx, obj)) {
JSXMLObjectOps *ops;
ops = (JSXMLObjectOps *) obj->map->ops;
ok = ops->setMethod(cx, obj, id, &rval);
} else {
CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
}
if (!ok)
goto out;
--sp;
STORE_OPND(-1, rval);
END_LITOPX_CASE
case JSOP_GETFUNNS:
ok = js_GetFunctionNamespace(cx, &rval);
if (!ok)

View File

@ -1894,7 +1894,23 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
#if JS_HAS_XML_SUPPORT
BEGIN_LITOPX_CASE(JSOP_GETMETHOD)
goto do_getprop;
GET_QUOTE_AND_FMT("%s.function::[%s]", "%s.function::%s", rval);
lval = POP_STR();
todo = Sprint(&ss->sprinter, fmt, lval, rval);
END_LITOPX_CASE
BEGIN_LITOPX_CASE(JSOP_SETMETHOD)
GET_ATOM_QUOTE_AND_FMT("%s.function::[%s] %s= %s",
"%s.function::%s %s= %s",
xval);
rval = POP_STR();
lval = POP_STR();
sn = js_GetSrcNote(jp->script, pc - 1);
todo = Sprint(&ss->sprinter, fmt, lval, xval,
(sn && SN_TYPE(sn) == SRC_ASSIGNOP)
? js_CodeSpec[lastop].token
: "",
rval);
END_LITOPX_CASE
#endif
@ -2018,6 +2034,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
#endif
#if JS_HAS_XML_SUPPORT
case JSOP_GETMETHOD: goto do_JSOP_GETMETHOD;
case JSOP_SETMETHOD: goto do_JSOP_SETMETHOD;
#endif
case JSOP_NAMEDFUNOBJ: goto do_JSOP_NAMEDFUNOBJ;
case JSOP_NUMBER: goto do_JSOP_NUMBER;

View File

@ -391,3 +391,4 @@ OPDEF(JSOP_LITOPX, 191,"litopx", NULL, 5, 0, 0, 12, JOF_LITOPX
*/
OPDEF(JSOP_STARTXML, 192,"startxml", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_STARTXMLEXPR, 193,"startxmlexpr",NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_SETMETHOD, 194,"setmethod", NULL, 3, 2, 1, 1, JOF_CONST|JOF_PROP)

View File

@ -2428,7 +2428,9 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
tc->flags |= TCF_FUN_HEAVYWEIGHT;
break;
case TOK_DOT:
pn2->pn_op = JSOP_SETPROP;
pn2->pn_op = (pn2->pn_op == JSOP_GETMETHOD)
? JSOP_SETMETHOD
: JSOP_SETPROP;
break;
case TOK_LB:
pn2->pn_op = JSOP_SETELEM;

View File

@ -504,6 +504,10 @@ typedef JSObject *
(* JS_DLL_CALLBACK JSGetMethodOp)(JSContext *cx, JSObject *obj, jsid id,
jsval *vp);
typedef JSBool
(* JS_DLL_CALLBACK JSSetMethodOp)(JSContext *cx, JSObject *obj, jsid id,
jsval *vp);
typedef JSBool
(* JS_DLL_CALLBACK JSEnumerateValuesOp)(JSContext *cx, JSObject *obj,
JSIterateOp enum_op,

View File

@ -3853,8 +3853,11 @@ GetFunction(JSContext *cx, JSObject *obj, JSXML *xml, jsid id, jsval *vp)
if (JSVAL_IS_FUNCTION(cx, fval)) {
if (xml && OBJECT_IS_XML(cx, obj)) {
fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval));
if ((fun->spare & CLASS_TO_MASK(xml->xml_class)) == 0)
if (fun->spare &&
(fun->spare & CLASS_TO_MASK(xml->xml_class)) == 0) {
/* XML method called on XMLList or vice versa. */
fval = JSVAL_VOID;
}
}
break;
}
@ -4422,6 +4425,15 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
goto bad;
}
nameqn = ToXMLName(cx, id, &funid);
if (!nameqn)
goto bad;
if (funid) {
ok = js_SetProperty(cx, obj, funid, vp);
goto out;
}
nameobj = nameqn->object;
if (JSXML_HAS_VALUE(xml))
goto out;
@ -4439,15 +4451,6 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
*vp = OBJECT_TO_JSVAL(vxml->object);
}
nameqn = ToXMLName(cx, id, &funid);
if (!nameqn)
goto bad;
if (funid) {
ok = js_SetProperty(cx, obj, funid, vp);
goto out;
}
nameobj = nameqn->object;
/*
* 6.
* Erratum: why is this done here, so early? use is way later....
@ -5143,12 +5146,15 @@ retry:
}
} else if (HasSimpleContent(xml)) {
JSString *str;
JSObject *tmp;
str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
if (!str || !js_ValueToObject(cx, STRING_TO_JSVAL(str), &obj))
if (!str || !js_ValueToObject(cx, STRING_TO_JSVAL(str), &tmp))
return NULL;
if (!js_GetProperty(cx, obj, id, &fval))
if (!js_GetProperty(cx, tmp, id, &fval))
return NULL;
if (!JSVAL_IS_VOID(fval))
obj = tmp;
}
}
@ -5156,6 +5162,12 @@ retry:
return obj;
}
static JSBool
xml_setMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
return js_SetProperty(cx, obj, id, vp);
}
static JSBool
xml_enumerateValues(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp, jsval *vp)
@ -5344,8 +5356,9 @@ JS_FRIEND_DATA(JSXMLObjectOps) js_XMLObjectOps = {
js_SetProtoOrParent, js_SetProtoOrParent,
xml_mark, xml_clear,
NULL, NULL },
xml_getMethod, xml_enumerateValues,
xml_equality, xml_concatenate
xml_getMethod, xml_setMethod,
xml_enumerateValues, xml_equality,
xml_concatenate
};
static JSObjectOps *