1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * JavaScript Debugging support - Value and Property support
40 : */
41 :
42 : #include "jsd.h"
43 : #include "jsapi.h"
44 : #include "jsfriendapi.h"
45 :
46 : #ifdef DEBUG
47 4 : void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
48 : {
49 4 : JS_ASSERT(jsdval);
50 4 : JS_ASSERT(jsdval->nref > 0);
51 4 : if(!JS_CLIST_IS_EMPTY(&jsdval->props))
52 : {
53 0 : JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS));
54 0 : JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val));
55 : }
56 :
57 4 : if(jsdval->proto)
58 : {
59 0 : JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO));
60 0 : JS_ASSERT(jsdval->proto->nref > 0);
61 : }
62 4 : if(jsdval->parent)
63 : {
64 2 : JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT));
65 2 : JS_ASSERT(jsdval->parent->nref > 0);
66 : }
67 4 : if(jsdval->ctor)
68 : {
69 0 : JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR));
70 0 : JS_ASSERT(jsdval->ctor->nref > 0);
71 : }
72 4 : }
73 :
74 0 : void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop)
75 : {
76 0 : JS_ASSERT(jsdprop);
77 0 : JS_ASSERT(jsdprop->name);
78 0 : JS_ASSERT(jsdprop->name->nref > 0);
79 0 : JS_ASSERT(jsdprop->val);
80 0 : JS_ASSERT(jsdprop->val->nref > 0);
81 0 : if(jsdprop->alias)
82 0 : JS_ASSERT(jsdprop->alias->nref > 0);
83 0 : }
84 : #endif
85 :
86 :
87 : JSBool
88 0 : jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
89 : {
90 0 : return JSVAL_IS_OBJECT(jsdval->val);
91 : }
92 :
93 : JSBool
94 0 : jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
95 : {
96 0 : return JSVAL_IS_NUMBER(jsdval->val);
97 : }
98 :
99 : JSBool
100 0 : jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
101 : {
102 0 : return JSVAL_IS_INT(jsdval->val);
103 : }
104 :
105 : JSBool
106 0 : jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
107 : {
108 0 : return JSVAL_IS_DOUBLE(jsdval->val);
109 : }
110 :
111 : JSBool
112 0 : jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
113 : {
114 0 : return JSVAL_IS_STRING(jsdval->val);
115 : }
116 :
117 : JSBool
118 0 : jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
119 : {
120 0 : return JSVAL_IS_BOOLEAN(jsdval->val);
121 : }
122 :
123 : JSBool
124 0 : jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
125 : {
126 0 : return JSVAL_IS_NULL(jsdval->val);
127 : }
128 :
129 : JSBool
130 0 : jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
131 : {
132 0 : return JSVAL_IS_VOID(jsdval->val);
133 : }
134 :
135 : JSBool
136 0 : jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
137 : {
138 0 : return JSVAL_IS_PRIMITIVE(jsdval->val);
139 : }
140 :
141 : JSBool
142 0 : jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
143 : {
144 0 : return !JSVAL_IS_PRIMITIVE(jsdval->val) &&
145 0 : JS_ObjectIsCallable(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
146 : }
147 :
148 : JSBool
149 0 : jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
150 : {
151 0 : JSContext* cx = jsdc->dumbContext;
152 : JSFunction* fun;
153 : JSExceptionState* exceptionState;
154 0 : JSCrossCompartmentCall *call = NULL;
155 :
156 0 : if(jsd_IsValueFunction(jsdc, jsdval))
157 : {
158 0 : JSBool ok = JS_FALSE;
159 0 : JS_BeginRequest(cx);
160 0 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
161 0 : if(!call) {
162 0 : JS_EndRequest(cx);
163 :
164 0 : return JS_FALSE;
165 : }
166 :
167 0 : exceptionState = JS_SaveExceptionState(cx);
168 0 : fun = JSD_GetValueFunction(jsdc, jsdval);
169 0 : JS_RestoreExceptionState(cx, exceptionState);
170 0 : if(fun)
171 0 : ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
172 0 : JS_LeaveCrossCompartmentCall(call);
173 0 : JS_EndRequest(cx);
174 0 : JS_ASSERT(fun);
175 0 : return ok;
176 : }
177 0 : return !JSVAL_IS_PRIMITIVE(jsdval->val);
178 : }
179 :
180 : /***************************************************************************/
181 :
182 : JSBool
183 0 : jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
184 : {
185 0 : jsval val = jsdval->val;
186 0 : if(!JSVAL_IS_BOOLEAN(val))
187 0 : return JS_FALSE;
188 0 : return JSVAL_TO_BOOLEAN(val);
189 : }
190 :
191 : int32_t
192 0 : jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
193 : {
194 0 : jsval val = jsdval->val;
195 0 : if(!JSVAL_IS_INT(val))
196 0 : return 0;
197 0 : return JSVAL_TO_INT(val);
198 : }
199 :
200 : double
201 0 : jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
202 : {
203 0 : if(!JSVAL_IS_DOUBLE(jsdval->val))
204 0 : return 0;
205 0 : return JSVAL_TO_DOUBLE(jsdval->val);
206 : }
207 :
208 : JSString*
209 0 : jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
210 : {
211 0 : JSContext* cx = jsdc->dumbContext;
212 : JSExceptionState* exceptionState;
213 0 : JSCrossCompartmentCall *call = NULL;
214 : jsval stringval;
215 : JSString *string;
216 : JSBool needWrap;
217 : JSObject *scopeObj;
218 :
219 0 : if(jsdval->string)
220 0 : return jsdval->string;
221 :
222 : /* Reuse the string without copying or re-rooting it */
223 0 : if(JSVAL_IS_STRING(jsdval->val)) {
224 0 : jsdval->string = JSVAL_TO_STRING(jsdval->val);
225 0 : return jsdval->string;
226 : }
227 :
228 0 : JS_BeginRequest(cx);
229 :
230 : /* Objects call JS_ValueToString in their own compartment. */
231 0 : scopeObj = !JSVAL_IS_PRIMITIVE(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob;
232 0 : call = JS_EnterCrossCompartmentCall(cx, scopeObj);
233 0 : if(!call) {
234 0 : JS_EndRequest(cx);
235 0 : return NULL;
236 : }
237 0 : exceptionState = JS_SaveExceptionState(cx);
238 :
239 0 : string = JS_ValueToString(cx, jsdval->val);
240 :
241 0 : JS_RestoreExceptionState(cx, exceptionState);
242 0 : JS_LeaveCrossCompartmentCall(call);
243 0 : call = NULL;
244 :
245 0 : if(string) {
246 0 : stringval = STRING_TO_JSVAL(string);
247 0 : call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
248 : }
249 0 : if(!string || !call || !JS_WrapValue(cx, &stringval)) {
250 0 : if(call)
251 0 : JS_LeaveCrossCompartmentCall(call);
252 0 : JS_EndRequest(cx);
253 0 : return NULL;
254 : }
255 :
256 0 : jsdval->string = JSVAL_TO_STRING(stringval);
257 0 : if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
258 0 : jsdval->string = NULL;
259 :
260 0 : JS_LeaveCrossCompartmentCall(call);
261 0 : JS_EndRequest(cx);
262 :
263 0 : return jsdval->string;
264 : }
265 :
266 : JSString*
267 0 : jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
268 : {
269 0 : JSContext* cx = jsdc->dumbContext;
270 : JSFunction* fun;
271 : JSExceptionState* exceptionState;
272 0 : JSCrossCompartmentCall *call = NULL;
273 :
274 0 : if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
275 : {
276 0 : JS_BeginRequest(cx);
277 :
278 0 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
279 0 : if(!call) {
280 0 : JS_EndRequest(cx);
281 :
282 0 : return NULL;
283 : }
284 :
285 0 : exceptionState = JS_SaveExceptionState(cx);
286 0 : fun = JSD_GetValueFunction(jsdc, jsdval);
287 0 : JS_RestoreExceptionState(cx, exceptionState);
288 0 : JS_LeaveCrossCompartmentCall(call);
289 0 : JS_EndRequest(cx);
290 0 : if(!fun)
291 0 : return NULL;
292 0 : jsdval->funName = JS_GetFunctionId(fun);
293 :
294 : /* For compatibility we return "anonymous", not an empty string here. */
295 0 : if (!jsdval->funName)
296 0 : jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
297 : }
298 0 : return jsdval->funName;
299 : }
300 :
301 : /***************************************************************************/
302 :
303 : /*
304 : * Create a new JSD value referring to a jsval. Copy string values into the
305 : * JSD compartment. Leave all other GCTHINGs in their native compartments
306 : * and access them through cross-compartment calls.
307 : */
308 : JSDValue*
309 2 : jsd_NewValue(JSDContext* jsdc, jsval val)
310 : {
311 : JSDValue* jsdval;
312 2 : JSCrossCompartmentCall *call = NULL;
313 :
314 2 : if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
315 0 : return NULL;
316 :
317 2 : if(JSVAL_IS_GCTHING(val))
318 : {
319 : JSBool ok;
320 2 : JS_BeginRequest(jsdc->dumbContext);
321 :
322 2 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
323 2 : if(!call) {
324 0 : JS_EndRequest(jsdc->dumbContext);
325 0 : free(jsdval);
326 0 : return NULL;
327 : }
328 :
329 2 : ok = JS_AddNamedValueRoot(jsdc->dumbContext, &jsdval->val, "JSDValue");
330 2 : if(ok && JSVAL_IS_STRING(val)) {
331 0 : if(!JS_WrapValue(jsdc->dumbContext, &val)) {
332 0 : ok = JS_FALSE;
333 : }
334 : }
335 :
336 2 : JS_LeaveCrossCompartmentCall(call);
337 2 : JS_EndRequest(jsdc->dumbContext);
338 2 : if(!ok)
339 : {
340 0 : free(jsdval);
341 0 : return NULL;
342 : }
343 : }
344 2 : jsdval->val = val;
345 2 : jsdval->nref = 1;
346 2 : JS_INIT_CLIST(&jsdval->props);
347 :
348 2 : return jsdval;
349 : }
350 :
351 : void
352 3 : jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
353 : {
354 3 : JSCrossCompartmentCall *call = NULL;
355 :
356 3 : JS_ASSERT(jsdval->nref > 0);
357 3 : if(0 == --jsdval->nref)
358 : {
359 2 : jsd_RefreshValue(jsdc, jsdval);
360 2 : if(JSVAL_IS_GCTHING(jsdval->val))
361 : {
362 2 : JS_BeginRequest(jsdc->dumbContext);
363 2 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
364 2 : if(!call) {
365 0 : JS_EndRequest(jsdc->dumbContext);
366 :
367 0 : return;
368 : }
369 :
370 2 : JS_RemoveValueRoot(jsdc->dumbContext, &jsdval->val);
371 2 : JS_LeaveCrossCompartmentCall(call);
372 2 : JS_EndRequest(jsdc->dumbContext);
373 : }
374 2 : free(jsdval);
375 : }
376 : }
377 :
378 : jsval
379 1 : jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
380 : {
381 : JSObject* obj;
382 : JSContext* cx;
383 1 : jsval val = jsdval->val;
384 1 : if (!JSVAL_IS_PRIMITIVE(val)) {
385 1 : cx = JSD_GetDefaultJSContext(jsdc);
386 1 : obj = JS_ObjectToOuterObject(cx, JSVAL_TO_OBJECT(val));
387 1 : if (!obj)
388 : {
389 0 : JS_ClearPendingException(cx);
390 0 : val = JSVAL_NULL;
391 : }
392 : else
393 1 : val = OBJECT_TO_JSVAL(obj);
394 : }
395 :
396 1 : return val;
397 : }
398 :
399 0 : static JSDProperty* _newProperty(JSDContext* jsdc, JSPropertyDesc* pd,
400 : unsigned additionalFlags)
401 : {
402 : JSDProperty* jsdprop;
403 :
404 0 : if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
405 0 : return NULL;
406 :
407 0 : JS_INIT_CLIST(&jsdprop->links);
408 0 : jsdprop->nref = 1;
409 0 : jsdprop->flags = pd->flags | additionalFlags;
410 0 : jsdprop->slot = pd->slot;
411 :
412 0 : if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
413 0 : goto new_prop_fail;
414 :
415 0 : if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
416 0 : goto new_prop_fail;
417 :
418 0 : if((jsdprop->flags & JSDPD_ALIAS) &&
419 0 : !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
420 0 : goto new_prop_fail;
421 :
422 0 : return jsdprop;
423 : new_prop_fail:
424 0 : jsd_DropProperty(jsdc, jsdprop);
425 0 : return NULL;
426 : }
427 :
428 2 : static void _freeProps(JSDContext* jsdc, JSDValue* jsdval)
429 : {
430 : JSDProperty* jsdprop;
431 :
432 6 : while(jsdprop = (JSDProperty*)jsdval->props.next,
433 2 : jsdprop != (JSDProperty*)&jsdval->props)
434 : {
435 0 : JS_REMOVE_AND_INIT_LINK(&jsdprop->links);
436 0 : jsd_DropProperty(jsdc, jsdprop);
437 : }
438 2 : JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
439 2 : CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS);
440 2 : }
441 :
442 0 : static JSBool _buildProps(JSDContext* jsdc, JSDValue* jsdval)
443 : {
444 0 : JSContext* cx = jsdc->dumbContext;
445 : JSObject *obj;
446 : JSPropertyDescArray pda;
447 : unsigned i;
448 0 : JSCrossCompartmentCall *call = NULL;
449 :
450 0 : JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
451 0 : JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
452 0 : JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val));
453 :
454 0 : if(JSVAL_IS_PRIMITIVE(jsdval->val))
455 0 : return JS_FALSE;
456 :
457 0 : obj = JSVAL_TO_OBJECT(jsdval->val);
458 :
459 0 : JS_BeginRequest(cx);
460 0 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
461 0 : if(!call)
462 : {
463 0 : JS_EndRequest(jsdc->dumbContext);
464 0 : return JS_FALSE;
465 : }
466 :
467 0 : if(!JS_GetPropertyDescArray(cx, obj, &pda))
468 : {
469 0 : JS_EndRequest(cx);
470 0 : JS_LeaveCrossCompartmentCall(call);
471 0 : return JS_FALSE;
472 : }
473 :
474 0 : for(i = 0; i < pda.length; i++)
475 : {
476 0 : JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
477 0 : if(!prop)
478 : {
479 0 : _freeProps(jsdc, jsdval);
480 0 : break;
481 : }
482 0 : JS_APPEND_LINK(&prop->links, &jsdval->props);
483 : }
484 0 : JS_PutPropertyDescArray(cx, &pda);
485 0 : JS_LeaveCrossCompartmentCall(call);
486 0 : JS_EndRequest(cx);
487 0 : SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
488 0 : return !JS_CLIST_IS_EMPTY(&jsdval->props);
489 : }
490 :
491 : #undef DROP_CLEAR_VALUE
492 : #define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = NULL;}
493 :
494 : void
495 2 : jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
496 : {
497 2 : JSContext* cx = jsdc->dumbContext;
498 2 : JSCrossCompartmentCall *call = NULL;
499 :
500 2 : if(jsdval->string)
501 : {
502 : /* if the jsval is a string, then we didn't need to root the string */
503 0 : if(!JSVAL_IS_STRING(jsdval->val))
504 : {
505 0 : JS_BeginRequest(cx);
506 0 : call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
507 0 : if(!call) {
508 0 : JS_EndRequest(cx);
509 :
510 0 : return;
511 : }
512 :
513 0 : JS_RemoveStringRoot(cx, &jsdval->string);
514 0 : JS_LeaveCrossCompartmentCall(call);
515 0 : JS_EndRequest(cx);
516 : }
517 0 : jsdval->string = NULL;
518 : }
519 :
520 2 : jsdval->funName = NULL;
521 2 : jsdval->className = NULL;
522 2 : DROP_CLEAR_VALUE(jsdc, jsdval->proto);
523 2 : DROP_CLEAR_VALUE(jsdc, jsdval->parent);
524 2 : DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
525 2 : _freeProps(jsdc, jsdval);
526 2 : jsdval->flags = 0;
527 : }
528 :
529 : /***************************************************************************/
530 :
531 : unsigned
532 0 : jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
533 : {
534 : JSDProperty* jsdprop;
535 0 : unsigned count = 0;
536 :
537 0 : if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
538 0 : if(!_buildProps(jsdc, jsdval))
539 0 : return 0;
540 :
541 0 : for(jsdprop = (JSDProperty*)jsdval->props.next;
542 0 : jsdprop != (JSDProperty*)&jsdval->props;
543 0 : jsdprop = (JSDProperty*)jsdprop->links.next)
544 : {
545 0 : count++;
546 : }
547 0 : return count;
548 : }
549 :
550 : JSDProperty*
551 0 : jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
552 : {
553 0 : JSDProperty* jsdprop = *iterp;
554 0 : if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
555 : {
556 0 : JS_ASSERT(!jsdprop);
557 0 : if(!_buildProps(jsdc, jsdval))
558 0 : return NULL;
559 : }
560 :
561 0 : if(!jsdprop)
562 0 : jsdprop = (JSDProperty*)jsdval->props.next;
563 0 : if(jsdprop == (JSDProperty*)&jsdval->props)
564 0 : return NULL;
565 0 : *iterp = (JSDProperty*)jsdprop->links.next;
566 :
567 0 : JS_ASSERT(jsdprop);
568 0 : jsdprop->nref++;
569 0 : return jsdprop;
570 : }
571 :
572 : JSDProperty*
573 0 : jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
574 : {
575 0 : JSContext* cx = jsdc->dumbContext;
576 : JSDProperty* jsdprop;
577 0 : JSDProperty* iter = NULL;
578 : JSObject* obj;
579 0 : unsigned attrs = 0;
580 : JSBool found;
581 : JSPropertyDesc pd;
582 : const jschar * nameChars;
583 : size_t nameLen;
584 : jsval val, nameval;
585 : jsid nameid;
586 0 : JSCrossCompartmentCall *call = NULL;
587 :
588 0 : if(!jsd_IsValueObject(jsdc, jsdval))
589 0 : return NULL;
590 :
591 : /* If we already have the prop, then return it */
592 0 : while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
593 : {
594 0 : JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
595 0 : if(propName) {
596 : int result;
597 0 : if (JS_CompareStrings(cx, propName, name, &result) && !result)
598 0 : return jsdprop;
599 : }
600 0 : JSD_DropProperty(jsdc, jsdprop);
601 : }
602 : /* Not found in property list, look it up explicitly */
603 :
604 0 : if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
605 0 : return NULL;
606 :
607 0 : if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
608 0 : return NULL;
609 :
610 0 : JS_BeginRequest(cx);
611 0 : call = JS_EnterCrossCompartmentCall(cx, obj);
612 0 : if(!call) {
613 0 : JS_EndRequest(cx);
614 :
615 0 : return NULL;
616 : }
617 :
618 0 : JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
619 0 : if (!found)
620 : {
621 0 : JS_LeaveCrossCompartmentCall(call);
622 0 : JS_EndRequest(cx);
623 0 : return NULL;
624 : }
625 :
626 0 : JS_ClearPendingException(cx);
627 :
628 0 : if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val))
629 : {
630 0 : if (JS_IsExceptionPending(cx))
631 : {
632 0 : if (!JS_GetPendingException(cx, &pd.value))
633 : {
634 0 : JS_LeaveCrossCompartmentCall(call);
635 0 : JS_EndRequest(cx);
636 0 : return NULL;
637 : }
638 0 : pd.flags = JSPD_EXCEPTION;
639 : }
640 : else
641 : {
642 0 : pd.flags = JSPD_ERROR;
643 0 : pd.value = JSVAL_VOID;
644 : }
645 : }
646 : else
647 : {
648 0 : pd.value = val;
649 : }
650 :
651 0 : JS_LeaveCrossCompartmentCall(call);
652 0 : JS_EndRequest(cx);
653 :
654 0 : nameval = STRING_TO_JSVAL(name);
655 0 : if (!JS_ValueToId(cx, nameval, &nameid) ||
656 0 : !JS_IdToValue(cx, nameid, &pd.id)) {
657 0 : return NULL;
658 : }
659 :
660 0 : pd.slot = pd.spare = 0;
661 0 : pd.alias = JSVAL_NULL;
662 0 : pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
663 0 : | (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0
664 : | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;
665 :
666 0 : return _newProperty(jsdc, &pd, JSDPD_HINTED);
667 : }
668 :
669 : /*
670 : * Retrieve a JSFunction* from a JSDValue*. This differs from
671 : * JS_ValueToFunction by fully unwrapping the object first.
672 : */
673 : JSFunction*
674 0 : jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
675 : {
676 : JSObject *obj;
677 : JSFunction *fun;
678 0 : JSCrossCompartmentCall *call = NULL;
679 0 : if (!JSVAL_IS_OBJECT(jsdval->val))
680 0 : return NULL;
681 0 : if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
682 0 : return NULL;
683 0 : obj = JS_UnwrapObject(obj);
684 :
685 0 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
686 0 : if (!call)
687 0 : return NULL;
688 0 : fun = JS_ValueToFunction(jsdc->dumbContext, OBJECT_TO_JSVAL(obj));
689 0 : JS_LeaveCrossCompartmentCall(call);
690 :
691 0 : return fun;
692 : }
693 :
694 : JSDValue*
695 0 : jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
696 : {
697 0 : JSCrossCompartmentCall *call = NULL;
698 :
699 0 : if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
700 : {
701 : JSObject* obj;
702 : JSObject* proto;
703 0 : JS_ASSERT(!jsdval->proto);
704 0 : SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
705 0 : if(!JSVAL_IS_OBJECT(jsdval->val))
706 0 : return NULL;
707 0 : if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
708 0 : return NULL;
709 0 : proto = JS_GetPrototype(obj);
710 0 : if(!proto)
711 0 : return NULL;
712 0 : jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
713 : }
714 0 : if(jsdval->proto)
715 0 : jsdval->proto->nref++;
716 0 : return jsdval->proto;
717 : }
718 :
719 : JSDValue*
720 1 : jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
721 : {
722 1 : JSCrossCompartmentCall *call = NULL;
723 :
724 1 : if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
725 : {
726 : JSObject* obj;
727 : JSObject* parent;
728 1 : JS_ASSERT(!jsdval->parent);
729 1 : SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
730 1 : if(!JSVAL_IS_OBJECT(jsdval->val))
731 0 : return NULL;
732 1 : if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
733 0 : return NULL;
734 1 : JS_BeginRequest(jsdc->dumbContext);
735 1 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
736 1 : if(!call) {
737 0 : JS_EndRequest(jsdc->dumbContext);
738 :
739 0 : return NULL;
740 : }
741 1 : parent = JS_GetParentOrScopeChain(jsdc->dumbContext,obj);
742 1 : JS_LeaveCrossCompartmentCall(call);
743 1 : JS_EndRequest(jsdc->dumbContext);
744 1 : if(!parent)
745 0 : return NULL;
746 1 : jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
747 : }
748 1 : if(jsdval->parent)
749 1 : jsdval->parent->nref++;
750 1 : return jsdval->parent;
751 : }
752 :
753 : JSDValue*
754 0 : jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
755 : {
756 0 : JSCrossCompartmentCall *call = NULL;
757 :
758 0 : if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
759 : {
760 : JSObject* obj;
761 : JSObject* proto;
762 : JSObject* ctor;
763 0 : JS_ASSERT(!jsdval->ctor);
764 0 : SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
765 0 : if(!JSVAL_IS_OBJECT(jsdval->val))
766 0 : return NULL;
767 0 : if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
768 0 : return NULL;
769 0 : proto = JS_GetPrototype(obj);
770 0 : if(!proto)
771 0 : return NULL;
772 0 : JS_BeginRequest(jsdc->dumbContext);
773 0 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
774 0 : if(!call) {
775 0 : JS_EndRequest(jsdc->dumbContext);
776 :
777 0 : return NULL;
778 : }
779 0 : ctor = JS_GetConstructor(jsdc->dumbContext,proto);
780 0 : JS_LeaveCrossCompartmentCall(call);
781 0 : JS_EndRequest(jsdc->dumbContext);
782 0 : if(!ctor)
783 0 : return NULL;
784 0 : jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
785 : }
786 0 : if(jsdval->ctor)
787 0 : jsdval->ctor->nref++;
788 0 : return jsdval->ctor;
789 : }
790 :
791 : const char*
792 0 : jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
793 : {
794 0 : jsval val = jsdval->val;
795 0 : JSCrossCompartmentCall *call = NULL;
796 :
797 0 : if(!jsdval->className && JSVAL_IS_OBJECT(val))
798 : {
799 : JSObject* obj;
800 0 : if(!(obj = JSVAL_TO_OBJECT(val)))
801 0 : return NULL;
802 0 : JS_BeginRequest(jsdc->dumbContext);
803 0 : call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
804 0 : if(!call) {
805 0 : JS_EndRequest(jsdc->dumbContext);
806 :
807 0 : return NULL;
808 : }
809 0 : jsdval->className = JS_GetClass(obj)->name;
810 0 : JS_LeaveCrossCompartmentCall(call);
811 0 : JS_EndRequest(jsdc->dumbContext);
812 : }
813 0 : return jsdval->className;
814 : }
815 :
816 : JSDScript*
817 0 : jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
818 : {
819 0 : JSContext* cx = jsdc->dumbContext;
820 0 : jsval val = jsdval->val;
821 0 : JSFunction* fun = NULL;
822 : JSExceptionState* exceptionState;
823 0 : JSScript* script = NULL;
824 : JSDScript* jsdscript;
825 0 : JSCrossCompartmentCall *call = NULL;
826 :
827 0 : if (!jsd_IsValueFunction(jsdc, jsdval))
828 0 : return NULL;
829 :
830 0 : JS_BeginRequest(cx);
831 0 : call = JS_EnterCrossCompartmentCall(cx, JSVAL_TO_OBJECT(val));
832 0 : if (!call) {
833 0 : JS_EndRequest(cx);
834 :
835 0 : return NULL;
836 : }
837 :
838 0 : exceptionState = JS_SaveExceptionState(cx);
839 0 : fun = JSD_GetValueFunction(jsdc, jsdval);
840 0 : JS_RestoreExceptionState(cx, exceptionState);
841 0 : if (fun)
842 0 : script = JS_GetFunctionScript(cx, fun);
843 0 : JS_LeaveCrossCompartmentCall(call);
844 0 : JS_EndRequest(cx);
845 :
846 0 : if (!script)
847 0 : return NULL;
848 :
849 0 : JSD_LOCK_SCRIPTS(jsdc);
850 0 : jsdscript = jsd_FindJSDScript(jsdc, script);
851 0 : JSD_UNLOCK_SCRIPTS(jsdc);
852 0 : return jsdscript;
853 : }
854 :
855 :
856 : /***************************************************************************/
857 : /***************************************************************************/
858 :
859 : JSDValue*
860 0 : jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
861 : {
862 0 : jsdprop->name->nref++;
863 0 : return jsdprop->name;
864 : }
865 :
866 : JSDValue*
867 0 : jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
868 : {
869 0 : jsdprop->val->nref++;
870 0 : return jsdprop->val;
871 : }
872 :
873 : JSDValue*
874 0 : jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
875 : {
876 0 : if(jsdprop->alias)
877 0 : jsdprop->alias->nref++;
878 0 : return jsdprop->alias;
879 : }
880 :
881 : unsigned
882 0 : jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
883 : {
884 0 : return jsdprop->flags;
885 : }
886 :
887 : unsigned
888 0 : jsd_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop)
889 : {
890 0 : return jsdprop->slot;
891 : }
892 :
893 : void
894 0 : jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop)
895 : {
896 0 : JS_ASSERT(jsdprop->nref > 0);
897 0 : if(0 == --jsdprop->nref)
898 : {
899 0 : JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links));
900 0 : DROP_CLEAR_VALUE(jsdc, jsdprop->val);
901 0 : DROP_CLEAR_VALUE(jsdc, jsdprop->name);
902 0 : DROP_CLEAR_VALUE(jsdc, jsdprop->alias);
903 0 : free(jsdprop);
904 : }
905 0 : }
|