js/jsd/jsd_val.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*
michael@0 8 * JavaScript Debugging support - Value and Property support
michael@0 9 */
michael@0 10
michael@0 11 #include "jsd.h"
michael@0 12 #include "jsapi.h"
michael@0 13 #include "jsfriendapi.h"
michael@0 14 #include "jswrapper.h"
michael@0 15 #include "nsCxPusher.h"
michael@0 16
michael@0 17 using mozilla::AutoSafeJSContext;
michael@0 18
michael@0 19 #ifdef DEBUG
michael@0 20 void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
michael@0 21 {
michael@0 22 MOZ_ASSERT(jsdval);
michael@0 23 MOZ_ASSERT(jsdval->nref > 0);
michael@0 24 if(!JS_CLIST_IS_EMPTY(&jsdval->props))
michael@0 25 {
michael@0 26 MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS));
michael@0 27 MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val));
michael@0 28 }
michael@0 29
michael@0 30 if(jsdval->proto)
michael@0 31 {
michael@0 32 MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO));
michael@0 33 MOZ_ASSERT(jsdval->proto->nref > 0);
michael@0 34 }
michael@0 35 if(jsdval->parent)
michael@0 36 {
michael@0 37 MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT));
michael@0 38 MOZ_ASSERT(jsdval->parent->nref > 0);
michael@0 39 }
michael@0 40 if(jsdval->ctor)
michael@0 41 {
michael@0 42 MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR));
michael@0 43 MOZ_ASSERT(jsdval->ctor->nref > 0);
michael@0 44 }
michael@0 45 }
michael@0 46
michael@0 47 void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop)
michael@0 48 {
michael@0 49 MOZ_ASSERT(jsdprop);
michael@0 50 MOZ_ASSERT(jsdprop->name);
michael@0 51 MOZ_ASSERT(jsdprop->name->nref > 0);
michael@0 52 MOZ_ASSERT(jsdprop->val);
michael@0 53 MOZ_ASSERT(jsdprop->val->nref > 0);
michael@0 54 if(jsdprop->alias)
michael@0 55 MOZ_ASSERT(jsdprop->alias->nref > 0);
michael@0 56 }
michael@0 57 #endif
michael@0 58
michael@0 59
michael@0 60 bool
michael@0 61 jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
michael@0 62 {
michael@0 63 return !JSVAL_IS_PRIMITIVE(jsdval->val) || JSVAL_IS_NULL(jsdval->val);
michael@0 64 }
michael@0 65
michael@0 66 bool
michael@0 67 jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
michael@0 68 {
michael@0 69 return JSVAL_IS_NUMBER(jsdval->val);
michael@0 70 }
michael@0 71
michael@0 72 bool
michael@0 73 jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
michael@0 74 {
michael@0 75 return JSVAL_IS_INT(jsdval->val);
michael@0 76 }
michael@0 77
michael@0 78 bool
michael@0 79 jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
michael@0 80 {
michael@0 81 return JSVAL_IS_DOUBLE(jsdval->val);
michael@0 82 }
michael@0 83
michael@0 84 bool
michael@0 85 jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
michael@0 86 {
michael@0 87 return JSVAL_IS_STRING(jsdval->val);
michael@0 88 }
michael@0 89
michael@0 90 bool
michael@0 91 jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
michael@0 92 {
michael@0 93 return JSVAL_IS_BOOLEAN(jsdval->val);
michael@0 94 }
michael@0 95
michael@0 96 bool
michael@0 97 jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
michael@0 98 {
michael@0 99 return JSVAL_IS_NULL(jsdval->val);
michael@0 100 }
michael@0 101
michael@0 102 bool
michael@0 103 jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
michael@0 104 {
michael@0 105 return JSVAL_IS_VOID(jsdval->val);
michael@0 106 }
michael@0 107
michael@0 108 bool
michael@0 109 jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
michael@0 110 {
michael@0 111 return JSVAL_IS_PRIMITIVE(jsdval->val);
michael@0 112 }
michael@0 113
michael@0 114 bool
michael@0 115 jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
michael@0 116 {
michael@0 117 AutoSafeJSContext cx; // NB: Actually unused.
michael@0 118 return !JSVAL_IS_PRIMITIVE(jsdval->val) &&
michael@0 119 JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(jsdval->val));
michael@0 120 }
michael@0 121
michael@0 122 bool
michael@0 123 jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
michael@0 124 {
michael@0 125 AutoSafeJSContext cx;
michael@0 126 JS::RootedFunction fun(cx);
michael@0 127
michael@0 128 if(jsd_IsValueFunction(jsdc, jsdval))
michael@0 129 {
michael@0 130 JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val));
michael@0 131 AutoSaveExceptionState as(cx);
michael@0 132 bool ok = false;
michael@0 133 fun = JSD_GetValueFunction(jsdc, jsdval);
michael@0 134 if(fun)
michael@0 135 ok = JS_GetFunctionScript(cx, fun) ? false : true;
michael@0 136 MOZ_ASSERT(fun);
michael@0 137 return ok;
michael@0 138 }
michael@0 139 return !JSVAL_IS_PRIMITIVE(jsdval->val);
michael@0 140 }
michael@0 141
michael@0 142 /***************************************************************************/
michael@0 143
michael@0 144 bool
michael@0 145 jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
michael@0 146 {
michael@0 147 jsval val = jsdval->val;
michael@0 148 if(!JSVAL_IS_BOOLEAN(val))
michael@0 149 return false;
michael@0 150 return JSVAL_TO_BOOLEAN(val);
michael@0 151 }
michael@0 152
michael@0 153 int32_t
michael@0 154 jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
michael@0 155 {
michael@0 156 jsval val = jsdval->val;
michael@0 157 if(!JSVAL_IS_INT(val))
michael@0 158 return 0;
michael@0 159 return JSVAL_TO_INT(val);
michael@0 160 }
michael@0 161
michael@0 162 double
michael@0 163 jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
michael@0 164 {
michael@0 165 if(!JSVAL_IS_DOUBLE(jsdval->val))
michael@0 166 return 0;
michael@0 167 return JSVAL_TO_DOUBLE(jsdval->val);
michael@0 168 }
michael@0 169
michael@0 170 JSString*
michael@0 171 jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
michael@0 172 {
michael@0 173 AutoSafeJSContext cx;
michael@0 174 JS::RootedValue stringval(cx);
michael@0 175 JS::RootedString string(cx);
michael@0 176 JS::RootedObject scopeObj(cx);
michael@0 177
michael@0 178 if(jsdval->string)
michael@0 179 return jsdval->string;
michael@0 180
michael@0 181 /* Reuse the string without copying or re-rooting it */
michael@0 182 if(JSVAL_IS_STRING(jsdval->val)) {
michael@0 183 jsdval->string = JSVAL_TO_STRING(jsdval->val);
michael@0 184 return jsdval->string;
michael@0 185 }
michael@0 186
michael@0 187 /* Objects call JS_ValueToString in their own compartment. */
michael@0 188 scopeObj = !JSVAL_IS_PRIMITIVE(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob;
michael@0 189 {
michael@0 190 JSAutoCompartment ac(cx, scopeObj);
michael@0 191 AutoSaveExceptionState as(cx);
michael@0 192 JS::RootedValue v(cx, jsdval->val);
michael@0 193 string = JS::ToString(cx, v);
michael@0 194 }
michael@0 195
michael@0 196 JSAutoCompartment ac2(cx, jsdc->glob);
michael@0 197 if(string) {
michael@0 198 stringval = STRING_TO_JSVAL(string);
michael@0 199 }
michael@0 200 if(!string || !JS_WrapValue(cx, &stringval)) {
michael@0 201 return nullptr;
michael@0 202 }
michael@0 203
michael@0 204 jsdval->string = JSVAL_TO_STRING(stringval);
michael@0 205 if(!JS::AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
michael@0 206 jsdval->string = nullptr;
michael@0 207
michael@0 208 return jsdval->string;
michael@0 209 }
michael@0 210
michael@0 211 JSString*
michael@0 212 jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
michael@0 213 {
michael@0 214 AutoSafeJSContext cx;
michael@0 215 JS::RootedFunction fun(cx);
michael@0 216
michael@0 217 if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
michael@0 218 {
michael@0 219 JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val));
michael@0 220 AutoSaveExceptionState as(cx);
michael@0 221 fun = JSD_GetValueFunction(jsdc, jsdval);
michael@0 222 if(!fun)
michael@0 223 return nullptr;
michael@0 224 jsdval->funName = JS_GetFunctionId(fun);
michael@0 225
michael@0 226 /* For compatibility we return "anonymous", not an empty string here. */
michael@0 227 if (!jsdval->funName)
michael@0 228 jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
michael@0 229 }
michael@0 230 return jsdval->funName;
michael@0 231 }
michael@0 232
michael@0 233 /***************************************************************************/
michael@0 234
michael@0 235 /*
michael@0 236 * Create a new JSD value referring to a jsval. Copy string values into the
michael@0 237 * JSD compartment. Leave all other GCTHINGs in their native compartments
michael@0 238 * and access them through cross-compartment calls.
michael@0 239 */
michael@0 240 JSDValue*
michael@0 241 jsd_NewValue(JSDContext* jsdc, jsval value)
michael@0 242 {
michael@0 243 JS::RootedValue val(jsdc->jsrt, value);
michael@0 244 AutoSafeJSContext cx;
michael@0 245 JSDValue* jsdval;
michael@0 246
michael@0 247 if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
michael@0 248 return nullptr;
michael@0 249
michael@0 250 if(JSVAL_IS_GCTHING(val))
michael@0 251 {
michael@0 252 bool ok;
michael@0 253 JSAutoCompartment ac(cx, jsdc->glob);
michael@0 254
michael@0 255 ok = JS::AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
michael@0 256 if(ok && JSVAL_IS_STRING(val)) {
michael@0 257 if(!JS_WrapValue(cx, &val)) {
michael@0 258 ok = false;
michael@0 259 }
michael@0 260 }
michael@0 261
michael@0 262 if(!ok)
michael@0 263 {
michael@0 264 free(jsdval);
michael@0 265 return nullptr;
michael@0 266 }
michael@0 267 }
michael@0 268 jsdval->val = val;
michael@0 269 jsdval->nref = 1;
michael@0 270 JS_INIT_CLIST(&jsdval->props);
michael@0 271
michael@0 272 return jsdval;
michael@0 273 }
michael@0 274
michael@0 275 void
michael@0 276 jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
michael@0 277 {
michael@0 278 MOZ_ASSERT(jsdval->nref > 0);
michael@0 279 if(0 == --jsdval->nref)
michael@0 280 {
michael@0 281 jsd_RefreshValue(jsdc, jsdval);
michael@0 282 if(JSVAL_IS_GCTHING(jsdval->val))
michael@0 283 {
michael@0 284 AutoSafeJSContext cx;
michael@0 285 JSAutoCompartment ac(cx, jsdc->glob);
michael@0 286 JS::RemoveValueRoot(cx, &jsdval->val);
michael@0 287 }
michael@0 288 free(jsdval);
michael@0 289 }
michael@0 290 }
michael@0 291
michael@0 292 jsval
michael@0 293 jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
michael@0 294 {
michael@0 295 AutoSafeJSContext cx;
michael@0 296 JS::RootedValue val(cx, jsdval->val);
michael@0 297 if (!val.isPrimitive()) {
michael@0 298 JS::RootedObject obj(cx, &val.toObject());
michael@0 299 JSAutoCompartment ac(cx, obj);
michael@0 300 obj = JS_ObjectToOuterObject(cx, obj);
michael@0 301 if (!obj)
michael@0 302 {
michael@0 303 JS_ClearPendingException(cx);
michael@0 304 val = JSVAL_NULL;
michael@0 305 }
michael@0 306 else
michael@0 307 val = JS::ObjectValue(*obj);
michael@0 308 }
michael@0 309
michael@0 310 return val;
michael@0 311 }
michael@0 312
michael@0 313 static JSDProperty* _newProperty(JSDContext* jsdc, JS::HandleValue propId,
michael@0 314 JS::HandleValue propValue, JS::HandleValue propAlias,
michael@0 315 uint8_t propFlags, unsigned additionalFlags)
michael@0 316 {
michael@0 317 JSDProperty* jsdprop;
michael@0 318
michael@0 319 if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
michael@0 320 return nullptr;
michael@0 321
michael@0 322 JS_INIT_CLIST(&jsdprop->links);
michael@0 323 jsdprop->nref = 1;
michael@0 324 jsdprop->flags = propFlags | additionalFlags;
michael@0 325
michael@0 326 if(!(jsdprop->name = jsd_NewValue(jsdc, propId)))
michael@0 327 goto new_prop_fail;
michael@0 328
michael@0 329 if(!(jsdprop->val = jsd_NewValue(jsdc, propValue)))
michael@0 330 goto new_prop_fail;
michael@0 331
michael@0 332 if((jsdprop->flags & JSDPD_ALIAS) &&
michael@0 333 !(jsdprop->alias = jsd_NewValue(jsdc, propAlias)))
michael@0 334 goto new_prop_fail;
michael@0 335
michael@0 336 return jsdprop;
michael@0 337 new_prop_fail:
michael@0 338 jsd_DropProperty(jsdc, jsdprop);
michael@0 339 return nullptr;
michael@0 340 }
michael@0 341
michael@0 342 static void _freeProps(JSDContext* jsdc, JSDValue* jsdval)
michael@0 343 {
michael@0 344 JSDProperty* jsdprop;
michael@0 345
michael@0 346 while(jsdprop = (JSDProperty*)jsdval->props.next,
michael@0 347 jsdprop != (JSDProperty*)&jsdval->props)
michael@0 348 {
michael@0 349 JS_REMOVE_AND_INIT_LINK(&jsdprop->links);
michael@0 350 jsd_DropProperty(jsdc, jsdprop);
michael@0 351 }
michael@0 352 MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
michael@0 353 CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS);
michael@0 354 }
michael@0 355
michael@0 356 static bool _buildProps(JSDContext* jsdc, JSDValue* jsdval)
michael@0 357 {
michael@0 358 AutoSafeJSContext cx;
michael@0 359 JS::RootedObject obj(cx);
michael@0 360 JSPropertyDescArray pda;
michael@0 361 unsigned i;
michael@0 362
michael@0 363 MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
michael@0 364 MOZ_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
michael@0 365 MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val));
michael@0 366
michael@0 367 if(JSVAL_IS_PRIMITIVE(jsdval->val))
michael@0 368 return false;
michael@0 369
michael@0 370 obj = JSVAL_TO_OBJECT(jsdval->val);
michael@0 371
michael@0 372 JSAutoCompartment ac(cx, obj);
michael@0 373
michael@0 374 if(!JS_GetPropertyDescArray(cx, obj, &pda))
michael@0 375 {
michael@0 376 return false;
michael@0 377 }
michael@0 378
michael@0 379 JS::RootedValue propId(cx);
michael@0 380 JS::RootedValue propValue(cx);
michael@0 381 JS::RootedValue propAlias(cx);
michael@0 382 uint8_t propFlags;
michael@0 383 for(i = 0; i < pda.length; i++)
michael@0 384 {
michael@0 385 propId = pda.array[i].id;
michael@0 386 propValue = pda.array[i].value;
michael@0 387 propAlias = pda.array[i].alias;
michael@0 388 propFlags = pda.array[i].flags;
michael@0 389 JSDProperty* prop = _newProperty(jsdc, propId, propValue, propAlias, propFlags, 0);
michael@0 390 if(!prop)
michael@0 391 {
michael@0 392 _freeProps(jsdc, jsdval);
michael@0 393 break;
michael@0 394 }
michael@0 395 JS_APPEND_LINK(&prop->links, &jsdval->props);
michael@0 396 }
michael@0 397 JS_PutPropertyDescArray(cx, &pda);
michael@0 398 SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
michael@0 399 return !JS_CLIST_IS_EMPTY(&jsdval->props);
michael@0 400 }
michael@0 401
michael@0 402 #undef DROP_CLEAR_VALUE
michael@0 403 #define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = nullptr;}
michael@0 404
michael@0 405 void
michael@0 406 jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
michael@0 407 {
michael@0 408 AutoSafeJSContext cx;
michael@0 409 if(jsdval->string)
michael@0 410 {
michael@0 411 /* if the jsval is a string, then we didn't need to root the string */
michael@0 412 if(!JSVAL_IS_STRING(jsdval->val))
michael@0 413 {
michael@0 414 JSAutoCompartment ac(cx, jsdc->glob);
michael@0 415 JS::RemoveStringRoot(cx, &jsdval->string);
michael@0 416 }
michael@0 417 jsdval->string = nullptr;
michael@0 418 }
michael@0 419
michael@0 420 jsdval->funName = nullptr;
michael@0 421 jsdval->className = nullptr;
michael@0 422 DROP_CLEAR_VALUE(jsdc, jsdval->proto);
michael@0 423 DROP_CLEAR_VALUE(jsdc, jsdval->parent);
michael@0 424 DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
michael@0 425 _freeProps(jsdc, jsdval);
michael@0 426 jsdval->flags = 0;
michael@0 427 }
michael@0 428
michael@0 429 /***************************************************************************/
michael@0 430
michael@0 431 unsigned
michael@0 432 jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
michael@0 433 {
michael@0 434 JSDProperty* jsdprop;
michael@0 435 unsigned count = 0;
michael@0 436
michael@0 437 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
michael@0 438 if(!_buildProps(jsdc, jsdval))
michael@0 439 return 0;
michael@0 440
michael@0 441 for(jsdprop = (JSDProperty*)jsdval->props.next;
michael@0 442 jsdprop != (JSDProperty*)&jsdval->props;
michael@0 443 jsdprop = (JSDProperty*)jsdprop->links.next)
michael@0 444 {
michael@0 445 count++;
michael@0 446 }
michael@0 447 return count;
michael@0 448 }
michael@0 449
michael@0 450 JSDProperty*
michael@0 451 jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
michael@0 452 {
michael@0 453 JSDProperty* jsdprop = *iterp;
michael@0 454 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
michael@0 455 {
michael@0 456 MOZ_ASSERT(!jsdprop);
michael@0 457 if(!_buildProps(jsdc, jsdval))
michael@0 458 return nullptr;
michael@0 459 }
michael@0 460
michael@0 461 if(!jsdprop)
michael@0 462 jsdprop = (JSDProperty*)jsdval->props.next;
michael@0 463 if(jsdprop == (JSDProperty*)&jsdval->props)
michael@0 464 return nullptr;
michael@0 465 *iterp = (JSDProperty*)jsdprop->links.next;
michael@0 466
michael@0 467 MOZ_ASSERT(jsdprop);
michael@0 468 jsdprop->nref++;
michael@0 469 return jsdprop;
michael@0 470 }
michael@0 471
michael@0 472 JSDProperty*
michael@0 473 jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr)
michael@0 474 {
michael@0 475 JS::RootedString name(jsdc->jsrt, nameStr);
michael@0 476 AutoSafeJSContext cx;
michael@0 477 JSAutoCompartment acBase(cx, jsdc->glob);
michael@0 478 JSDProperty* jsdprop;
michael@0 479 JSDProperty* iter = nullptr;
michael@0 480 JS::RootedObject obj(cx);
michael@0 481 JS::RootedValue val(cx), nameval(cx);
michael@0 482 JS::RootedId nameid(cx);
michael@0 483 JS::RootedValue propId(cx);
michael@0 484 JS::RootedValue propValue(cx);
michael@0 485 JS::RootedValue propAlias(cx);
michael@0 486 uint8_t propFlags;
michael@0 487
michael@0 488 if(!jsd_IsValueObject(jsdc, jsdval))
michael@0 489 return nullptr;
michael@0 490
michael@0 491 /* If we already have the prop, then return it */
michael@0 492 while(nullptr != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
michael@0 493 {
michael@0 494 JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
michael@0 495 if(propName) {
michael@0 496 int result;
michael@0 497 if (JS_CompareStrings(cx, propName, name, &result) && !result)
michael@0 498 return jsdprop;
michael@0 499 }
michael@0 500 JSD_DropProperty(jsdc, jsdprop);
michael@0 501 }
michael@0 502 /* Not found in property list, look it up explicitly */
michael@0 503
michael@0 504 nameval = STRING_TO_JSVAL(name);
michael@0 505 if(!JS_ValueToId(cx, nameval, &nameid))
michael@0 506 return nullptr;
michael@0 507
michael@0 508 if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
michael@0 509 return nullptr;
michael@0 510
michael@0 511 JS::Rooted<JSPropertyDescriptor> desc(cx);
michael@0 512 {
michael@0 513 JSAutoCompartment ac(cx, obj);
michael@0 514 JS::RootedId id(cx, nameid);
michael@0 515
michael@0 516 if(!JS_WrapId(cx, &id))
michael@0 517 return nullptr;
michael@0 518 if(!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc))
michael@0 519 return nullptr;
michael@0 520 if(!desc.object())
michael@0 521 return nullptr;
michael@0 522
michael@0 523 JS_ClearPendingException(cx);
michael@0 524
michael@0 525 if(!JS_GetPropertyById(cx, obj, id, &val))
michael@0 526 {
michael@0 527 if (JS_IsExceptionPending(cx))
michael@0 528 {
michael@0 529 if (!JS_GetPendingException(cx, &propValue))
michael@0 530 {
michael@0 531 return nullptr;
michael@0 532 }
michael@0 533 propFlags = JSPD_EXCEPTION;
michael@0 534 }
michael@0 535 else
michael@0 536 {
michael@0 537 propFlags = JSPD_ERROR;
michael@0 538 propValue = JSVAL_VOID;
michael@0 539 }
michael@0 540 }
michael@0 541 else
michael@0 542 {
michael@0 543 propValue = val;
michael@0 544 }
michael@0 545 }
michael@0 546
michael@0 547 if (!JS_IdToValue(cx, nameid, &propId))
michael@0 548 return nullptr;
michael@0 549
michael@0 550 propAlias = JSVAL_NULL;
michael@0 551 propFlags |= desc.isEnumerable() ? JSPD_ENUMERATE : 0
michael@0 552 | desc.isReadonly() ? JSPD_READONLY : 0
michael@0 553 | desc.isPermanent() ? JSPD_PERMANENT : 0;
michael@0 554
michael@0 555 return _newProperty(jsdc, propId, propValue, propAlias, propFlags, JSDPD_HINTED);
michael@0 556 }
michael@0 557
michael@0 558 /*
michael@0 559 * Retrieve a JSFunction* from a JSDValue*. This differs from
michael@0 560 * JS_ValueToFunction by fully unwrapping the object first.
michael@0 561 */
michael@0 562 JSFunction*
michael@0 563 jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
michael@0 564 {
michael@0 565 AutoSafeJSContext cx;
michael@0 566
michael@0 567 JS::RootedObject obj(cx);
michael@0 568 JS::RootedFunction fun(cx);
michael@0 569
michael@0 570 if (JSVAL_IS_PRIMITIVE(jsdval->val))
michael@0 571 return nullptr;
michael@0 572
michael@0 573 obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val));
michael@0 574 JSAutoCompartment ac(cx, obj);
michael@0 575 JS::RootedValue funval(cx, JS::ObjectValue(*obj));
michael@0 576 fun = JS_ValueToFunction(cx, funval);
michael@0 577
michael@0 578 return fun;
michael@0 579 }
michael@0 580
michael@0 581 JSDValue*
michael@0 582 jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
michael@0 583 {
michael@0 584 AutoSafeJSContext cx;
michael@0 585 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
michael@0 586 {
michael@0 587 JS::RootedObject obj(cx);
michael@0 588 JS::RootedObject proto(cx);
michael@0 589 MOZ_ASSERT(!jsdval->proto);
michael@0 590 SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
michael@0 591 if(JSVAL_IS_PRIMITIVE(jsdval->val))
michael@0 592 return nullptr;
michael@0 593 obj = JSVAL_TO_OBJECT(jsdval->val);
michael@0 594 if(!JS_GetPrototype(cx, obj, &proto))
michael@0 595 return nullptr;
michael@0 596 if(!proto)
michael@0 597 return nullptr;
michael@0 598 jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
michael@0 599 }
michael@0 600 if(jsdval->proto)
michael@0 601 jsdval->proto->nref++;
michael@0 602 return jsdval->proto;
michael@0 603 }
michael@0 604
michael@0 605 JSDValue*
michael@0 606 jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
michael@0 607 {
michael@0 608 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
michael@0 609 {
michael@0 610 AutoSafeJSContext cx;
michael@0 611 JS::RootedObject obj(cx);
michael@0 612 JS::RootedObject parent(cx);
michael@0 613 MOZ_ASSERT(!jsdval->parent);
michael@0 614 SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
michael@0 615 if(JSVAL_IS_PRIMITIVE(jsdval->val))
michael@0 616 return nullptr;
michael@0 617 obj = JSVAL_TO_OBJECT(jsdval->val);
michael@0 618 {
michael@0 619 JSAutoCompartment ac(cx, obj);
michael@0 620 parent = JS_GetParentOrScopeChain(cx, obj);
michael@0 621 }
michael@0 622 if(!parent)
michael@0 623 return nullptr;
michael@0 624 jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
michael@0 625 }
michael@0 626 if(jsdval->parent)
michael@0 627 jsdval->parent->nref++;
michael@0 628 return jsdval->parent;
michael@0 629 }
michael@0 630
michael@0 631 JSDValue*
michael@0 632 jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
michael@0 633 {
michael@0 634 if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
michael@0 635 {
michael@0 636 AutoSafeJSContext cx;
michael@0 637 JS::RootedObject obj(cx);
michael@0 638 JS::RootedObject proto(cx);
michael@0 639 JS::RootedObject ctor(cx);
michael@0 640 MOZ_ASSERT(!jsdval->ctor);
michael@0 641 SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
michael@0 642 if(JSVAL_IS_PRIMITIVE(jsdval->val))
michael@0 643 return nullptr;
michael@0 644 obj = JSVAL_TO_OBJECT(jsdval->val);
michael@0 645 if(!JS_GetPrototype(cx, obj, &proto))
michael@0 646 return nullptr;
michael@0 647 if(!proto)
michael@0 648 return nullptr;
michael@0 649 {
michael@0 650 JSAutoCompartment ac(cx, obj);
michael@0 651 ctor = JS_GetConstructor(cx, proto);
michael@0 652 }
michael@0 653 if(!ctor)
michael@0 654 return nullptr;
michael@0 655 jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
michael@0 656 }
michael@0 657 if(jsdval->ctor)
michael@0 658 jsdval->ctor->nref++;
michael@0 659 return jsdval->ctor;
michael@0 660 }
michael@0 661
michael@0 662 const char*
michael@0 663 jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
michael@0 664 {
michael@0 665 jsval val = jsdval->val;
michael@0 666 if(!jsdval->className && !JSVAL_IS_PRIMITIVE(val))
michael@0 667 {
michael@0 668 JS::RootedObject obj(jsdc->jsrt, JSVAL_TO_OBJECT(val));
michael@0 669 AutoSafeJSContext cx;
michael@0 670 JSAutoCompartment ac(cx, obj);
michael@0 671 jsdval->className = JS_GetDebugClassName(obj);
michael@0 672 }
michael@0 673 return jsdval->className;
michael@0 674 }
michael@0 675
michael@0 676 JSDScript*
michael@0 677 jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
michael@0 678 {
michael@0 679 AutoSafeJSContext cx;
michael@0 680 JS::RootedValue val(cx, jsdval->val);
michael@0 681 JS::RootedScript script(cx);
michael@0 682 JSDScript* jsdscript;
michael@0 683
michael@0 684 if (!jsd_IsValueFunction(jsdc, jsdval))
michael@0 685 return nullptr;
michael@0 686
michael@0 687 {
michael@0 688 JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(val));
michael@0 689 AutoSaveExceptionState as(cx);
michael@0 690 JS::RootedFunction fun(cx, JSD_GetValueFunction(jsdc, jsdval));
michael@0 691 if (fun)
michael@0 692 script = JS_GetFunctionScript(cx, fun);
michael@0 693 }
michael@0 694
michael@0 695 if (!script)
michael@0 696 return nullptr;
michael@0 697
michael@0 698 JSD_LOCK_SCRIPTS(jsdc);
michael@0 699 jsdscript = jsd_FindJSDScript(jsdc, script);
michael@0 700 JSD_UNLOCK_SCRIPTS(jsdc);
michael@0 701 return jsdscript;
michael@0 702 }
michael@0 703
michael@0 704
michael@0 705 /***************************************************************************/
michael@0 706 /***************************************************************************/
michael@0 707
michael@0 708 JSDValue*
michael@0 709 jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
michael@0 710 {
michael@0 711 jsdprop->name->nref++;
michael@0 712 return jsdprop->name;
michael@0 713 }
michael@0 714
michael@0 715 JSDValue*
michael@0 716 jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
michael@0 717 {
michael@0 718 jsdprop->val->nref++;
michael@0 719 return jsdprop->val;
michael@0 720 }
michael@0 721
michael@0 722 JSDValue*
michael@0 723 jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
michael@0 724 {
michael@0 725 if(jsdprop->alias)
michael@0 726 jsdprop->alias->nref++;
michael@0 727 return jsdprop->alias;
michael@0 728 }
michael@0 729
michael@0 730 unsigned
michael@0 731 jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
michael@0 732 {
michael@0 733 return jsdprop->flags;
michael@0 734 }
michael@0 735
michael@0 736 void
michael@0 737 jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop)
michael@0 738 {
michael@0 739 MOZ_ASSERT(jsdprop->nref > 0);
michael@0 740 if(0 == --jsdprop->nref)
michael@0 741 {
michael@0 742 MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links));
michael@0 743 DROP_CLEAR_VALUE(jsdc, jsdprop->val);
michael@0 744 DROP_CLEAR_VALUE(jsdc, jsdprop->name);
michael@0 745 DROP_CLEAR_VALUE(jsdc, jsdprop->alias);
michael@0 746 free(jsdprop);
michael@0 747 }
michael@0 748 }

mercurial