ref: 2e2738b2930ccb0fbd04a37f6f214f9967b33a88
parent: dd149b98bd600ce2673d9123bacbafa6b58080af
author: Tor Andersson <tor.andersson@artifex.com>
date: Fri Dec 2 09:13:29 EST 2022
Change js_Value to union to avoid some compiler optimization warnings. Use a union of a union and the padding + type tag, to let the shrstr object size be the full 16 bytes to avoid compiler complaints about stepping out of bounds of the array when it optimizes heavily.
--- a/jsarray.c
+++ b/jsarray.c
@@ -247,8 +247,8 @@
double v;
int c;
- int unx = (a->type == JS_TUNDEFINED);
- int uny = (b->type == JS_TUNDEFINED);
+ int unx = (a->t.type == JS_TUNDEFINED);
+ int uny = (b->t.type == JS_TUNDEFINED);
if (unx) return !uny;
if (uny) return -1;
--- a/jsgc.c
+++ b/jsgc.c
@@ -85,9 +85,9 @@
if (node->left->level) jsG_markproperty(J, mark, node->left);
if (node->right->level) jsG_markproperty(J, mark, node->right);
- if (node->value.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark)
+ if (node->value.t.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark)
node->value.u.memstr->gcmark = mark;
- if (node->value.type == JS_TOBJECT && node->value.u.object->gcmark != mark)
+ if (node->value.t.type == JS_TOBJECT && node->value.u.object->gcmark != mark)
jsG_markobject(J, mark, node->value.u.object);
if (node->getter && node->getter->gcmark != mark)
jsG_markobject(J, mark, node->getter);
@@ -106,9 +106,9 @@
int i;
for (i = 0; i < obj->u.a.flat_length; ++i) {
js_Value *v = &obj->u.a.array[i];
- if (v->type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
+ if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
v->u.memstr->gcmark = mark;
- if (v->type == JS_TOBJECT && v->u.object->gcmark != mark)
+ if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark)
jsG_markobject(J, mark, v->u.object);
}
}
@@ -128,9 +128,9 @@
js_Value *v = J->stack;
int n = J->top;
while (n--) {
- if (v->type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
+ if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
v->u.memstr->gcmark = mark;
- if (v->type == JS_TOBJECT && v->u.object->gcmark != mark)
+ if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark)
jsG_markobject(J, mark, v->u.object);
++v;
}
--- a/jsi.h
+++ b/jsi.h
@@ -64,8 +64,8 @@
void *js_realloc(js_State *J, void *ptr, int size);
void js_free(js_State *J, void *ptr);
+typedef union js_Value js_Value;
typedef struct js_Regexp js_Regexp;
-typedef struct js_Value js_Value;
typedef struct js_Object js_Object;
typedef struct js_String js_String;
typedef struct js_Ast js_Ast;
@@ -329,18 +329,20 @@
purpose as the string zero terminator.
*/
-struct js_Value
+union js_Value
{
+ struct {
+ char pad[15];
+ char type; /* type tag overlaps with final byte of shrstr */
+ } t;
union {
+ char shrstr[16];
int boolean;
double number;
- char shrstr[8];
const char *litstr;
js_String *memstr;
js_Object *object;
} u;
- char pad[7]; /* extra storage for shrstr */
- char type; /* type tag and zero terminator for shrstr */
};
struct js_String
--- a/jsobject.c
+++ b/jsobject.c
@@ -312,7 +312,7 @@
if (ref->left->level)
O_create_walk(J, obj, ref->left);
if (!(ref->atts & JS_DONTENUM)) {
- if (ref->value.type != JS_TOBJECT)
+ if (ref->value.t.type != JS_TOBJECT)
js_typeerror(J, "not an object");
ToPropertyDescriptor(J, obj, ref->name, ref->value.u.object);
}
--- a/jsproperty.c
+++ b/jsproperty.c
@@ -22,7 +22,7 @@
static js_Property sentinel = {
&sentinel, &sentinel,
0, 0,
- { {0}, {0}, JS_TUNDEFINED },
+ { { {0}, JS_TUNDEFINED } },
NULL, NULL, ""
};
@@ -33,7 +33,7 @@
node->left = node->right = &sentinel;
node->level = 1;
node->atts = 0;
- node->value.type = JS_TUNDEFINED;
+ node->value.t.type = JS_TUNDEFINED;
node->value.u.number = 0;
node->getter = NULL;
node->setter = NULL;
--- a/jsrun.c
+++ b/jsrun.c
@@ -13,7 +13,7 @@
static void js_trystackoverflow(js_State *J)
{
- STACK[TOP].type = JS_TLITSTR;
+ STACK[TOP].t.type = JS_TLITSTR;
STACK[TOP].u.litstr = "exception stack overflow";
++TOP;
js_throw(J);
@@ -21,7 +21,7 @@
static void js_stackoverflow(js_State *J)
{
- STACK[TOP].type = JS_TLITSTR;
+ STACK[TOP].t.type = JS_TLITSTR;
STACK[TOP].u.litstr = "stack overflow";
++TOP;
js_throw(J);
@@ -29,7 +29,7 @@
static void js_outofmemory(js_State *J)
{
- STACK[TOP].type = JS_TLITSTR;
+ STACK[TOP].t.type = JS_TLITSTR;
STACK[TOP].u.litstr = "out of memory";
++TOP;
js_throw(J);
@@ -88,7 +88,7 @@
void js_pushundefined(js_State *J)
{
CHECKSTACK(1);
- STACK[TOP].type = JS_TUNDEFINED;
+ STACK[TOP].t.type = JS_TUNDEFINED;
++TOP;
}
@@ -95,7 +95,7 @@
void js_pushnull(js_State *J)
{
CHECKSTACK(1);
- STACK[TOP].type = JS_TNULL;
+ STACK[TOP].t.type = JS_TNULL;
++TOP;
}
@@ -102,7 +102,7 @@
void js_pushboolean(js_State *J, int v)
{
CHECKSTACK(1);
- STACK[TOP].type = JS_TBOOLEAN;
+ STACK[TOP].t.type = JS_TBOOLEAN;
STACK[TOP].u.boolean = !!v;
++TOP;
}
@@ -110,7 +110,7 @@
void js_pushnumber(js_State *J, double v)
{
CHECKSTACK(1);
- STACK[TOP].type = JS_TNUMBER;
+ STACK[TOP].t.type = JS_TNUMBER;
STACK[TOP].u.number = v;
++TOP;
}
@@ -121,13 +121,13 @@
if (n > JS_STRLIMIT)
js_rangeerror(J, "invalid string length");
CHECKSTACK(1);
- if (n <= soffsetof(js_Value, type)) {
+ if (n <= soffsetof(js_Value, t.type)) {
char *s = STACK[TOP].u.shrstr;
while (n--) *s++ = *v++;
*s = 0;
- STACK[TOP].type = JS_TSHRSTR;
+ STACK[TOP].t.type = JS_TSHRSTR;
} else {
- STACK[TOP].type = JS_TMEMSTR;
+ STACK[TOP].t.type = JS_TMEMSTR;
STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
}
++TOP;
@@ -138,13 +138,13 @@
if (n > JS_STRLIMIT)
js_rangeerror(J, "invalid string length");
CHECKSTACK(1);
- if (n <= soffsetof(js_Value, type)) {
+ if (n <= soffsetof(js_Value, t.type)) {
char *s = STACK[TOP].u.shrstr;
while (n--) *s++ = *v++;
*s = 0;
- STACK[TOP].type = JS_TSHRSTR;
+ STACK[TOP].t.type = JS_TSHRSTR;
} else {
- STACK[TOP].type = JS_TMEMSTR;
+ STACK[TOP].t.type = JS_TMEMSTR;
STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
}
++TOP;
@@ -153,7 +153,7 @@
void js_pushliteral(js_State *J, const char *v)
{
CHECKSTACK(1);
- STACK[TOP].type = JS_TLITSTR;
+ STACK[TOP].t.type = JS_TLITSTR;
STACK[TOP].u.litstr = v;
++TOP;
}
@@ -161,7 +161,7 @@
void js_pushobject(js_State *J, js_Object *v)
{
CHECKSTACK(1);
- STACK[TOP].type = JS_TOBJECT;
+ STACK[TOP].t.type = JS_TOBJECT;
STACK[TOP].u.object = v;
++TOP;
}
@@ -177,7 +177,7 @@
if (BOT > 0)
STACK[TOP] = STACK[BOT-1];
else
- STACK[TOP].type = JS_TUNDEFINED;
+ STACK[TOP].t.type = JS_TUNDEFINED;
++TOP;
}
@@ -192,7 +192,7 @@
static js_Value *stackidx(js_State *J, int idx)
{
- static js_Value undefined = { {0}, {0}, JS_TUNDEFINED };
+ static js_Value undefined = { { {0}, JS_TUNDEFINED } };
idx = idx < 0 ? TOP + idx : BOT + idx;
if (idx < 0 || idx >= TOP)
return &undefined;
@@ -204,20 +204,20 @@
return stackidx(J, idx);
}
-int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TUNDEFINED; }
-int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TUNDEFINED; }
-int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNULL; }
-int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TBOOLEAN; }
-int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNUMBER; }
-int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; }
-int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; }
-int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; }
-int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type != JS_TUNDEFINED && v->type != JS_TNULL; }
+int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->t.type != JS_TUNDEFINED; }
+int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TUNDEFINED; }
+int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TNULL; }
+int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TBOOLEAN; }
+int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TNUMBER; }
+int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->t.type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; }
+int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->t.type != JS_TOBJECT; }
+int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TOBJECT; }
+int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->t.type != JS_TUNDEFINED && v->t.type != JS_TNULL; }
int js_iscallable(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- if (v->type == JS_TOBJECT)
+ if (v->t.type == JS_TOBJECT)
return v->u.object->type == JS_CFUNCTION ||
v->u.object->type == JS_CSCRIPT ||
v->u.object->type == JS_CCFUNCTION;
@@ -227,19 +227,19 @@
int js_isarray(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- return v->type == JS_TOBJECT && v->u.object->type == JS_CARRAY;
+ return v->t.type == JS_TOBJECT && v->u.object->type == JS_CARRAY;
}
int js_isregexp(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- return v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP;
+ return v->t.type == JS_TOBJECT && v->u.object->type == JS_CREGEXP;
}
int js_isuserdata(js_State *J, int idx, const char *tag)
{
js_Value *v = stackidx(J, idx);
- if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
+ if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
return !strcmp(tag, v->u.object->u.user.tag);
return 0;
}
@@ -247,13 +247,13 @@
int js_iserror(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- return v->type == JS_TOBJECT && v->u.object->type == JS_CERROR;
+ return v->t.type == JS_TOBJECT && v->u.object->type == JS_CERROR;
}
const char *js_typeof(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- switch (v->type) {
+ switch (v->t.type) {
default:
case JS_TSHRSTR: return "string";
case JS_TUNDEFINED: return "undefined";
@@ -272,7 +272,7 @@
int js_type(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- switch (v->type) {
+ switch (v->t.type) {
default:
case JS_TSHRSTR: return JS_ISSTRING;
case JS_TUNDEFINED: return JS_ISUNDEFINED;
@@ -341,7 +341,7 @@
js_Regexp *js_toregexp(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- if (v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP)
+ if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CREGEXP)
return &v->u.object->u.r;
js_typeerror(J, "not a regexp");
}
@@ -349,7 +349,7 @@
void *js_touserdata(js_State *J, int idx, const char *tag)
{
js_Value *v = stackidx(J, idx);
- if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
+ if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
if (!strcmp(tag, v->u.object->u.user.tag))
return v->u.object->u.user.data;
js_typeerror(J, "not a %s", tag);
@@ -358,9 +358,9 @@
static js_Object *jsR_tofunction(js_State *J, int idx)
{
js_Value *v = stackidx(J, idx);
- if (v->type == JS_TUNDEFINED || v->type == JS_TNULL)
+ if (v->t.type == JS_TUNDEFINED || v->t.type == JS_TNULL)
return NULL;
- if (v->type == JS_TOBJECT)
+ if (v->t.type == JS_TOBJECT)
if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
return v->u.object;
js_typeerror(J, "not a function");
@@ -912,7 +912,7 @@
js_Value *v = stackidx(J, -1);
const char *s;
char buf[32];
- switch (v->type) {
+ switch (v->t.type) {
case JS_TUNDEFINED: s = "_Undefined"; break;
case JS_TNULL: s = "_Null"; break;
case JS_TBOOLEAN:
@@ -1457,7 +1457,7 @@
static void js_dumpvalue(js_State *J, js_Value v)
{
- switch (v.type) {
+ switch (v.t.type) {
case JS_TUNDEFINED: printf("undefined"); break;
case JS_TNULL: printf("null"); break;
case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break;
@@ -1537,7 +1537,7 @@
static int jsR_isindex(js_State *J, int idx, int *k)
{
js_Value *v = stackidx(J, idx);
- if (v->type == JS_TNUMBER) {
+ if (v->t.type == JS_TNUMBER) {
*k = v->u.number;
return *k == v->u.number && *k >= 0;
}
--- a/jsstate.c
+++ b/jsstate.c
@@ -5,7 +5,7 @@
static int js_ptry(js_State *J) {
if (J->trytop == JS_TRYLIMIT) {
- J->stack[J->top].type = JS_TLITSTR;
+ J->stack[J->top].t.type = JS_TLITSTR;
J->stack[J->top].u.litstr = "exception stack overflow";
++J->top;
return 1;
@@ -285,7 +285,7 @@
js_State *J;
assert(sizeof(js_Value) == 16);
- assert(soffsetof(js_Value, type) == 15);
+ assert(soffsetof(js_Value, t.type) == 15);
if (!alloc)
alloc = js_defaultalloc;
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -1,8 +1,8 @@
#include "jsi.h"
#include "utf.h"
-#define JSV_ISSTRING(v) (v->type==JS_TSHRSTR || v->type==JS_TMEMSTR || v->type==JS_TLITSTR)
-#define JSV_TOSTRING(v) (v->type==JS_TSHRSTR ? v->u.shrstr : v->type==JS_TLITSTR ? v->u.litstr : v->type==JS_TMEMSTR ? v->u.memstr->p : "")
+#define JSV_ISSTRING(v) (v->t.type==JS_TSHRSTR || v->t.type==JS_TMEMSTR || v->t.type==JS_TLITSTR)
+#define JSV_TOSTRING(v) (v->t.type==JS_TSHRSTR ? v->u.shrstr : v->t.type==JS_TLITSTR ? v->u.litstr : v->t.type==JS_TMEMSTR ? v->u.memstr->p : "")
double js_strtol(const char *s, char **p, int base)
{
@@ -118,7 +118,7 @@
{
js_Object *obj;
- if (v->type != JS_TOBJECT)
+ if (v->t.type != JS_TOBJECT)
return;
obj = v->u.object;
@@ -143,7 +143,7 @@
if (J->strict)
js_typeerror(J, "cannot convert object to primitive");
- v->type = JS_TLITSTR;
+ v->t.type = JS_TLITSTR;
v->u.litstr = "[object]";
return;
}
@@ -151,7 +151,7 @@
/* ToBoolean() on a value */
int jsV_toboolean(js_State *J, js_Value *v)
{
- switch (v->type) {
+ switch (v->t.type) {
default:
case JS_TSHRSTR: return v->u.shrstr[0] != 0;
case JS_TUNDEFINED: return 0;
@@ -239,7 +239,7 @@
/* ToNumber() on a value */
double jsV_tonumber(js_State *J, js_Value *v)
{
- switch (v->type) {
+ switch (v->t.type) {
default:
case JS_TSHRSTR: return jsV_stringtonumber(J, v->u.shrstr);
case JS_TUNDEFINED: return NAN;
@@ -324,7 +324,7 @@
{
char buf[32];
const char *p;
- switch (v->type) {
+ switch (v->t.type) {
default:
case JS_TSHRSTR: return v->u.shrstr;
case JS_TUNDEFINED: return "undefined";
@@ -336,15 +336,15 @@
p = jsV_numbertostring(J, buf, v->u.number);
if (p == buf) {
int n = strlen(p);
- if (n <= soffsetof(js_Value, type)) {
+ if (n <= soffsetof(js_Value, t.type)) {
char *s = v->u.shrstr;
while (n--) *s++ = *p++;
*s = 0;
- v->type = JS_TSHRSTR;
+ v->t.type = JS_TSHRSTR;
return v->u.shrstr;
} else {
v->u.memstr = jsV_newmemstring(J, p, n);
- v->type = JS_TMEMSTR;
+ v->t.type = JS_TMEMSTR;
return v->u.memstr->p;
}
}
@@ -389,7 +389,7 @@
js_Object *jsV_toobject(js_State *J, js_Value *v)
{
js_Object *o;
- switch (v->type) {
+ switch (v->t.type) {
default:
case JS_TUNDEFINED: js_typeerror(J, "cannot convert undefined to object");
case JS_TNULL: js_typeerror(J, "cannot convert null to object");
@@ -400,7 +400,7 @@
case JS_TBOOLEAN: o = jsV_newboolean(J, v->u.boolean); break;
case JS_TNUMBER: o = jsV_newnumber(J, v->u.number); break;
}
- v->type = JS_TOBJECT;
+ v->t.type = JS_TOBJECT;
v->u.object = o;
return o;
}
@@ -624,38 +624,38 @@
retry:
if (JSV_ISSTRING(x) && JSV_ISSTRING(y))
return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y));
- if (x->type == y->type) {
- if (x->type == JS_TUNDEFINED) return 1;
- if (x->type == JS_TNULL) return 1;
- if (x->type == JS_TNUMBER) return x->u.number == y->u.number;
- if (x->type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean;
- if (x->type == JS_TOBJECT) return x->u.object == y->u.object;
+ if (x->t.type == y->t.type) {
+ if (x->t.type == JS_TUNDEFINED) return 1;
+ if (x->t.type == JS_TNULL) return 1;
+ if (x->t.type == JS_TNUMBER) return x->u.number == y->u.number;
+ if (x->t.type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean;
+ if (x->t.type == JS_TOBJECT) return x->u.object == y->u.object;
return 0;
}
- if (x->type == JS_TNULL && y->type == JS_TUNDEFINED) return 1;
- if (x->type == JS_TUNDEFINED && y->type == JS_TNULL) return 1;
+ if (x->t.type == JS_TNULL && y->t.type == JS_TUNDEFINED) return 1;
+ if (x->t.type == JS_TUNDEFINED && y->t.type == JS_TNULL) return 1;
- if (x->type == JS_TNUMBER && JSV_ISSTRING(y))
+ if (x->t.type == JS_TNUMBER && JSV_ISSTRING(y))
return x->u.number == jsV_tonumber(J, y);
- if (JSV_ISSTRING(x) && y->type == JS_TNUMBER)
+ if (JSV_ISSTRING(x) && y->t.type == JS_TNUMBER)
return jsV_tonumber(J, x) == y->u.number;
- if (x->type == JS_TBOOLEAN) {
- x->type = JS_TNUMBER;
+ if (x->t.type == JS_TBOOLEAN) {
+ x->t.type = JS_TNUMBER;
x->u.number = x->u.boolean ? 1 : 0;
goto retry;
}
- if (y->type == JS_TBOOLEAN) {
- y->type = JS_TNUMBER;
+ if (y->t.type == JS_TBOOLEAN) {
+ y->t.type = JS_TNUMBER;
y->u.number = y->u.boolean ? 1 : 0;
goto retry;
}
- if ((JSV_ISSTRING(x) || x->type == JS_TNUMBER) && y->type == JS_TOBJECT) {
+ if ((JSV_ISSTRING(x) || x->t.type == JS_TNUMBER) && y->t.type == JS_TOBJECT) {
jsV_toprimitive(J, y, JS_HNONE);
goto retry;
}
- if (x->type == JS_TOBJECT && (JSV_ISSTRING(y) || y->type == JS_TNUMBER)) {
+ if (x->t.type == JS_TOBJECT && (JSV_ISSTRING(y) || y->t.type == JS_TNUMBER)) {
jsV_toprimitive(J, x, JS_HNONE);
goto retry;
}
@@ -671,11 +671,11 @@
if (JSV_ISSTRING(x) && JSV_ISSTRING(y))
return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y));
- if (x->type != y->type) return 0;
- if (x->type == JS_TUNDEFINED) return 1;
- if (x->type == JS_TNULL) return 1;
- if (x->type == JS_TNUMBER) return x->u.number == y->u.number;
- if (x->type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean;
- if (x->type == JS_TOBJECT) return x->u.object == y->u.object;
+ if (x->t.type != y->t.type) return 0;
+ if (x->t.type == JS_TUNDEFINED) return 1;
+ if (x->t.type == JS_TNULL) return 1;
+ if (x->t.type == JS_TNUMBER) return x->u.number == y->u.number;
+ if (x->t.type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean;
+ if (x->t.type == JS_TOBJECT) return x->u.object == y->u.object;
return 0;
}