Backout e2807e45402c for Android b-c permaorange and 502c33ae0d81, 3326454d70f5 for Android M5 permaorange.

This commit is contained in:
Marco Bonardo 2011-09-03 12:22:10 +02:00
parent 5e9f41713e
commit 2c9501a685
29 changed files with 69 additions and 201 deletions

View File

@ -60,6 +60,9 @@
#include "nsIScriptContext.h"
#include "nsIJSContextStack.h"
/* XXX private JS headers. */
#include "jscompartment.h"
/*
* defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
* script hook. This was a hack to avoid some js engine problems that should

View File

@ -191,6 +191,7 @@ INSTALLED_HEADERS = \
jscell.h \
jsgcchunk.h \
jsgcstats.h \
jscompartment.h \
jshash.h \
jsinfer.h \
jsinferinlines.h \

View File

@ -1,4 +0,0 @@
function test() {
for each (var i in []) {}
}
for each (new test().p in [0]) {}

View File

@ -1,13 +0,0 @@
var x = {f: 1, g: 0};
function f() {
for each (new f().nosuch.prop in x)
throw 'FAIL';
}
var e;
try {
f();
} catch (exc) {
e = exc;
}
assertEq(e instanceof InternalError, true);

View File

@ -1,15 +1,15 @@
// |jit-test| debug
f = (function() {
function b() {
"use strict";
Object.defineProperty(this, "x", ({}));
}
for each(let d in [0, 0]) {
try {
b(d);
} catch (e) {}
}
});
trap(f, 53, undefined);
f();
function b() {
"use strict";
Object.defineProperty(this, "x", ({}));
}
for each(let d in [0, 0]) {
try {
b(d);
} catch (e) {}
}
})
trap(f, 54, undefined);
f()

View File

@ -4640,8 +4640,7 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS
case TOK_LP:
if (!js_EmitTree(cx, cg, lhs))
return false;
JS_ASSERT(lhs->pn_xflags & PNX_SETCALL);
offset += 2;
offset++;
break;
#if JS_HAS_XML_SUPPORT
case TOK_UNARYOP:
@ -4718,13 +4717,8 @@ EmitAssignment(JSContext *cx, JSCodeGenerator *cg, JSParseNode *lhs, JSOp op, JS
if (!js_EmitTree(cx, cg, rhs))
return false;
} else {
/*
* The value to assign is the next enumeration value in a for-in loop.
* That value is produced by a JSOP_ITERNEXT op, previously emitted.
* If offset == 1, that slot is already at the top of the
* stack. Otherwise, rearrange the stack to put that value on top.
*/
if (offset != 1 && js_Emit2(cx, cg, JSOP_PICK, offset - 1) < 0)
/* The value to assign is the next enumeration value in a for-in loop. */
if (js_Emit2(cx, cg, JSOP_ITERNEXT, offset) < 0)
return false;
}
@ -5427,6 +5421,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
SET_STATEMENT_TOP(&stmtInfo, top);
if (EmitTraceOp(cx, cg, NULL) < 0)
return JS_FALSE;
#ifdef DEBUG
intN loopDepth = cg->stackDepth;
#endif
@ -5437,8 +5432,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* so that the decompiler can distinguish 'for (x in y)' from
* 'for (var x in y)'.
*/
if (js_Emit1(cx, cg, JSOP_ITERNEXT) < 0)
return false;
if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL))
return false;
tmp2 = CG_OFFSET(cg);

View File

@ -44,7 +44,6 @@
#include "jsobjinlines.h"
using namespace js;
using namespace JS;
JS_FRIEND_API(JSString *)
JS_GetAnonymousString(JSRuntime *rt)
@ -113,53 +112,6 @@ JS_ObjectCountDynamicSlots(JSObject *obj)
return 0;
}
JS_FRIEND_API(JSPrincipals *)
JS_GetCompartmentPrincipals(JSCompartment *compartment)
{
return compartment->principals;
}
JS_FRIEND_API(JSBool)
JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc)
{
return cx->compartment->wrap(cx, desc);
}
AutoPreserveCompartment::AutoPreserveCompartment(JSContext *cx
JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
: cx(cx), oldCompartment(cx->compartment)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
AutoPreserveCompartment::~AutoPreserveCompartment()
{
/* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
cx->compartment = oldCompartment;
}
AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
: cx(cx), oldCompartment(cx->compartment)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
cx->setCompartment(newCompartment);
}
AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSObject *target
JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
: cx(cx), oldCompartment(cx->compartment)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
cx->setCompartment(target->compartment());
}
AutoSwitchCompartment::~AutoSwitchCompartment()
{
/* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
cx->compartment = oldCompartment;
}
/*
* The below code is for temporary telemetry use. It can be removed when
* sufficient data has been harvested.

View File

@ -93,45 +93,6 @@ extern JS_FRIEND_API(void)
JS_GetTypeInferenceObjectStats(/*TypeObject*/ void *object,
TypeInferenceMemoryStats *stats);
extern JS_FRIEND_API(JSPrincipals *)
JS_GetCompartmentPrincipals(JSCompartment *compartment);
#ifdef __cplusplus
extern JS_FRIEND_API(JSBool)
JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc);
#endif
JS_END_EXTERN_C
#ifdef __cplusplus
namespace JS {
class JS_FRIEND_API(AutoPreserveCompartment) {
private:
JSContext *cx;
JSCompartment *oldCompartment;
public:
AutoPreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM);
~AutoPreserveCompartment();
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class JS_FRIEND_API(AutoSwitchCompartment) {
private:
JSContext *cx;
JSCompartment *oldCompartment;
public:
AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
JS_GUARD_OBJECT_NOTIFIER_PARAM);
AutoSwitchCompartment(JSContext *cx, JSObject *target JS_GUARD_OBJECT_NOTIFIER_PARAM);
~AutoSwitchCompartment();
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
}
#endif
#endif /* jsfriendapi_h___ */

View File

@ -2666,10 +2666,11 @@ END_CASE(JSOP_MOREITER)
BEGIN_CASE(JSOP_ITERNEXT)
{
JS_ASSERT(regs.sp - 1 >= regs.fp()->base());
JS_ASSERT(regs.sp[-1].isObject());
Value *itervp = regs.sp - GET_INT8(regs.pc);
JS_ASSERT(itervp >= regs.fp()->base());
JS_ASSERT(itervp->isObject());
PUSH_NULL();
if (!IteratorNext(cx, &regs.sp[-2].toObject(), &regs.sp[-1]))
if (!IteratorNext(cx, &itervp->toObject(), &regs.sp[-1]))
goto error;
}
END_CASE(JSOP_ITERNEXT)

View File

@ -2723,26 +2723,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
sn = NULL;
break;
case JSOP_PICK:
{
uintN i = pc[1];
LOCAL_ASSERT(ss->top > i + 1);
uintN bottom = ss->top - (i + 1);
ptrdiff_t pickedOffset = ss->offsets[bottom];
memmove(ss->offsets + bottom, ss->offsets + bottom + 1,
i * sizeof(ss->offsets[0]));
ss->offsets[ss->top - 1] = pickedOffset;
jsbytecode pickedOpcode = ss->opcodes[bottom];
memmove(ss->opcodes + bottom, ss->opcodes + bottom + 1,
i * sizeof(ss->opcodes[0]));
ss->opcodes[ss->top - 1] = pickedOpcode;
todo = -2;
break;
}
case JSOP_ENTERWITH:
LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
rval = POP_STR();
@ -3251,9 +3231,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* <<RHS>>
* iter
* pc: goto/gotox C [src_for_in(B, D)]
* A: trace
* iternext
* <<LHS = result_of_iternext>>
* A: <<LHS = iternext>>
* B: pop [maybe a src_decl_var/let]
* <<S>>
* C: moreiter
@ -3276,14 +3254,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* JSOP_MOREITER or JSOP_IFNE, though we do quick asserts
* to check that they are there.
*/
LOCAL_ASSERT(pc[-JSOP_ITER_LENGTH] == JSOP_ITER);
LOCAL_ASSERT(pc[js_CodeSpec[op].length] == JSOP_TRACE);
LOCAL_ASSERT(pc[js_CodeSpec[op].length + JSOP_TRACE_LENGTH] == JSOP_ITERNEXT);
cond = GetJumpOffset(pc, pc);
next = js_GetSrcNoteOffset(sn, 0);
tail = js_GetSrcNoteOffset(sn, 1);
LOCAL_ASSERT(pc[next] == JSOP_POP);
LOCAL_ASSERT(pc[cond] == JSOP_MOREITER);
JS_ASSERT(pc[next] == JSOP_POP);
JS_ASSERT(pc[cond] == JSOP_MOREITER);
DECOMPILE_CODE(pc + oplen, next - oplen);
lval = POP_STR();
@ -3291,7 +3266,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* This string "<next>" comes from jsopcode.tbl. It stands
* for the result pushed by JSOP_ITERNEXT.
*/
LOCAL_ASSERT(strcmp(lval + strlen(lval) - 9, " = <next>") == 0);
JS_ASSERT(strcmp(lval + strlen(lval) - 9, " = <next>") == 0);
const_cast<char *>(lval)[strlen(lval) - 9] = '\0';
LOCAL_ASSERT(ss->top >= 1);

View File

@ -199,9 +199,8 @@ OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|J
OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
/*
* Sometimes web pages do 'o.Item(i) = j'. This is not an early SyntaxError,
* for web compatibility. Instead we emit JSOP_SETCALL after the function call,
* an opcode that always throws.
* Host object extension: given 'o.item(i) = j', the left-hand side compiles
* JSOP_SETCALL after JSOP_CALL, JSOP_EVAL, JSOP_FUNAPPLY, or JSOP_FUNCALL.
*/
OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 1, 1, 2, 18, JOF_BYTE)
@ -219,7 +218,7 @@ OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 1, 1, 2, 18, JOF_BYTE)
*/
OPDEF(JSOP_ITER, 75, "iter", NULL, 2, 1, 1, 0, JOF_UINT8)
OPDEF(JSOP_MOREITER, 76, "moreiter", NULL, 1, 1, 2, 0, JOF_BYTE)
OPDEF(JSOP_ITERNEXT, 77, "iternext", "<next>", 1, 0, 1, 0, JOF_BYTE)
OPDEF(JSOP_ITERNEXT, 77, "iternext", "<next>", 2, 0, 1, 0, JOF_UINT8)
OPDEF(JSOP_ENDITER, 78, "enditer", NULL, 1, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_FUNAPPLY, 79, "funapply", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE|JOF_TYPESET)

View File

@ -185,7 +185,6 @@ class InlineMap;
class PropertyCache;
struct PropertyCacheEntry;
struct PropertyDescriptor;
struct Shape;
struct EmptyShape;

View File

@ -14862,7 +14862,7 @@ JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_ITERNEXT()
{
LIns* v_ins;
Value &iterobj_val = stackval(-1);
Value &iterobj_val = stackval(-GET_INT8(cx->regs().pc));
CHECK_STATUS_A(unboxNextValue(iterobj_val, v_ins));
stack(0, v_ins);
return ARECORD_CONTINUE;

View File

@ -222,7 +222,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
* before deserialization of bytecode. If the saved version does not match
* the current version, abort deserialization and invalidate the file.
*/
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 94)
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 93)
/*
* Library-private functions.

View File

@ -1682,7 +1682,7 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_ARGUMENTS)
BEGIN_CASE(JSOP_ITERNEXT)
iterNext();
iterNext(GET_INT8(PC));
END_CASE(JSOP_ITERNEXT)
BEGIN_CASE(JSOP_DUP)
@ -5583,9 +5583,9 @@ mjit::Compiler::iter(uintN flags)
* of a for-in loop to put the next value on the stack.
*/
void
mjit::Compiler::iterNext()
mjit::Compiler::iterNext(ptrdiff_t offset)
{
FrameEntry *fe = frame.peek(-1);
FrameEntry *fe = frame.peek(-offset);
RegisterID reg = frame.tempRegForData(fe);
/* Is it worth trying to pin this longer? Prolly not. */
@ -5629,6 +5629,7 @@ mjit::Compiler::iterNext()
frame.freeReg(T2);
stubcc.leave();
stubcc.masm.move(Imm32(offset), Registers::ArgReg1);
OOL_STUBCALL(stubs::IterNext, REJOIN_FALLTHROUGH);
frame.pushUntypedPayload(JSVAL_TYPE_STRING, T3);

View File

@ -578,7 +578,7 @@ class Compiler : public BaseCompiler
bool constantFoldBranch(jsbytecode *target, bool taken);
bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
bool iter(uintN flags);
void iterNext();
void iterNext(ptrdiff_t offset);
bool iterMore(jsbytecode *target);
void iterEnd();
MaybeJump loadDouble(FrameEntry *fe, FPRegisterID *fpReg, bool *allocated);

View File

@ -1843,12 +1843,12 @@ stubs::InitMethod(VMFrame &f, JSAtom *atom)
}
void JS_FASTCALL
stubs::IterNext(VMFrame &f)
stubs::IterNext(VMFrame &f, int32 offset)
{
JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
JS_ASSERT(f.regs.sp[-1].isObject());
JS_ASSERT(f.regs.sp - offset >= f.fp()->base());
JS_ASSERT(f.regs.sp[-offset].isObject());
JSObject *iterobj = &f.regs.sp[-1].toObject();
JSObject *iterobj = &f.regs.sp[-offset].toObject();
f.regs.sp[0].setNull();
f.regs.sp++;
if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))

View File

@ -192,7 +192,7 @@ void JS_FASTCALL StrictEq(VMFrame &f);
void JS_FASTCALL StrictNe(VMFrame &f);
void JS_FASTCALL Iter(VMFrame &f, uint32 flags);
void JS_FASTCALL IterNext(VMFrame &f);
void JS_FASTCALL IterNext(VMFrame &f, int32 offset);
JSBool JS_FASTCALL IterMore(VMFrame &f);
void JS_FASTCALL EndIter(VMFrame &f);

View File

@ -74,6 +74,7 @@
#include "nsNetUtil.h"
#include "nsDOMFile.h"
#include "jsxdrapi.h"
#include "jscompartment.h"
#include "jsprf.h"
// For reporting errors with the console service
#include "nsIScriptError.h"
@ -751,8 +752,8 @@ mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile,
JSCLContextHelper cx(this);
// preserve caller's compartment
JS::AutoPreserveCompartment pc(cx);
js::PreserveCompartment pc(cx);
rv = mSystemPrincipal->GetJSPrincipals(cx, &jsPrincipals);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -1063,7 +1063,7 @@ CreateNewCompartment(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
*global = tempGlobal;
*compartment = tempGlobal->compartment();
JS::AutoSwitchCompartment sc(cx, *compartment);
js::SwitchToCompartment sc(cx, *compartment);
JS_SetCompartmentPrivate(cx, *compartment, priv_holder.forget());
return true;
}
@ -1095,7 +1095,7 @@ xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
}
else
{
JS::AutoSwitchCompartment sc(cx, *compartment);
js::SwitchToCompartment sc(cx, *compartment);
JSObject *tempGlobal = JS_NewGlobalObject(cx, clasp);
if(!tempGlobal)
@ -1132,7 +1132,7 @@ xpc_CreateMTGlobalObject(JSContext *cx, JSClass *clasp,
}
else
{
JS::AutoSwitchCompartment sc(cx, *compartment);
js::SwitchToCompartment sc(cx, *compartment);
JSObject *tempGlobal = JS_NewGlobalObject(cx, clasp);
if(!tempGlobal)
@ -2565,7 +2565,7 @@ nsXPConnect::CheckForDebugMode(JSRuntime *rt) {
js::CompartmentVector &vector = rt->compartments;
for (JSCompartment **p = vector.begin(); p != vector.end(); ++p) {
JSCompartment *comp = *p;
if (!JS_GetCompartmentPrincipals(comp)) {
if (!comp->principals) {
/* Ignore special compartments (atoms, JSD compartments) */
continue;
}

View File

@ -105,8 +105,8 @@ WrappedJSDyingJSObjectFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
{
if(wrapper->IsSubjectToFinalization())
{
JS::AutoSwitchCompartment sc(data->cx,
wrapper->GetJSObjectPreserveColor());
js::SwitchToCompartment sc(data->cx,
wrapper->GetJSObjectPreserveColor());
if(JS_IsAboutToBeFinalized(data->cx,
wrapper->GetJSObjectPreserveColor()))
data->array->AppendElement(wrapper);

View File

@ -58,8 +58,8 @@
#include "jsinterp.h"
#include "jscntxt.h"
#include "jsdbgapi.h"
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jscompartment.h"
#include "nscore.h"
#include "nsXPCOM.h"
#include "nsAutoPtr.h"

View File

@ -442,7 +442,7 @@ XPCWrappedNativeScope::FinishedMarkPhaseOfGC(JSContext* cx, XPCJSRuntime* rt)
{
XPCWrappedNativeScope* next = cur->mNext;
JS::AutoSwitchCompartment sc(cx, cur->mGlobalJSObject);
js::SwitchToCompartment sc(cx, cur->mGlobalJSObject);
if(cur->mGlobalJSObject &&
JS_IsAboutToBeFinalized(cx, cur->mGlobalJSObject))

View File

@ -53,11 +53,10 @@
namespace xpc {
nsIPrincipal *
static nsIPrincipal *
GetCompartmentPrincipal(JSCompartment *compartment)
{
JSPrincipals *prin = JS_GetCompartmentPrincipals(compartment);
return prin ? static_cast<nsJSPrincipals *>(prin)->nsIPrincipalPtr : nsnull;
return compartment->principals ? static_cast<nsJSPrincipals *>(compartment->principals)->nsIPrincipalPtr : 0;
}
bool

View File

@ -44,9 +44,6 @@ class nsIPrincipal;
namespace xpc {
nsIPrincipal *
GetCompartmentPrincipal(JSCompartment *compartment);
class AccessCheck {
public:
static bool isSameOrigin(JSCompartment *a, JSCompartment *b);

View File

@ -42,7 +42,6 @@
#include "XPCWrapper.h"
#include "CrossOriginWrapper.h"
#include "AccessCheck.h"
#include "WrapperFactory.h"
namespace xpc {
@ -63,6 +62,12 @@ CrossOriginWrapper::~CrossOriginWrapper()
{
}
static nsIPrincipal *
GetCompartmentPrincipal(JSCompartment *compartment)
{
return static_cast<nsJSPrincipals *>(compartment->principals)->nsIPrincipalPtr;
}
bool
CrossOriginWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
bool set, js::PropertyDescriptor *desc)

View File

@ -265,8 +265,7 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
JSObject *xrayHolder = nsnull;
JSWrapper *wrapper;
CompartmentPrivate *targetdata =
static_cast<CompartmentPrivate *>(JS_GetCompartmentPrivate(cx, target));
CompartmentPrivate *targetdata = static_cast<CompartmentPrivate *>(target->data);
if (AccessCheck::isChrome(target)) {
if (AccessCheck::isChrome(origin)) {
wrapper = &JSCrossCompartmentWrapper::singleton;

View File

@ -556,7 +556,7 @@ XrayWrapper<Base>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid
if (desc->obj)
desc->obj = wrapper;
return JS_WrapPropertyDescriptor(cx, desc_in);
return cx->compartment->wrap(cx, desc_in);
}
if (!this->resolveOwnProperty(cx, wrapper, id, set, desc_in))
@ -627,7 +627,7 @@ XrayWrapper<Base>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, js
}
desc->obj = (desc->obj == wnObject) ? wrapper : nsnull;
return JS_WrapPropertyDescriptor(cx, desc_in);
return cx->compartment->wrap(cx, desc_in);
}
return this->resolveOwnProperty(cx, wrapper, id, set, desc_in);
@ -649,7 +649,7 @@ XrayWrapper<Base>::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
if (!ac.enter(cx, wnObject))
return false;
if (!JS_WrapPropertyDescriptor(cx, desc))
if (!cx->compartment->wrap(cx, desc))
return false;
return JS_DefinePropertyById(cx, wnObject, id, jsdesc->value, jsdesc->getter, jsdesc->setter,

View File

@ -495,10 +495,9 @@ let Content = {
if (uri)
sendAsyncMessage("Browser:OpenURI", { uri: uri,
referrer: element.ownerDocument.documentURIObject.spec });
} else if (this._highlightElement) {
if (!this._formAssistant.open(element))
sendAsyncMessage("FindAssist:Hide", { });
this._sendMouseEvent("mousemove", this._highlightElement, x, y);
} else if (!this._formAssistant.open(element) && this._highlightElement) {
sendAsyncMessage("FindAssist:Hide", { });
this._sendMouseEvent("mousemove", this._highlightElement, x, y);
this._sendMouseEvent("mousedown", this._highlightElement, x, y);
this._sendMouseEvent("mouseup", this._highlightElement, x, y);
}