1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/jsd/jsd_val.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,748 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JavaScript Debugging support - Value and Property support 1.12 + */ 1.13 + 1.14 +#include "jsd.h" 1.15 +#include "jsapi.h" 1.16 +#include "jsfriendapi.h" 1.17 +#include "jswrapper.h" 1.18 +#include "nsCxPusher.h" 1.19 + 1.20 +using mozilla::AutoSafeJSContext; 1.21 + 1.22 +#ifdef DEBUG 1.23 +void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval) 1.24 +{ 1.25 + MOZ_ASSERT(jsdval); 1.26 + MOZ_ASSERT(jsdval->nref > 0); 1.27 + if(!JS_CLIST_IS_EMPTY(&jsdval->props)) 1.28 + { 1.29 + MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)); 1.30 + MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val)); 1.31 + } 1.32 + 1.33 + if(jsdval->proto) 1.34 + { 1.35 + MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)); 1.36 + MOZ_ASSERT(jsdval->proto->nref > 0); 1.37 + } 1.38 + if(jsdval->parent) 1.39 + { 1.40 + MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)); 1.41 + MOZ_ASSERT(jsdval->parent->nref > 0); 1.42 + } 1.43 + if(jsdval->ctor) 1.44 + { 1.45 + MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)); 1.46 + MOZ_ASSERT(jsdval->ctor->nref > 0); 1.47 + } 1.48 +} 1.49 + 1.50 +void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop) 1.51 +{ 1.52 + MOZ_ASSERT(jsdprop); 1.53 + MOZ_ASSERT(jsdprop->name); 1.54 + MOZ_ASSERT(jsdprop->name->nref > 0); 1.55 + MOZ_ASSERT(jsdprop->val); 1.56 + MOZ_ASSERT(jsdprop->val->nref > 0); 1.57 + if(jsdprop->alias) 1.58 + MOZ_ASSERT(jsdprop->alias->nref > 0); 1.59 +} 1.60 +#endif 1.61 + 1.62 + 1.63 +bool 1.64 +jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval) 1.65 +{ 1.66 + return !JSVAL_IS_PRIMITIVE(jsdval->val) || JSVAL_IS_NULL(jsdval->val); 1.67 +} 1.68 + 1.69 +bool 1.70 +jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval) 1.71 +{ 1.72 + return JSVAL_IS_NUMBER(jsdval->val); 1.73 +} 1.74 + 1.75 +bool 1.76 +jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval) 1.77 +{ 1.78 + return JSVAL_IS_INT(jsdval->val); 1.79 +} 1.80 + 1.81 +bool 1.82 +jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval) 1.83 +{ 1.84 + return JSVAL_IS_DOUBLE(jsdval->val); 1.85 +} 1.86 + 1.87 +bool 1.88 +jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval) 1.89 +{ 1.90 + return JSVAL_IS_STRING(jsdval->val); 1.91 +} 1.92 + 1.93 +bool 1.94 +jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval) 1.95 +{ 1.96 + return JSVAL_IS_BOOLEAN(jsdval->val); 1.97 +} 1.98 + 1.99 +bool 1.100 +jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval) 1.101 +{ 1.102 + return JSVAL_IS_NULL(jsdval->val); 1.103 +} 1.104 + 1.105 +bool 1.106 +jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval) 1.107 +{ 1.108 + return JSVAL_IS_VOID(jsdval->val); 1.109 +} 1.110 + 1.111 +bool 1.112 +jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval) 1.113 +{ 1.114 + return JSVAL_IS_PRIMITIVE(jsdval->val); 1.115 +} 1.116 + 1.117 +bool 1.118 +jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval) 1.119 +{ 1.120 + AutoSafeJSContext cx; // NB: Actually unused. 1.121 + return !JSVAL_IS_PRIMITIVE(jsdval->val) && 1.122 + JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(jsdval->val)); 1.123 +} 1.124 + 1.125 +bool 1.126 +jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) 1.127 +{ 1.128 + AutoSafeJSContext cx; 1.129 + JS::RootedFunction fun(cx); 1.130 + 1.131 + if(jsd_IsValueFunction(jsdc, jsdval)) 1.132 + { 1.133 + JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val)); 1.134 + AutoSaveExceptionState as(cx); 1.135 + bool ok = false; 1.136 + fun = JSD_GetValueFunction(jsdc, jsdval); 1.137 + if(fun) 1.138 + ok = JS_GetFunctionScript(cx, fun) ? false : true; 1.139 + MOZ_ASSERT(fun); 1.140 + return ok; 1.141 + } 1.142 + return !JSVAL_IS_PRIMITIVE(jsdval->val); 1.143 +} 1.144 + 1.145 +/***************************************************************************/ 1.146 + 1.147 +bool 1.148 +jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval) 1.149 +{ 1.150 + jsval val = jsdval->val; 1.151 + if(!JSVAL_IS_BOOLEAN(val)) 1.152 + return false; 1.153 + return JSVAL_TO_BOOLEAN(val); 1.154 +} 1.155 + 1.156 +int32_t 1.157 +jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) 1.158 +{ 1.159 + jsval val = jsdval->val; 1.160 + if(!JSVAL_IS_INT(val)) 1.161 + return 0; 1.162 + return JSVAL_TO_INT(val); 1.163 +} 1.164 + 1.165 +double 1.166 +jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) 1.167 +{ 1.168 + if(!JSVAL_IS_DOUBLE(jsdval->val)) 1.169 + return 0; 1.170 + return JSVAL_TO_DOUBLE(jsdval->val); 1.171 +} 1.172 + 1.173 +JSString* 1.174 +jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval) 1.175 +{ 1.176 + AutoSafeJSContext cx; 1.177 + JS::RootedValue stringval(cx); 1.178 + JS::RootedString string(cx); 1.179 + JS::RootedObject scopeObj(cx); 1.180 + 1.181 + if(jsdval->string) 1.182 + return jsdval->string; 1.183 + 1.184 + /* Reuse the string without copying or re-rooting it */ 1.185 + if(JSVAL_IS_STRING(jsdval->val)) { 1.186 + jsdval->string = JSVAL_TO_STRING(jsdval->val); 1.187 + return jsdval->string; 1.188 + } 1.189 + 1.190 + /* Objects call JS_ValueToString in their own compartment. */ 1.191 + scopeObj = !JSVAL_IS_PRIMITIVE(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob; 1.192 + { 1.193 + JSAutoCompartment ac(cx, scopeObj); 1.194 + AutoSaveExceptionState as(cx); 1.195 + JS::RootedValue v(cx, jsdval->val); 1.196 + string = JS::ToString(cx, v); 1.197 + } 1.198 + 1.199 + JSAutoCompartment ac2(cx, jsdc->glob); 1.200 + if(string) { 1.201 + stringval = STRING_TO_JSVAL(string); 1.202 + } 1.203 + if(!string || !JS_WrapValue(cx, &stringval)) { 1.204 + return nullptr; 1.205 + } 1.206 + 1.207 + jsdval->string = JSVAL_TO_STRING(stringval); 1.208 + if(!JS::AddNamedStringRoot(cx, &jsdval->string, "ValueString")) 1.209 + jsdval->string = nullptr; 1.210 + 1.211 + return jsdval->string; 1.212 +} 1.213 + 1.214 +JSString* 1.215 +jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval) 1.216 +{ 1.217 + AutoSafeJSContext cx; 1.218 + JS::RootedFunction fun(cx); 1.219 + 1.220 + if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval)) 1.221 + { 1.222 + JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(jsdval->val)); 1.223 + AutoSaveExceptionState as(cx); 1.224 + fun = JSD_GetValueFunction(jsdc, jsdval); 1.225 + if(!fun) 1.226 + return nullptr; 1.227 + jsdval->funName = JS_GetFunctionId(fun); 1.228 + 1.229 + /* For compatibility we return "anonymous", not an empty string here. */ 1.230 + if (!jsdval->funName) 1.231 + jsdval->funName = JS_GetAnonymousString(jsdc->jsrt); 1.232 + } 1.233 + return jsdval->funName; 1.234 +} 1.235 + 1.236 +/***************************************************************************/ 1.237 + 1.238 +/* 1.239 + * Create a new JSD value referring to a jsval. Copy string values into the 1.240 + * JSD compartment. Leave all other GCTHINGs in their native compartments 1.241 + * and access them through cross-compartment calls. 1.242 + */ 1.243 +JSDValue* 1.244 +jsd_NewValue(JSDContext* jsdc, jsval value) 1.245 +{ 1.246 + JS::RootedValue val(jsdc->jsrt, value); 1.247 + AutoSafeJSContext cx; 1.248 + JSDValue* jsdval; 1.249 + 1.250 + if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue)))) 1.251 + return nullptr; 1.252 + 1.253 + if(JSVAL_IS_GCTHING(val)) 1.254 + { 1.255 + bool ok; 1.256 + JSAutoCompartment ac(cx, jsdc->glob); 1.257 + 1.258 + ok = JS::AddNamedValueRoot(cx, &jsdval->val, "JSDValue"); 1.259 + if(ok && JSVAL_IS_STRING(val)) { 1.260 + if(!JS_WrapValue(cx, &val)) { 1.261 + ok = false; 1.262 + } 1.263 + } 1.264 + 1.265 + if(!ok) 1.266 + { 1.267 + free(jsdval); 1.268 + return nullptr; 1.269 + } 1.270 + } 1.271 + jsdval->val = val; 1.272 + jsdval->nref = 1; 1.273 + JS_INIT_CLIST(&jsdval->props); 1.274 + 1.275 + return jsdval; 1.276 +} 1.277 + 1.278 +void 1.279 +jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval) 1.280 +{ 1.281 + MOZ_ASSERT(jsdval->nref > 0); 1.282 + if(0 == --jsdval->nref) 1.283 + { 1.284 + jsd_RefreshValue(jsdc, jsdval); 1.285 + if(JSVAL_IS_GCTHING(jsdval->val)) 1.286 + { 1.287 + AutoSafeJSContext cx; 1.288 + JSAutoCompartment ac(cx, jsdc->glob); 1.289 + JS::RemoveValueRoot(cx, &jsdval->val); 1.290 + } 1.291 + free(jsdval); 1.292 + } 1.293 +} 1.294 + 1.295 +jsval 1.296 +jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval) 1.297 +{ 1.298 + AutoSafeJSContext cx; 1.299 + JS::RootedValue val(cx, jsdval->val); 1.300 + if (!val.isPrimitive()) { 1.301 + JS::RootedObject obj(cx, &val.toObject()); 1.302 + JSAutoCompartment ac(cx, obj); 1.303 + obj = JS_ObjectToOuterObject(cx, obj); 1.304 + if (!obj) 1.305 + { 1.306 + JS_ClearPendingException(cx); 1.307 + val = JSVAL_NULL; 1.308 + } 1.309 + else 1.310 + val = JS::ObjectValue(*obj); 1.311 + } 1.312 + 1.313 + return val; 1.314 +} 1.315 + 1.316 +static JSDProperty* _newProperty(JSDContext* jsdc, JS::HandleValue propId, 1.317 + JS::HandleValue propValue, JS::HandleValue propAlias, 1.318 + uint8_t propFlags, unsigned additionalFlags) 1.319 +{ 1.320 + JSDProperty* jsdprop; 1.321 + 1.322 + if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty)))) 1.323 + return nullptr; 1.324 + 1.325 + JS_INIT_CLIST(&jsdprop->links); 1.326 + jsdprop->nref = 1; 1.327 + jsdprop->flags = propFlags | additionalFlags; 1.328 + 1.329 + if(!(jsdprop->name = jsd_NewValue(jsdc, propId))) 1.330 + goto new_prop_fail; 1.331 + 1.332 + if(!(jsdprop->val = jsd_NewValue(jsdc, propValue))) 1.333 + goto new_prop_fail; 1.334 + 1.335 + if((jsdprop->flags & JSDPD_ALIAS) && 1.336 + !(jsdprop->alias = jsd_NewValue(jsdc, propAlias))) 1.337 + goto new_prop_fail; 1.338 + 1.339 + return jsdprop; 1.340 +new_prop_fail: 1.341 + jsd_DropProperty(jsdc, jsdprop); 1.342 + return nullptr; 1.343 +} 1.344 + 1.345 +static void _freeProps(JSDContext* jsdc, JSDValue* jsdval) 1.346 +{ 1.347 + JSDProperty* jsdprop; 1.348 + 1.349 + while(jsdprop = (JSDProperty*)jsdval->props.next, 1.350 + jsdprop != (JSDProperty*)&jsdval->props) 1.351 + { 1.352 + JS_REMOVE_AND_INIT_LINK(&jsdprop->links); 1.353 + jsd_DropProperty(jsdc, jsdprop); 1.354 + } 1.355 + MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props)); 1.356 + CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS); 1.357 +} 1.358 + 1.359 +static bool _buildProps(JSDContext* jsdc, JSDValue* jsdval) 1.360 +{ 1.361 + AutoSafeJSContext cx; 1.362 + JS::RootedObject obj(cx); 1.363 + JSPropertyDescArray pda; 1.364 + unsigned i; 1.365 + 1.366 + MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props)); 1.367 + MOZ_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))); 1.368 + MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val)); 1.369 + 1.370 + if(JSVAL_IS_PRIMITIVE(jsdval->val)) 1.371 + return false; 1.372 + 1.373 + obj = JSVAL_TO_OBJECT(jsdval->val); 1.374 + 1.375 + JSAutoCompartment ac(cx, obj); 1.376 + 1.377 + if(!JS_GetPropertyDescArray(cx, obj, &pda)) 1.378 + { 1.379 + return false; 1.380 + } 1.381 + 1.382 + JS::RootedValue propId(cx); 1.383 + JS::RootedValue propValue(cx); 1.384 + JS::RootedValue propAlias(cx); 1.385 + uint8_t propFlags; 1.386 + for(i = 0; i < pda.length; i++) 1.387 + { 1.388 + propId = pda.array[i].id; 1.389 + propValue = pda.array[i].value; 1.390 + propAlias = pda.array[i].alias; 1.391 + propFlags = pda.array[i].flags; 1.392 + JSDProperty* prop = _newProperty(jsdc, propId, propValue, propAlias, propFlags, 0); 1.393 + if(!prop) 1.394 + { 1.395 + _freeProps(jsdc, jsdval); 1.396 + break; 1.397 + } 1.398 + JS_APPEND_LINK(&prop->links, &jsdval->props); 1.399 + } 1.400 + JS_PutPropertyDescArray(cx, &pda); 1.401 + SET_BIT_FLAG(jsdval->flags, GOT_PROPS); 1.402 + return !JS_CLIST_IS_EMPTY(&jsdval->props); 1.403 +} 1.404 + 1.405 +#undef DROP_CLEAR_VALUE 1.406 +#define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = nullptr;} 1.407 + 1.408 +void 1.409 +jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval) 1.410 +{ 1.411 + AutoSafeJSContext cx; 1.412 + if(jsdval->string) 1.413 + { 1.414 + /* if the jsval is a string, then we didn't need to root the string */ 1.415 + if(!JSVAL_IS_STRING(jsdval->val)) 1.416 + { 1.417 + JSAutoCompartment ac(cx, jsdc->glob); 1.418 + JS::RemoveStringRoot(cx, &jsdval->string); 1.419 + } 1.420 + jsdval->string = nullptr; 1.421 + } 1.422 + 1.423 + jsdval->funName = nullptr; 1.424 + jsdval->className = nullptr; 1.425 + DROP_CLEAR_VALUE(jsdc, jsdval->proto); 1.426 + DROP_CLEAR_VALUE(jsdc, jsdval->parent); 1.427 + DROP_CLEAR_VALUE(jsdc, jsdval->ctor); 1.428 + _freeProps(jsdc, jsdval); 1.429 + jsdval->flags = 0; 1.430 +} 1.431 + 1.432 +/***************************************************************************/ 1.433 + 1.434 +unsigned 1.435 +jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval) 1.436 +{ 1.437 + JSDProperty* jsdprop; 1.438 + unsigned count = 0; 1.439 + 1.440 + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))) 1.441 + if(!_buildProps(jsdc, jsdval)) 1.442 + return 0; 1.443 + 1.444 + for(jsdprop = (JSDProperty*)jsdval->props.next; 1.445 + jsdprop != (JSDProperty*)&jsdval->props; 1.446 + jsdprop = (JSDProperty*)jsdprop->links.next) 1.447 + { 1.448 + count++; 1.449 + } 1.450 + return count; 1.451 +} 1.452 + 1.453 +JSDProperty* 1.454 +jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp) 1.455 +{ 1.456 + JSDProperty* jsdprop = *iterp; 1.457 + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))) 1.458 + { 1.459 + MOZ_ASSERT(!jsdprop); 1.460 + if(!_buildProps(jsdc, jsdval)) 1.461 + return nullptr; 1.462 + } 1.463 + 1.464 + if(!jsdprop) 1.465 + jsdprop = (JSDProperty*)jsdval->props.next; 1.466 + if(jsdprop == (JSDProperty*)&jsdval->props) 1.467 + return nullptr; 1.468 + *iterp = (JSDProperty*)jsdprop->links.next; 1.469 + 1.470 + MOZ_ASSERT(jsdprop); 1.471 + jsdprop->nref++; 1.472 + return jsdprop; 1.473 +} 1.474 + 1.475 +JSDProperty* 1.476 +jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr) 1.477 +{ 1.478 + JS::RootedString name(jsdc->jsrt, nameStr); 1.479 + AutoSafeJSContext cx; 1.480 + JSAutoCompartment acBase(cx, jsdc->glob); 1.481 + JSDProperty* jsdprop; 1.482 + JSDProperty* iter = nullptr; 1.483 + JS::RootedObject obj(cx); 1.484 + JS::RootedValue val(cx), nameval(cx); 1.485 + JS::RootedId nameid(cx); 1.486 + JS::RootedValue propId(cx); 1.487 + JS::RootedValue propValue(cx); 1.488 + JS::RootedValue propAlias(cx); 1.489 + uint8_t propFlags; 1.490 + 1.491 + if(!jsd_IsValueObject(jsdc, jsdval)) 1.492 + return nullptr; 1.493 + 1.494 + /* If we already have the prop, then return it */ 1.495 + while(nullptr != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter))) 1.496 + { 1.497 + JSString* propName = jsd_GetValueString(jsdc, jsdprop->name); 1.498 + if(propName) { 1.499 + int result; 1.500 + if (JS_CompareStrings(cx, propName, name, &result) && !result) 1.501 + return jsdprop; 1.502 + } 1.503 + JSD_DropProperty(jsdc, jsdprop); 1.504 + } 1.505 + /* Not found in property list, look it up explicitly */ 1.506 + 1.507 + nameval = STRING_TO_JSVAL(name); 1.508 + if(!JS_ValueToId(cx, nameval, &nameid)) 1.509 + return nullptr; 1.510 + 1.511 + if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) 1.512 + return nullptr; 1.513 + 1.514 + JS::Rooted<JSPropertyDescriptor> desc(cx); 1.515 + { 1.516 + JSAutoCompartment ac(cx, obj); 1.517 + JS::RootedId id(cx, nameid); 1.518 + 1.519 + if(!JS_WrapId(cx, &id)) 1.520 + return nullptr; 1.521 + if(!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) 1.522 + return nullptr; 1.523 + if(!desc.object()) 1.524 + return nullptr; 1.525 + 1.526 + JS_ClearPendingException(cx); 1.527 + 1.528 + if(!JS_GetPropertyById(cx, obj, id, &val)) 1.529 + { 1.530 + if (JS_IsExceptionPending(cx)) 1.531 + { 1.532 + if (!JS_GetPendingException(cx, &propValue)) 1.533 + { 1.534 + return nullptr; 1.535 + } 1.536 + propFlags = JSPD_EXCEPTION; 1.537 + } 1.538 + else 1.539 + { 1.540 + propFlags = JSPD_ERROR; 1.541 + propValue = JSVAL_VOID; 1.542 + } 1.543 + } 1.544 + else 1.545 + { 1.546 + propValue = val; 1.547 + } 1.548 + } 1.549 + 1.550 + if (!JS_IdToValue(cx, nameid, &propId)) 1.551 + return nullptr; 1.552 + 1.553 + propAlias = JSVAL_NULL; 1.554 + propFlags |= desc.isEnumerable() ? JSPD_ENUMERATE : 0 1.555 + | desc.isReadonly() ? JSPD_READONLY : 0 1.556 + | desc.isPermanent() ? JSPD_PERMANENT : 0; 1.557 + 1.558 + return _newProperty(jsdc, propId, propValue, propAlias, propFlags, JSDPD_HINTED); 1.559 +} 1.560 + 1.561 +/* 1.562 + * Retrieve a JSFunction* from a JSDValue*. This differs from 1.563 + * JS_ValueToFunction by fully unwrapping the object first. 1.564 + */ 1.565 +JSFunction* 1.566 +jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval) 1.567 +{ 1.568 + AutoSafeJSContext cx; 1.569 + 1.570 + JS::RootedObject obj(cx); 1.571 + JS::RootedFunction fun(cx); 1.572 + 1.573 + if (JSVAL_IS_PRIMITIVE(jsdval->val)) 1.574 + return nullptr; 1.575 + 1.576 + obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val)); 1.577 + JSAutoCompartment ac(cx, obj); 1.578 + JS::RootedValue funval(cx, JS::ObjectValue(*obj)); 1.579 + fun = JS_ValueToFunction(cx, funval); 1.580 + 1.581 + return fun; 1.582 +} 1.583 + 1.584 +JSDValue* 1.585 +jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval) 1.586 +{ 1.587 + AutoSafeJSContext cx; 1.588 + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO))) 1.589 + { 1.590 + JS::RootedObject obj(cx); 1.591 + JS::RootedObject proto(cx); 1.592 + MOZ_ASSERT(!jsdval->proto); 1.593 + SET_BIT_FLAG(jsdval->flags, GOT_PROTO); 1.594 + if(JSVAL_IS_PRIMITIVE(jsdval->val)) 1.595 + return nullptr; 1.596 + obj = JSVAL_TO_OBJECT(jsdval->val); 1.597 + if(!JS_GetPrototype(cx, obj, &proto)) 1.598 + return nullptr; 1.599 + if(!proto) 1.600 + return nullptr; 1.601 + jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto)); 1.602 + } 1.603 + if(jsdval->proto) 1.604 + jsdval->proto->nref++; 1.605 + return jsdval->proto; 1.606 +} 1.607 + 1.608 +JSDValue* 1.609 +jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval) 1.610 +{ 1.611 + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT))) 1.612 + { 1.613 + AutoSafeJSContext cx; 1.614 + JS::RootedObject obj(cx); 1.615 + JS::RootedObject parent(cx); 1.616 + MOZ_ASSERT(!jsdval->parent); 1.617 + SET_BIT_FLAG(jsdval->flags, GOT_PARENT); 1.618 + if(JSVAL_IS_PRIMITIVE(jsdval->val)) 1.619 + return nullptr; 1.620 + obj = JSVAL_TO_OBJECT(jsdval->val); 1.621 + { 1.622 + JSAutoCompartment ac(cx, obj); 1.623 + parent = JS_GetParentOrScopeChain(cx, obj); 1.624 + } 1.625 + if(!parent) 1.626 + return nullptr; 1.627 + jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent)); 1.628 + } 1.629 + if(jsdval->parent) 1.630 + jsdval->parent->nref++; 1.631 + return jsdval->parent; 1.632 +} 1.633 + 1.634 +JSDValue* 1.635 +jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval) 1.636 +{ 1.637 + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR))) 1.638 + { 1.639 + AutoSafeJSContext cx; 1.640 + JS::RootedObject obj(cx); 1.641 + JS::RootedObject proto(cx); 1.642 + JS::RootedObject ctor(cx); 1.643 + MOZ_ASSERT(!jsdval->ctor); 1.644 + SET_BIT_FLAG(jsdval->flags, GOT_CTOR); 1.645 + if(JSVAL_IS_PRIMITIVE(jsdval->val)) 1.646 + return nullptr; 1.647 + obj = JSVAL_TO_OBJECT(jsdval->val); 1.648 + if(!JS_GetPrototype(cx, obj, &proto)) 1.649 + return nullptr; 1.650 + if(!proto) 1.651 + return nullptr; 1.652 + { 1.653 + JSAutoCompartment ac(cx, obj); 1.654 + ctor = JS_GetConstructor(cx, proto); 1.655 + } 1.656 + if(!ctor) 1.657 + return nullptr; 1.658 + jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor)); 1.659 + } 1.660 + if(jsdval->ctor) 1.661 + jsdval->ctor->nref++; 1.662 + return jsdval->ctor; 1.663 +} 1.664 + 1.665 +const char* 1.666 +jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval) 1.667 +{ 1.668 + jsval val = jsdval->val; 1.669 + if(!jsdval->className && !JSVAL_IS_PRIMITIVE(val)) 1.670 + { 1.671 + JS::RootedObject obj(jsdc->jsrt, JSVAL_TO_OBJECT(val)); 1.672 + AutoSafeJSContext cx; 1.673 + JSAutoCompartment ac(cx, obj); 1.674 + jsdval->className = JS_GetDebugClassName(obj); 1.675 + } 1.676 + return jsdval->className; 1.677 +} 1.678 + 1.679 +JSDScript* 1.680 +jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval) 1.681 +{ 1.682 + AutoSafeJSContext cx; 1.683 + JS::RootedValue val(cx, jsdval->val); 1.684 + JS::RootedScript script(cx); 1.685 + JSDScript* jsdscript; 1.686 + 1.687 + if (!jsd_IsValueFunction(jsdc, jsdval)) 1.688 + return nullptr; 1.689 + 1.690 + { 1.691 + JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(val)); 1.692 + AutoSaveExceptionState as(cx); 1.693 + JS::RootedFunction fun(cx, JSD_GetValueFunction(jsdc, jsdval)); 1.694 + if (fun) 1.695 + script = JS_GetFunctionScript(cx, fun); 1.696 + } 1.697 + 1.698 + if (!script) 1.699 + return nullptr; 1.700 + 1.701 + JSD_LOCK_SCRIPTS(jsdc); 1.702 + jsdscript = jsd_FindJSDScript(jsdc, script); 1.703 + JSD_UNLOCK_SCRIPTS(jsdc); 1.704 + return jsdscript; 1.705 +} 1.706 + 1.707 + 1.708 +/***************************************************************************/ 1.709 +/***************************************************************************/ 1.710 + 1.711 +JSDValue* 1.712 +jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop) 1.713 +{ 1.714 + jsdprop->name->nref++; 1.715 + return jsdprop->name; 1.716 +} 1.717 + 1.718 +JSDValue* 1.719 +jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop) 1.720 +{ 1.721 + jsdprop->val->nref++; 1.722 + return jsdprop->val; 1.723 +} 1.724 + 1.725 +JSDValue* 1.726 +jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop) 1.727 +{ 1.728 + if(jsdprop->alias) 1.729 + jsdprop->alias->nref++; 1.730 + return jsdprop->alias; 1.731 +} 1.732 + 1.733 +unsigned 1.734 +jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop) 1.735 +{ 1.736 + return jsdprop->flags; 1.737 +} 1.738 + 1.739 +void 1.740 +jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop) 1.741 +{ 1.742 + MOZ_ASSERT(jsdprop->nref > 0); 1.743 + if(0 == --jsdprop->nref) 1.744 + { 1.745 + MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links)); 1.746 + DROP_CLEAR_VALUE(jsdc, jsdprop->val); 1.747 + DROP_CLEAR_VALUE(jsdc, jsdprop->name); 1.748 + DROP_CLEAR_VALUE(jsdc, jsdprop->alias); 1.749 + free(jsdprop); 1.750 + } 1.751 +}