mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
f427cf7043
This is unnecessary now that object jsids no longer exist. Both string and symbol jsids point only to GC things in the atoms compartment, which are safe to pass to any compartment without wrapping. --HG-- extra : rebase_source : 82c21e8474df05b1bb42c14d872c981205bbe879
747 lines
19 KiB
C++
747 lines
19 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* JavaScript Debugging support - Value and Property support
|
|
*/
|
|
|
|
#include "jsd.h"
|
|
#include "jsapi.h"
|
|
#include "jsfriendapi.h"
|
|
#include "jswrapper.h"
|
|
#include "nsCxPusher.h"
|
|
|
|
using mozilla::AutoSafeJSContext;
|
|
|
|
#ifdef DEBUG
|
|
void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
|
|
{
|
|
MOZ_ASSERT(jsdval);
|
|
MOZ_ASSERT(jsdval->nref > 0);
|
|
if(!JS_CLIST_IS_EMPTY(&jsdval->props))
|
|
{
|
|
MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS));
|
|
MOZ_ASSERT(!jsdval->val.isPrimitive());
|
|
}
|
|
|
|
if(jsdval->proto)
|
|
{
|
|
MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO));
|
|
MOZ_ASSERT(jsdval->proto->nref > 0);
|
|
}
|
|
if(jsdval->parent)
|
|
{
|
|
MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT));
|
|
MOZ_ASSERT(jsdval->parent->nref > 0);
|
|
}
|
|
if(jsdval->ctor)
|
|
{
|
|
MOZ_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR));
|
|
MOZ_ASSERT(jsdval->ctor->nref > 0);
|
|
}
|
|
}
|
|
|
|
void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop)
|
|
{
|
|
MOZ_ASSERT(jsdprop);
|
|
MOZ_ASSERT(jsdprop->name);
|
|
MOZ_ASSERT(jsdprop->name->nref > 0);
|
|
MOZ_ASSERT(jsdprop->val);
|
|
MOZ_ASSERT(jsdprop->val->nref > 0);
|
|
if(jsdprop->alias)
|
|
MOZ_ASSERT(jsdprop->alias->nref > 0);
|
|
}
|
|
#endif
|
|
|
|
|
|
bool
|
|
jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return !jsdval->val.isPrimitive() || jsdval->val.isNull();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isNumber();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isInt32();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isDouble();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isString();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isBoolean();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isNull();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isUndefined();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
return jsdval->val.isPrimitive();
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx; // NB: Actually unused.
|
|
return !jsdval->val.isPrimitive() &&
|
|
JS_ObjectIsCallable(cx, jsdval->val.toObjectOrNull());
|
|
}
|
|
|
|
bool
|
|
jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedFunction fun(cx);
|
|
|
|
if(jsd_IsValueFunction(jsdc, jsdval))
|
|
{
|
|
JSAutoCompartment ac(cx, jsdval->val.toObjectOrNull());
|
|
AutoSaveExceptionState as(cx);
|
|
bool ok = false;
|
|
fun = JSD_GetValueFunction(jsdc, jsdval);
|
|
if(fun)
|
|
ok = JS_GetFunctionScript(cx, fun) ? false : true;
|
|
MOZ_ASSERT(fun);
|
|
return ok;
|
|
}
|
|
return !jsdval->val.isPrimitive();
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
bool
|
|
jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
jsval val = jsdval->val;
|
|
if(!val.isBoolean())
|
|
return false;
|
|
return val.toBoolean();
|
|
}
|
|
|
|
int32_t
|
|
jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
jsval val = jsdval->val;
|
|
if(!val.isInt32())
|
|
return 0;
|
|
return val.toInt32();
|
|
}
|
|
|
|
double
|
|
jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
if(!jsdval->val.isDouble())
|
|
return 0;
|
|
return jsdval->val.toDouble();
|
|
}
|
|
|
|
JSString*
|
|
jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedValue stringval(cx);
|
|
JS::RootedString string(cx);
|
|
JS::RootedObject scopeObj(cx);
|
|
|
|
if(jsdval->string)
|
|
return jsdval->string;
|
|
|
|
/* Reuse the string without copying or re-rooting it */
|
|
if(jsdval->val.isString()) {
|
|
jsdval->string = jsdval->val.toString();
|
|
return jsdval->string;
|
|
}
|
|
|
|
/* Objects call JS_ValueToString in their own compartment. */
|
|
scopeObj = !jsdval->val.isPrimitive() ? jsdval->val.toObjectOrNull() : jsdc->glob;
|
|
{
|
|
JSAutoCompartment ac(cx, scopeObj);
|
|
AutoSaveExceptionState as(cx);
|
|
JS::RootedValue v(cx, jsdval->val);
|
|
string = JS::ToString(cx, v);
|
|
}
|
|
|
|
JSAutoCompartment ac2(cx, jsdc->glob);
|
|
if(string) {
|
|
stringval = STRING_TO_JSVAL(string);
|
|
}
|
|
if(!string || !JS_WrapValue(cx, &stringval)) {
|
|
return nullptr;
|
|
}
|
|
|
|
jsdval->string = stringval.toString();
|
|
if(!JS::AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
|
|
jsdval->string = nullptr;
|
|
|
|
return jsdval->string;
|
|
}
|
|
|
|
JSString*
|
|
jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedFunction fun(cx);
|
|
|
|
if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
|
|
{
|
|
JSAutoCompartment ac(cx, jsdval->val.toObjectOrNull());
|
|
AutoSaveExceptionState as(cx);
|
|
fun = JSD_GetValueFunction(jsdc, jsdval);
|
|
if(!fun)
|
|
return nullptr;
|
|
jsdval->funName = JS_GetFunctionId(fun);
|
|
|
|
/* For compatibility we return "anonymous", not an empty string here. */
|
|
if (!jsdval->funName)
|
|
jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
|
|
}
|
|
return jsdval->funName;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
* Create a new JSD value referring to a jsval. Copy string values into the
|
|
* JSD compartment. Leave all other GCTHINGs in their native compartments
|
|
* and access them through cross-compartment calls.
|
|
*/
|
|
JSDValue*
|
|
jsd_NewValue(JSDContext* jsdc, jsval value)
|
|
{
|
|
JS::RootedValue val(jsdc->jsrt, value);
|
|
AutoSafeJSContext cx;
|
|
JSDValue* jsdval;
|
|
|
|
if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
|
|
return nullptr;
|
|
|
|
if(val.isGCThing())
|
|
{
|
|
bool ok;
|
|
JSAutoCompartment ac(cx, jsdc->glob);
|
|
|
|
ok = JS::AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
|
|
if(ok && val.isString()) {
|
|
if(!JS_WrapValue(cx, &val)) {
|
|
ok = false;
|
|
}
|
|
}
|
|
|
|
if(!ok)
|
|
{
|
|
free(jsdval);
|
|
return nullptr;
|
|
}
|
|
}
|
|
jsdval->val = val;
|
|
jsdval->nref = 1;
|
|
JS_INIT_CLIST(&jsdval->props);
|
|
|
|
return jsdval;
|
|
}
|
|
|
|
void
|
|
jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
MOZ_ASSERT(jsdval->nref > 0);
|
|
if(0 == --jsdval->nref)
|
|
{
|
|
jsd_RefreshValue(jsdc, jsdval);
|
|
if(jsdval->val.isGCThing())
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JSAutoCompartment ac(cx, jsdc->glob);
|
|
JS::RemoveValueRoot(cx, &jsdval->val);
|
|
}
|
|
free(jsdval);
|
|
}
|
|
}
|
|
|
|
jsval
|
|
jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedValue val(cx, jsdval->val);
|
|
if (!val.isPrimitive()) {
|
|
JS::RootedObject obj(cx, &val.toObject());
|
|
JSAutoCompartment ac(cx, obj);
|
|
obj = JS_ObjectToOuterObject(cx, obj);
|
|
if (!obj)
|
|
{
|
|
JS_ClearPendingException(cx);
|
|
val = JSVAL_NULL;
|
|
}
|
|
else
|
|
val = JS::ObjectValue(*obj);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static JSDProperty* _newProperty(JSDContext* jsdc, JS::HandleValue propId,
|
|
JS::HandleValue propValue, JS::HandleValue propAlias,
|
|
uint8_t propFlags, unsigned additionalFlags)
|
|
{
|
|
JSDProperty* jsdprop;
|
|
|
|
if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
|
|
return nullptr;
|
|
|
|
JS_INIT_CLIST(&jsdprop->links);
|
|
jsdprop->nref = 1;
|
|
jsdprop->flags = propFlags | additionalFlags;
|
|
|
|
if(!(jsdprop->name = jsd_NewValue(jsdc, propId)))
|
|
goto new_prop_fail;
|
|
|
|
if(!(jsdprop->val = jsd_NewValue(jsdc, propValue)))
|
|
goto new_prop_fail;
|
|
|
|
if((jsdprop->flags & JSDPD_ALIAS) &&
|
|
!(jsdprop->alias = jsd_NewValue(jsdc, propAlias)))
|
|
goto new_prop_fail;
|
|
|
|
return jsdprop;
|
|
new_prop_fail:
|
|
jsd_DropProperty(jsdc, jsdprop);
|
|
return nullptr;
|
|
}
|
|
|
|
static void _freeProps(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
JSDProperty* jsdprop;
|
|
|
|
while(jsdprop = (JSDProperty*)jsdval->props.next,
|
|
jsdprop != (JSDProperty*)&jsdval->props)
|
|
{
|
|
JS_REMOVE_AND_INIT_LINK(&jsdprop->links);
|
|
jsd_DropProperty(jsdc, jsdprop);
|
|
}
|
|
MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
|
|
CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS);
|
|
}
|
|
|
|
static bool _buildProps(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedObject obj(cx);
|
|
JSPropertyDescArray pda;
|
|
unsigned i;
|
|
|
|
MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
|
|
MOZ_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
|
|
MOZ_ASSERT(!jsdval->val.isPrimitive());
|
|
|
|
if(jsdval->val.isPrimitive())
|
|
return false;
|
|
|
|
obj = jsdval->val.toObjectOrNull();
|
|
|
|
JSAutoCompartment ac(cx, obj);
|
|
|
|
if(!JS_GetPropertyDescArray(cx, obj, &pda))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
JS::RootedValue propId(cx);
|
|
JS::RootedValue propValue(cx);
|
|
JS::RootedValue propAlias(cx);
|
|
uint8_t propFlags;
|
|
for(i = 0; i < pda.length; i++)
|
|
{
|
|
propId = pda.array[i].id;
|
|
propValue = pda.array[i].value;
|
|
propAlias = pda.array[i].alias;
|
|
propFlags = pda.array[i].flags;
|
|
JSDProperty* prop = _newProperty(jsdc, propId, propValue, propAlias, propFlags, 0);
|
|
if(!prop)
|
|
{
|
|
_freeProps(jsdc, jsdval);
|
|
break;
|
|
}
|
|
JS_APPEND_LINK(&prop->links, &jsdval->props);
|
|
}
|
|
JS_PutPropertyDescArray(cx, &pda);
|
|
SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
|
|
return !JS_CLIST_IS_EMPTY(&jsdval->props);
|
|
}
|
|
|
|
#undef DROP_CLEAR_VALUE
|
|
#define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = nullptr;}
|
|
|
|
void
|
|
jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
if(jsdval->string)
|
|
{
|
|
/* if the jsval is a string, then we didn't need to root the string */
|
|
if(!jsdval->val.isString())
|
|
{
|
|
JSAutoCompartment ac(cx, jsdc->glob);
|
|
JS::RemoveStringRoot(cx, &jsdval->string);
|
|
}
|
|
jsdval->string = nullptr;
|
|
}
|
|
|
|
jsdval->funName = nullptr;
|
|
jsdval->className = nullptr;
|
|
DROP_CLEAR_VALUE(jsdc, jsdval->proto);
|
|
DROP_CLEAR_VALUE(jsdc, jsdval->parent);
|
|
DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
|
|
_freeProps(jsdc, jsdval);
|
|
jsdval->flags = 0;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
unsigned
|
|
jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
JSDProperty* jsdprop;
|
|
unsigned count = 0;
|
|
|
|
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
|
|
if(!_buildProps(jsdc, jsdval))
|
|
return 0;
|
|
|
|
for(jsdprop = (JSDProperty*)jsdval->props.next;
|
|
jsdprop != (JSDProperty*)&jsdval->props;
|
|
jsdprop = (JSDProperty*)jsdprop->links.next)
|
|
{
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
JSDProperty*
|
|
jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp)
|
|
{
|
|
JSDProperty* jsdprop = *iterp;
|
|
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
|
|
{
|
|
MOZ_ASSERT(!jsdprop);
|
|
if(!_buildProps(jsdc, jsdval))
|
|
return nullptr;
|
|
}
|
|
|
|
if(!jsdprop)
|
|
jsdprop = (JSDProperty*)jsdval->props.next;
|
|
if(jsdprop == (JSDProperty*)&jsdval->props)
|
|
return nullptr;
|
|
*iterp = (JSDProperty*)jsdprop->links.next;
|
|
|
|
MOZ_ASSERT(jsdprop);
|
|
jsdprop->nref++;
|
|
return jsdprop;
|
|
}
|
|
|
|
JSDProperty*
|
|
jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr)
|
|
{
|
|
JS::RootedString name(jsdc->jsrt, nameStr);
|
|
AutoSafeJSContext cx;
|
|
JSAutoCompartment acBase(cx, jsdc->glob);
|
|
JSDProperty* jsdprop;
|
|
JSDProperty* iter = nullptr;
|
|
JS::RootedObject obj(cx);
|
|
JS::RootedValue val(cx), nameval(cx);
|
|
JS::RootedId nameid(cx);
|
|
JS::RootedValue propId(cx);
|
|
JS::RootedValue propValue(cx);
|
|
JS::RootedValue propAlias(cx);
|
|
uint8_t propFlags;
|
|
|
|
if(!jsd_IsValueObject(jsdc, jsdval))
|
|
return nullptr;
|
|
|
|
/* If we already have the prop, then return it */
|
|
while(nullptr != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
|
|
{
|
|
JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
|
|
if(propName) {
|
|
int result;
|
|
if (JS_CompareStrings(cx, propName, name, &result) && !result)
|
|
return jsdprop;
|
|
}
|
|
JSD_DropProperty(jsdc, jsdprop);
|
|
}
|
|
/* Not found in property list, look it up explicitly */
|
|
|
|
nameval = STRING_TO_JSVAL(name);
|
|
if(!JS_ValueToId(cx, nameval, &nameid))
|
|
return nullptr;
|
|
|
|
if(!(obj = jsdval->val.toObjectOrNull()))
|
|
return nullptr;
|
|
|
|
JS::Rooted<JSPropertyDescriptor> desc(cx);
|
|
{
|
|
JSAutoCompartment ac(cx, obj);
|
|
JS::RootedId id(cx, nameid);
|
|
|
|
if(!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc))
|
|
return nullptr;
|
|
if(!desc.object())
|
|
return nullptr;
|
|
|
|
JS_ClearPendingException(cx);
|
|
|
|
if(!JS_GetPropertyById(cx, obj, id, &val))
|
|
{
|
|
if (JS_IsExceptionPending(cx))
|
|
{
|
|
if (!JS_GetPendingException(cx, &propValue))
|
|
{
|
|
return nullptr;
|
|
}
|
|
propFlags = JSPD_EXCEPTION;
|
|
}
|
|
else
|
|
{
|
|
propFlags = JSPD_ERROR;
|
|
propValue = JSVAL_VOID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
propValue = val;
|
|
}
|
|
}
|
|
|
|
if (!JS_IdToValue(cx, nameid, &propId))
|
|
return nullptr;
|
|
|
|
propAlias = JSVAL_NULL;
|
|
propFlags |= desc.isEnumerable() ? JSPD_ENUMERATE : 0
|
|
| desc.isReadonly() ? JSPD_READONLY : 0
|
|
| desc.isPermanent() ? JSPD_PERMANENT : 0;
|
|
|
|
return _newProperty(jsdc, propId, propValue, propAlias, propFlags, JSDPD_HINTED);
|
|
}
|
|
|
|
/*
|
|
* Retrieve a JSFunction* from a JSDValue*. This differs from
|
|
* JS_ValueToFunction by fully unwrapping the object first.
|
|
*/
|
|
JSFunction*
|
|
jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
|
|
JS::RootedObject obj(cx);
|
|
JS::RootedFunction fun(cx);
|
|
|
|
if (jsdval->val.isPrimitive())
|
|
return nullptr;
|
|
|
|
obj = js::UncheckedUnwrap(jsdval->val.toObjectOrNull());
|
|
JSAutoCompartment ac(cx, obj);
|
|
JS::RootedValue funval(cx, JS::ObjectValue(*obj));
|
|
fun = JS_ValueToFunction(cx, funval);
|
|
|
|
return fun;
|
|
}
|
|
|
|
JSDValue*
|
|
jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
|
|
{
|
|
JS::RootedObject obj(cx);
|
|
JS::RootedObject proto(cx);
|
|
MOZ_ASSERT(!jsdval->proto);
|
|
SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
|
|
if(jsdval->val.isPrimitive())
|
|
return nullptr;
|
|
obj = jsdval->val.toObjectOrNull();
|
|
if(!JS_GetPrototype(cx, obj, &proto))
|
|
return nullptr;
|
|
if(!proto)
|
|
return nullptr;
|
|
jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
|
|
}
|
|
if(jsdval->proto)
|
|
jsdval->proto->nref++;
|
|
return jsdval->proto;
|
|
}
|
|
|
|
JSDValue*
|
|
jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedObject obj(cx);
|
|
JS::RootedObject parent(cx);
|
|
MOZ_ASSERT(!jsdval->parent);
|
|
SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
|
|
if(jsdval->val.isPrimitive())
|
|
return nullptr;
|
|
obj = jsdval->val.toObjectOrNull();
|
|
{
|
|
JSAutoCompartment ac(cx, obj);
|
|
parent = JS_GetParentOrScopeChain(cx, obj);
|
|
}
|
|
if(!parent)
|
|
return nullptr;
|
|
jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
|
|
}
|
|
if(jsdval->parent)
|
|
jsdval->parent->nref++;
|
|
return jsdval->parent;
|
|
}
|
|
|
|
JSDValue*
|
|
jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedObject obj(cx);
|
|
JS::RootedObject proto(cx);
|
|
JS::RootedObject ctor(cx);
|
|
MOZ_ASSERT(!jsdval->ctor);
|
|
SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
|
|
if(jsdval->val.isPrimitive())
|
|
return nullptr;
|
|
obj = jsdval->val.toObjectOrNull();
|
|
if(!JS_GetPrototype(cx, obj, &proto))
|
|
return nullptr;
|
|
if(!proto)
|
|
return nullptr;
|
|
{
|
|
JSAutoCompartment ac(cx, obj);
|
|
ctor = JS_GetConstructor(cx, proto);
|
|
}
|
|
if(!ctor)
|
|
return nullptr;
|
|
jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
|
|
}
|
|
if(jsdval->ctor)
|
|
jsdval->ctor->nref++;
|
|
return jsdval->ctor;
|
|
}
|
|
|
|
const char*
|
|
jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
jsval val = jsdval->val;
|
|
if(!jsdval->className && !val.isPrimitive())
|
|
{
|
|
JS::RootedObject obj(jsdc->jsrt, val.toObjectOrNull());
|
|
AutoSafeJSContext cx;
|
|
JSAutoCompartment ac(cx, obj);
|
|
jsdval->className = JS_GetDebugClassName(obj);
|
|
}
|
|
return jsdval->className;
|
|
}
|
|
|
|
JSDScript*
|
|
jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
|
|
{
|
|
AutoSafeJSContext cx;
|
|
JS::RootedValue val(cx, jsdval->val);
|
|
JS::RootedScript script(cx);
|
|
JSDScript* jsdscript;
|
|
|
|
if (!jsd_IsValueFunction(jsdc, jsdval))
|
|
return nullptr;
|
|
|
|
{
|
|
JSAutoCompartment ac(cx, val.toObjectOrNull());
|
|
AutoSaveExceptionState as(cx);
|
|
JS::RootedFunction fun(cx, JSD_GetValueFunction(jsdc, jsdval));
|
|
if (fun)
|
|
script = JS_GetFunctionScript(cx, fun);
|
|
}
|
|
|
|
if (!script)
|
|
return nullptr;
|
|
|
|
JSD_LOCK_SCRIPTS(jsdc);
|
|
jsdscript = jsd_FindJSDScript(jsdc, script);
|
|
JSD_UNLOCK_SCRIPTS(jsdc);
|
|
return jsdscript;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/***************************************************************************/
|
|
|
|
JSDValue*
|
|
jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop)
|
|
{
|
|
jsdprop->name->nref++;
|
|
return jsdprop->name;
|
|
}
|
|
|
|
JSDValue*
|
|
jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop)
|
|
{
|
|
jsdprop->val->nref++;
|
|
return jsdprop->val;
|
|
}
|
|
|
|
JSDValue*
|
|
jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop)
|
|
{
|
|
if(jsdprop->alias)
|
|
jsdprop->alias->nref++;
|
|
return jsdprop->alias;
|
|
}
|
|
|
|
unsigned
|
|
jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop)
|
|
{
|
|
return jsdprop->flags;
|
|
}
|
|
|
|
void
|
|
jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop)
|
|
{
|
|
MOZ_ASSERT(jsdprop->nref > 0);
|
|
if(0 == --jsdprop->nref)
|
|
{
|
|
MOZ_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links));
|
|
DROP_CLEAR_VALUE(jsdc, jsdprop->val);
|
|
DROP_CLEAR_VALUE(jsdc, jsdprop->name);
|
|
DROP_CLEAR_VALUE(jsdc, jsdprop->alias);
|
|
free(jsdprop);
|
|
}
|
|
}
|