2 * User object handling.
3 * Copyright (c) 1998 New Generation Software (NGS) Oy
5 * Author: Markku Rossi <mtr@ngs.fi>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/ksrc/object.c,v $
30 #include "ddk/ntddk.h"
35 * Types and definitions.
41 * Prototypes for static functions.
44 static void hash_create (JSVirtualMachine
*vm
, JSObject
*obj
);
46 static void hash_insert (JSVirtualMachine
*vm
, JSObject
*obj
, const char *name
,
47 unsigned int name_len
, int pos
);
49 static void hash_delete (JSVirtualMachine
*vm
, JSObject
*obj
, const char *name
,
50 unsigned int name_len
);
52 static int hash_lookup (JSObject
*obj
, char *name
, unsigned int name_len
);
60 js_vm_object_new (JSVirtualMachine
*vm
)
64 obj
= js_vm_alloc (vm
, sizeof (*obj
));
74 js_vm_object_mark (JSObject
*obj
)
77 unsigned int num_objects
;
84 if (!js_vm_mark_ptr (obj
))
85 /* This object has already been marked. Nothing to do here. */
88 js_vm_mark_ptr (obj
->props
);
90 /* Mark property hash. */
93 JSObjectPropHashBucket
*b
;
96 js_vm_mark_ptr (obj
->hash
);
97 js_vm_mark_ptr (obj
->hash_lengths
);
99 for (i
= 0; i
< HASH_SIZE
; i
++)
100 for (b
= obj
->hash
[i
]; b
; b
= b
->next
)
103 js_vm_mark_ptr (b
->data
);
107 /* Mark all non-object properties. */
109 for (i
= 0; i
< obj
->num_props
; i
++)
111 if (obj
->props
[i
].value
.type
== JS_OBJECT
)
113 if (!js_vm_is_marked_ptr (obj
->props
[i
].value
.u
.vobject
))
117 js_vm_mark (&obj
->props
[i
].value
);
120 /* And finally, mark all objects we have left. */
123 /* Find the objects. */
124 for (i
= 0; i
< obj
->num_props
; i
++)
125 if (obj
->props
[i
].value
.type
== JS_OBJECT
126 && !js_vm_is_marked_ptr (obj
->props
[i
].value
.u
.vobject
))
128 if (num_objects
== 1)
131 * Hahaa, this is the only non-marked object. We can
132 * do a tail-recursion optimization.
134 obj
= obj
->props
[i
].value
.u
.vobject
;
139 js_vm_mark (&obj
->props
[i
].value
);
146 js_vm_object_load_property (JSVirtualMachine
*vm
, JSObject
*obj
,
147 JSSymbol prop
, JSNode
*value_return
)
150 JSSymbol link_sym
= vm
->syms
.s___proto__
;
151 JSObject
*link_obj
= NULL
;
155 /* Check if we know this property. */
156 for (ui
= 0; ui
< obj
->num_props
; ui
++)
157 if (obj
->props
[ui
].name
== prop
)
159 JS_COPY (value_return
, &obj
->props
[ui
].value
);
160 return JS_PROPERTY_FOUND
;
162 else if (obj
->props
[ui
].name
== link_sym
163 && obj
->props
[ui
].value
.type
== JS_OBJECT
)
164 link_obj
= obj
->props
[ui
].value
.u
.vobject
;
166 /* Undefined so far. */
169 /* Follow the link. */
176 /* Undefined. Make it undef. */
177 value_return
->type
= JS_UNDEFINED
;
178 return JS_PROPERTY_UNKNOWN
;
183 js_vm_object_store_property (JSVirtualMachine
*vm
, JSObject
*obj
,
184 JSSymbol prop
, JSNode
*val
)
187 JSSymbol free_slot
= JS_SYMBOL_NULL
;
189 /* Check if we already know this property. */
190 for (ui
= 0; ui
< obj
->num_props
; ui
++)
191 if (obj
->props
[ui
].name
== prop
)
193 JS_COPY (&obj
->props
[ui
].value
, val
);
196 else if (obj
->props
[ui
].name
== JS_SYMBOL_NULL
)
199 /* Must create a new property. */
201 if (free_slot
== JS_SYMBOL_NULL
)
203 /* Expand our array of properties. */
204 obj
->props
= js_vm_realloc (vm
, obj
->props
,
205 (obj
->num_props
+ 1) * sizeof (JSProperty
));
206 free_slot
= obj
->num_props
++;
209 obj
->props
[free_slot
].name
= prop
;
210 obj
->props
[free_slot
].attributes
= 0;
211 JS_COPY (&obj
->props
[free_slot
].value
, val
);
213 /* Insert it to the hash (if the hash has been created). */
218 name
= js_vm_symname (vm
, prop
);
219 hash_insert (vm
, obj
, name
, strlen (name
), free_slot
);
225 js_vm_object_delete_property (JSVirtualMachine
*vm
, JSObject
*obj
,
230 /* Check if we already know this property. */
231 for (ui
= 0; ui
< obj
->num_props
; ui
++)
232 if (obj
->props
[ui
].name
== prop
)
234 /* Found, remove it from our list of properties. */
235 obj
->props
[ui
].name
= JS_SYMBOL_NULL
;
236 obj
->props
[ui
].value
.type
= JS_UNDEFINED
;
238 /* Remove its name from the hash (if present). */
241 const char *name
= js_vm_symname (vm
, prop
);
242 hash_delete (vm
, obj
, name
, strlen (name
));
252 js_vm_object_load_array (JSVirtualMachine
*vm
, JSObject
*obj
, JSNode
*sel
,
253 JSNode
*value_return
)
255 if (sel
->type
== JS_INTEGER
)
257 if (sel
->u
.vinteger
< 0 || sel
->u
.vinteger
>= obj
->num_props
)
258 value_return
->type
= JS_UNDEFINED
;
260 JS_COPY (value_return
, &obj
->props
[sel
->u
.vinteger
].value
);
262 else if (sel
->type
== JS_STRING
)
266 if (obj
->hash
== NULL
)
267 hash_create (vm
, obj
);
269 pos
= hash_lookup (obj
, (char *) sel
->u
.vstring
->data
,
270 sel
->u
.vstring
->len
);
272 value_return
->type
= JS_UNDEFINED
;
274 JS_COPY (value_return
, &obj
->props
[pos
].value
);
278 sprintf (vm
->error
, "load_property: illegal array index");
285 js_vm_object_store_array (JSVirtualMachine
*vm
, JSObject
*obj
, JSNode
*sel
,
288 if (sel
->type
== JS_INTEGER
)
290 if (sel
->u
.vinteger
< 0)
292 sprintf (vm
->error
, "store_array: array index can't be nagative");
295 if (sel
->u
.vinteger
>= obj
->num_props
)
297 /* Expand properties. */
298 obj
->props
= js_vm_realloc (vm
, obj
->props
,
299 (sel
->u
.vinteger
+ 1)
300 * sizeof (JSProperty
));
302 /* Init the possible gap. */
303 for (; obj
->num_props
<= sel
->u
.vinteger
; obj
->num_props
++)
305 obj
->props
[obj
->num_props
].name
= 0;
306 obj
->props
[obj
->num_props
].attributes
= 0;
307 obj
->props
[obj
->num_props
].value
.type
= JS_UNDEFINED
;
311 JS_COPY (&obj
->props
[sel
->u
.vinteger
].value
, value
);
313 else if (sel
->type
== JS_STRING
)
317 if (obj
->hash
== NULL
)
318 hash_create (vm
, obj
);
320 pos
= hash_lookup (obj
, (char *) sel
->u
.vstring
->data
,
321 sel
->u
.vstring
->len
);
324 /* It is undefined, define it. */
325 obj
->props
= js_vm_realloc (vm
, obj
->props
,
327 * sizeof (JSProperty
));
330 * XXX if <sel> is a valid symbol, intern it and set symbol's
333 obj
->props
[obj
->num_props
].name
= JS_SYMBOL_NULL
;
334 obj
->props
[obj
->num_props
].attributes
= 0;
335 JS_COPY (&obj
->props
[obj
->num_props
].value
, value
);
337 hash_insert (vm
, obj
, (char *) sel
->u
.vstring
->data
,
338 sel
->u
.vstring
->len
, obj
->num_props
);
343 JS_COPY (&obj
->props
[pos
].value
, value
);
349 js_vm_object_delete_array (JSVirtualMachine
*vm
, JSObject
*obj
, JSNode
*sel
)
351 if (sel
->type
== JS_INTEGER
)
353 if (0 <= sel
->u
.vinteger
&& sel
->u
.vinteger
< obj
->num_props
)
357 sym
= obj
->props
[sel
->u
.vinteger
].name
;
358 obj
->props
[sel
->u
.vinteger
].name
= JS_SYMBOL_NULL
;
359 obj
->props
[sel
->u
.vinteger
].value
.type
= JS_UNDEFINED
;
361 /* Remove its name from the hash (if present and it is not NULL). */
362 if (sym
!= JS_SYMBOL_NULL
&& obj
->hash
)
364 const char *name
= js_vm_symname (vm
, sym
);
365 hash_delete (vm
, obj
, name
, strlen (name
));
369 else if (sel
->type
== JS_STRING
)
373 if (obj
->hash
== NULL
)
374 hash_create (vm
, obj
);
376 pos
= hash_lookup (obj
, (char *) sel
->u
.vstring
->data
,
377 sel
->u
.vstring
->len
);
381 obj
->props
[pos
].name
= JS_SYMBOL_NULL
;
382 obj
->props
[pos
].value
.type
= JS_UNDEFINED
;
384 /* And, delete its name from the hash. */
385 hash_delete (vm
, obj
, (char *) sel
->u
.vstring
->data
,
386 sel
->u
.vstring
->len
);
391 sprintf (vm
->error
, "delete_array: illegal array index");
398 js_vm_object_nth (JSVirtualMachine
*vm
, JSObject
*obj
, int nth
,
399 JSNode
*value_return
)
402 JSObjectPropHashBucket
*b
;
404 value_return
->type
= JS_UNDEFINED
;
409 if (obj
->hash
== NULL
)
410 hash_create (vm
, obj
);
412 for (i
= 0; i
< HASH_SIZE
&& nth
>= obj
->hash_lengths
[i
]; i
++)
413 nth
-= obj
->hash_lengths
[i
];
418 /* The chain <i> is the correct one. */
419 for (b
= obj
->hash
[i
]; b
&& nth
> 0; b
= b
->next
, nth
--)
426 "js_vm_object_nth(): chain didn't contain that many items%s",
428 js_iostream_write (vm
->s_stderr
, buf
, strlen (buf
));
429 js_iostream_flush (vm
->s_stderr
);
434 js_vm_make_string (vm
, value_return
, (char*)b
->data
, b
->len
);
445 hash_create (JSVirtualMachine
*vm
, JSObject
*obj
)
449 obj
->hash
= js_vm_alloc (vm
, HASH_SIZE
* sizeof (JSObjectPropHashBucket
*));
450 memset (obj
->hash
, 0, HASH_SIZE
* sizeof (JSObjectPropHashBucket
*));
452 obj
->hash_lengths
= js_vm_alloc (vm
, HASH_SIZE
* sizeof (unsigned int));
453 memset (obj
->hash_lengths
, 0, HASH_SIZE
* sizeof (unsigned int));
455 /* Insert all known properties to the hash. */
456 for (i
= 0; i
< obj
->num_props
; i
++)
457 if (obj
->props
[i
].name
!= JS_SYMBOL_NULL
)
461 name
= js_vm_symname (vm
, obj
->props
[i
].name
);
462 hash_insert (vm
, obj
, name
, strlen (name
), i
);
468 hash_insert (JSVirtualMachine
*vm
, JSObject
*obj
, const char *name
,
469 unsigned int name_len
, int pos
)
472 JSObjectPropHashBucket
*b
;
474 hash
= js_count_hash (name
, name_len
) % HASH_SIZE
;
475 for (b
= obj
->hash
[hash
]; b
; b
= b
->next
)
476 if (b
->len
== name_len
477 && memcmp (b
->data
, name
, name_len
) == 0)
479 /* Ok, we already have a bucket */
484 /* Create a new bucket. */
485 b
= js_vm_alloc (vm
, sizeof (*b
));
487 b
->data
= js_vm_alloc (vm
, b
->len
);
488 memcpy (b
->data
, name
, b
->len
);
492 b
->next
= obj
->hash
[hash
];
495 obj
->hash_lengths
[hash
]++;
500 hash_delete (JSVirtualMachine
*vm
, JSObject
*obj
, const char *name
,
501 unsigned int name_len
)
504 JSObjectPropHashBucket
*b
, *prev
;
506 hash
= js_count_hash (name
, name_len
) % HASH_SIZE
;
507 for (prev
= NULL
, b
= obj
->hash
[hash
]; b
; prev
= b
, b
= b
->next
)
508 if (b
->len
== name_len
509 && memcmp (b
->data
, name
, name_len
) == 0)
513 prev
->next
= b
->next
;
515 obj
->hash
[hash
] = b
->next
;
517 obj
->hash_lengths
[hash
]--;
525 hash_lookup (JSObject
*obj
, char *name
, unsigned int name_len
)
528 JSObjectPropHashBucket
*b
;
530 hash
= js_count_hash (name
, name_len
) % HASH_SIZE
;
531 for (b
= obj
->hash
[hash
]; b
; b
= b
->next
)
532 if (b
->len
== name_len
533 && memcmp (b
->data
, name
, name_len
) == 0)