示例#1
0
JSDScript*
jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    jsval val = jsdval->val;
    JSFunction* fun;
    JSExceptionState* exceptionState;
    JSScript* script = NULL;
    JSDScript* jsdscript;

    if (!jsd_IsValueFunction(jsdc, jsdval))
        return NULL;

    JS_BeginRequest(cx);
    exceptionState = JS_SaveExceptionState(cx);
    fun = JS_ValueToFunction(cx, val);
    JS_RestoreExceptionState(cx, exceptionState);
    if (fun)
        script = JS_GetFunctionScript(cx, fun);
    JS_EndRequest(cx);

    if (!script)
        return NULL;

    JSD_LOCK_SCRIPTS(jsdc);
    jsdscript = jsd_FindJSDScript(jsdc, script);
    JSD_UNLOCK_SCRIPTS(jsdc);
    return jsdscript;
}
示例#2
0
文件: jsexn.cpp 项目: ahadzi/celtx
static JSString *
ValueToShortSource(JSContext *cx, jsval v)
{
    JSString *str;

    /* Avoid toSource bloat and fallibility for object types. */
    if (JSVAL_IS_PRIMITIVE(v)) {
        str = js_ValueToSource(cx, v);
    } else if (VALUE_IS_FUNCTION(cx, v)) {
        /*
         * XXX Avoid function decompilation bloat for now.
         */
        str = JS_GetFunctionId(JS_ValueToFunction(cx, v));
        if (!str && !(str = js_ValueToSource(cx, v))) {
            /*
             * Continue to soldier on if the function couldn't be
             * converted into a string.
             */
            JS_ClearPendingException(cx);
            str = JS_NewStringCopyZ(cx, "[unknown function]");
        }
    } else {
        /*
         * XXX Avoid toString on objects, it takes too long and uses too much
         * memory, for too many classes (see Mozilla bug 166743).
         */
        char buf[100];
        JS_snprintf(buf, sizeof buf, "[object %s]",
                    OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v))->name);
        str = JS_NewStringCopyZ(cx, buf);
    }
    return str;
}
示例#3
0
//
// constructor for the input object
//
static JSBool jsInput( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval )
{
	*rval = JSVAL_FALSE ;
	JSString *sDevice ;
	JSFunction *function ;
	if (( 0 != (cx->fp->flags & JSFRAME_CONSTRUCTING) )
	    && 
	    (2 == argc )
	    &&
	    (0 != (sDevice=JSVAL_TO_STRING(argv[0])))
	    &&
	    (0 != (function=JS_ValueToFunction(cx,argv[1])))){
		char const *fileName = JS_GetStringBytes(sDevice);
		jsInputPoll_t *poller = new jsInputPoll_t(fileName);
		if( poller && poller->isOpen() ){
			JSObject *retObj = JS_NewObject( cx, &jsInputClass_, inputProto, obj );
			*rval = OBJECT_TO_JSVAL(retObj);
			JS_SetPrivate( cx, retObj, poller );
			poller->handlerObj_ = OBJECT_TO_JSVAL(obj);
			poller->handlerCode_ = OBJECT_TO_JSVAL(argv[1]);
		}
		else
			JS_ReportError(cx, "Error opening %s\n", fileName );

	}
	else
		JS_ReportError(cx, "Usage: new input( '/dev/input/event0' )\n" );

	return JS_TRUE;
}
示例#4
0
文件: stack.c 项目: Katyunechka/gjs
/* Mimick the behaviour exposed by standard Error objects
   (http://mxr.mozilla.org/mozilla-central/source/js/src/jsexn.cpp#554)
*/
static char*
jsvalue_to_string(JSContext* cx, jsval val, gboolean* is_string)
{
    char* value = NULL;
    JSString* value_str = NULL;

    if (JSVAL_IS_PRIMITIVE(val)) {
      value_str = JS_ValueToSource(cx, val);
    } else {
      JSObject *obj = JSVAL_TO_OBJECT(val);

      if (JS_ObjectIsFunction(cx, obj)) {
	JSFunction *fn = JS_ValueToFunction(cx, val);
	value_str = JS_GetFunctionId(fn);

	if (!value_str)
	  value = g_strdup("[unknown function]");
      } else {
	value = g_strdup_printf("[object %s]", JS_GetClass(cx, obj)->name);
      }
    }

    if (!value && value_str)
      value = gjs_value_debug_string(cx, val);

    if (is_string)
        *is_string = JSVAL_IS_STRING(val);

    return value;
}
static JSBool
XPC_XOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                        jsval *rval)
{
  JSObject *wrappedObj, *outerObj = obj;

  // Allow 'this' to be either an XOW, in which case we unwrap it.
  // We disallow invalid XOWs that have no wrapped object. Otherwise,
  // if it isn't an XOW, then pass it through as-is.

  wrappedObj = GetWrapper(obj);
  if (wrappedObj) {
    wrappedObj = GetWrappedObject(cx, wrappedObj);
    if (!wrappedObj) {
      return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
    }
  } else {
    wrappedObj = obj;
  }

  JSObject *funObj = JSVAL_TO_OBJECT(argv[-2]);
  jsval funToCall;
  if (!JS_GetReservedSlot(cx, funObj, XPCWrapper::eWrappedFunctionSlot,
                          &funToCall)) {
    return JS_FALSE;
  }

  JSFunction *fun = JS_ValueToFunction(cx, funToCall);
  if (!fun) {
    return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
  }

  XPCCallContext ccx(JS_CALLER, cx);
  if (!ccx.IsValid()) {
    return ThrowException(NS_ERROR_FAILURE, cx);
  }

  nsresult rv = CanAccessWrapper(cx, JSVAL_TO_OBJECT(funToCall), nsnull);
  if (NS_FAILED(rv) && rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
    return ThrowException(rv, cx);
  }

#ifdef DEBUG
  JSNative native = JS_GetFunctionNative(cx, fun);
  NS_ASSERTION(native, "How'd we get here with a scripted function?");
#endif

  if (!JS_CallFunctionValue(cx, wrappedObj, funToCall, argc, argv, rval)) {
    return JS_FALSE;
  }

  if (NS_SUCCEEDED(rv)) {
    return WrapSameOriginProp(cx, outerObj, rval);
  }

  return XPC_XOW_RewrapIfNeeded(cx, obj, rval);
}
示例#6
0
component_mozilla_method_stub(JSContext *cx, JSObject *obj, uint argc, 
			      jsval *argv, jsval *rval)
{
    JSFunction *func;
    JSObject *func_obj;
    jsval type, native;
    uint i;
    JSCompArg *comp_argv;

    func = JS_ValueToFunction(cx, argv[-2]);
    func_obj = JS_GetFunctionObject(func);

    if (!JS_GetProperty(cx, func_obj, lm_typePrefix_str, &type) ||
	!JSVAL_IS_INT(type) ||
	!JS_GetProperty(cx, func_obj, lm_methodPrefix_str, &native) ||
	!(comp_argv = JS_malloc(cx, argc * sizeof(JSCompArg))))
	return JS_TRUE;
  
    for (i=0; i<argc; i++) {
	if (JSVAL_IS_INT(argv[i])) {
	    comp_argv[i].type = ARGTYPE_INT32;
	    comp_argv[i].value.intArg = JSVAL_TO_INT(argv[i]);
	}
	else if (JSVAL_IS_BOOLEAN(argv[i])) {
	    comp_argv[i].type = ARGTYPE_BOOL;
	    comp_argv[i].value.boolArg = JSVAL_TO_BOOLEAN(argv[i]);
	}
	else if (JSVAL_IS_STRING(argv[i])) {
	    comp_argv[i].type = ARGTYPE_STRING;
	    comp_argv[i].value.stringArg = JS_GetStringBytes(JSVAL_TO_STRING(argv[i]));
	}
	else {
	    comp_argv[i].type = ARGTYPE_NULL;
	    comp_argv[i].value.intArg = 0;
	}
    }

    switch(JSVAL_TO_INT(type)) {
    case ARGTYPE_NULL:
	ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, NULL);
	*rval = 0;
	break;
    case ARGTYPE_INT32:
	*rval = INT_TO_JSVAL((int32)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv));
	break;
    case ARGTYPE_BOOL:
	*rval = BOOLEAN_TO_JSVAL((JSBool)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv));
	break;
    case ARGTYPE_STRING:
	*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, 
		(char*)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv)));
	break;
    }
    return JS_TRUE;
}
static JSBool teletone_on_dtmf(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
{
	struct teletone_obj *tto = JS_GetPrivate(cx, obj);
	if (argc > 0) {
		tto->function = JS_ValueToFunction(cx, argv[0]);
		if (argc > 1) {
			tto->arg = argv[1];
		}
		switch_set_flag(tto, TTF_DTMF);
	}
	return JS_TRUE;
}
示例#8
0
bool rs::jsapi::Object::CallFunction(JSContext* cx, unsigned argc, JS::Value* vp) {
    JSAutoRequest ar(cx);
    char nameBuffer[256];
    const char* name = nameBuffer;
    
    auto args = JS::CallArgsFromVp(argc, vp);
    auto func = JS_ValueToFunction(cx, args.calleev());
    if (func != nullptr) {
        auto funcName = JS_GetFunctionId(func);                
        if (funcName != nullptr) {
            auto nameLength = JS_EncodeStringToBuffer(cx, funcName, nameBuffer, sizeof(nameBuffer));
            if ((nameLength + 1) < sizeof(nameBuffer)) {
                nameBuffer[nameLength] = '\0';
            } else {
                std::vector<char> vBuffer(nameLength + 1);
                JS_EncodeStringToBuffer(cx, funcName, &vBuffer[0], nameLength);
                vBuffer[nameLength] = '\0';
                name = &vBuffer[0];
            }
        }
    }
    
    if (name == nullptr) {
        // TODO: test this case
        JS_ReportError(cx, "Unable to find function in libjsapi object");
        return false;        
    } else {
        auto that = args.thisv();
        auto state = that.isObjectOrNull() ? Object::GetState(cx, JS::RootedObject(cx, that.toObjectOrNull())) : nullptr;
        if (state == nullptr) {
            // TODO: test this case
            JS_ReportError(cx, "Unable to find function callback in libjsapi object");
            return false;
        } else {
            try {
                static thread_local std::vector<Value> vArgs;

                VectorUtils::ScopedVectorCleaner<Value> clean(vArgs);
                for (int i = 0; i < argc; ++i) {
                    vArgs.emplace_back(cx, args.get(i));
                }

                Value result(cx);
                state->functions[name](vArgs, result);
                args.rval().set(result);
                return true;
            } catch (const std::exception& ex) {
                JS_ReportError(cx, ex.what());
                return false;
            }
        }        
    }
}
示例#9
0
void jsInputPoll_t::onData( struct input_event const &event )
{
	JSFunction *function = JS_ValueToFunction( execContext_, handlerCode_ );
	JSObject   *obj = JSVAL_TO_OBJECT(handlerObj_);
	if( function && obj ){
		jsval args[3] = {
                        INT_TO_JSVAL( event.type )
		,	INT_TO_JSVAL( event.code )
		,	INT_TO_JSVAL( event.value )
		};
		jsval rval ;
                JS_CallFunction(execContext_, obj, function, 3, args, &rval );
	}
}
static JSBool
Exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    JSFunction *fun;
    const char *name, **nargv;
    uintN i, nargc;
    JSString *str;
    pid_t pid;
    int status;

    fun = JS_ValueToFunction(cx, argv[-2]);
    if (!fun)
        return JS_FALSE;
    if (!fun->atom)
        return JS_TRUE;
    name = JS_GetStringBytes(ATOM_TO_STRING(fun->atom));
    nargc = 1 + argc;
    nargv = JS_malloc(cx, (nargc + 1) * sizeof(char *));
    if (!nargv)
        return JS_FALSE;
    nargv[0] = name;
    for (i = 1; i < nargc; i++) {
        str = JS_ValueToString(cx, argv[i-1]);
        if (!str) {
            JS_free(cx, nargv);
            return JS_FALSE;
        }
        nargv[i] = JS_GetStringBytes(str);
    }
    nargv[nargc] = 0;
    pid = fork();
    switch (pid) {
      case -1:
        perror("js");
        break;
      case 0:
        (void) execvp(name, (char **)nargv);
        perror("js");
        exit(127);
      default:
        while (waitpid(pid, &status, 0) < 0 && errno == EINTR)
            continue;
        break;
    }
    JS_free(cx, nargv);
    return JS_TRUE;
}
示例#11
0
/*
 * Retrieve a JSFunction* from a JSDValue*. This differs from
 * JS_ValueToFunction by fully unwrapping the object first.
 */
JSFunction*
jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
{
    JSObject *obj;
    JSFunction *fun;

    JSCompartment* oldCompartment = NULL;
    if (JSVAL_IS_PRIMITIVE(jsdval->val))
        return NULL;

    obj = JS_UnwrapObject(JSVAL_TO_OBJECT(jsdval->val));
    oldCompartment = JS_EnterCompartment(jsdc->dumbContext, obj);
    fun = JS_ValueToFunction(jsdc->dumbContext, OBJECT_TO_JSVAL(obj));
    JS_LeaveCompartment(jsdc->dumbContext, oldCompartment);

    return fun;
}
示例#12
0
/*
 * Retrieve a JSFunction* from a JSDValue*. This differs from
 * JS_ValueToFunction by fully unwrapping the object first.
 */
JSFunction*
jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;

    JS::RootedObject obj(cx);
    JS::RootedFunction fun(cx);

    JSCompartment* oldCompartment = NULL;
    if (JSVAL_IS_PRIMITIVE(jsdval->val))
        return NULL;

    obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val));
    oldCompartment = JS_EnterCompartment(cx, obj);
    fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj));
    JS_LeaveCompartment(cx, oldCompartment);

    return fun;
}
示例#13
0
/*
 * Retrieve a JSFunction* from a JSDValue*. This differs from
 * JS_ValueToFunction by fully unwrapping the object first.
 */
JSFunction*
jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
{
    JSObject *obj;
    JSFunction *fun;
    JSCrossCompartmentCall *call = NULL;
    if (!JSVAL_IS_OBJECT(jsdval->val))
        return NULL;
    if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
        return NULL;
    obj = JS_UnwrapObject(obj);

    call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
    if (!call)
        return NULL;
    fun = JS_ValueToFunction(jsdc->dumbContext, OBJECT_TO_JSVAL(obj));
    JS_LeaveCrossCompartmentCall(call);

    return fun;
}
示例#14
0
const char*
jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    JSFunction* fun;
    JSExceptionState* exceptionState;

    if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
    {
        JS_BeginRequest(cx);
        exceptionState = JS_SaveExceptionState(cx);
        fun = JS_ValueToFunction(cx, jsdval->val);
        JS_RestoreExceptionState(cx, exceptionState);
        JS_EndRequest(cx);
        if(!fun)
            return NULL;
        jsdval->funName = JS_GetFunctionName(fun);
    }
    return jsdval->funName;
}
示例#15
0
JSBool
jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    jsval val = jsdval->val;
    JSFunction* fun;
    JSExceptionState* exceptionState;

    if(jsd_IsValueFunction(jsdc, jsdval))
    {
        JSBool ok = JS_FALSE;
        JS_BeginRequest(cx);
        exceptionState = JS_SaveExceptionState(cx);
        fun = JS_ValueToFunction(cx, val);
        JS_RestoreExceptionState(cx, exceptionState);
        if(fun)
            ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
        JS_EndRequest(cx);
        JS_ASSERT(fun);
        return ok;
    }
    return !JSVAL_IS_PRIMITIVE(val);
}
JSBool
XPC_NW_WrapFunction(JSContext* cx, JSObject* funobj, jsval *rval)
{
  // If funobj is already a wrapped function, just return it.
  if (JS_GetFunctionNative(cx,
                           JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj))) ==
      XPC_NW_FunctionWrapper) {
    *rval = OBJECT_TO_JSVAL(funobj);
    return JS_TRUE;
  }

  // Ensure that we've been called from JS. Native code should extract
  // the wrapped native and deal with that directly.
  // XXX Can we simply trust |cx| here?
  JSStackFrame *iterator = nsnull;
  if (!::JS_FrameIterator(cx, &iterator)) {
    ::JS_ReportError(cx, "XPCNativeWrappers must be used from script");
    return JS_FALSE;
  }
  
  // Create a new function that'll call our given function.  This new
  // function's parent will be the original function and that's how we
  // get the right thing to call when this function is called.
  // Note that we pass nsnull as the nominal parent so that we'll inherit
  // our caller's Function.prototype.
  JSFunction *funWrapper =
    ::JS_NewFunction(cx, XPC_NW_FunctionWrapper, 0, 0, nsnull,
                     "XPCNativeWrapper function wrapper");
  if (!funWrapper) {
    return JS_FALSE;
  }

  JSObject* funWrapperObj = ::JS_GetFunctionObject(funWrapper);
  ::JS_SetParent(cx, funWrapperObj, funobj);
  *rval = OBJECT_TO_JSVAL(funWrapperObj);
  return JS_TRUE;
}
示例#17
0
文件: Thread.c 项目: robn/amber
static JSBool thread_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
    JSFunction *fun;
    jsval arg;
    thread_stuff ts;

    if(argc == 0) {
        *rval = JSVAL_VOID;
        return JS_TRUE;
    }

    fun = JS_ValueToFunction(cx, argv[0]);
    ASSERT_THROW(fun == NULL, "argument is not a function");
    
    if(argc > 1)
        arg = argv[1];
    else
        arg = JSVAL_VOID;

    ts = JS_malloc(cx, sizeof(struct thread_stuff));

    pthread_mutex_init(&ts->mutex, NULL);

    ts->state = THREAD_INIT;

    ts->rt = JS_GetRuntime(cx);
    ts->amber = JS_GetGlobalObject(cx);

    ts->fun = fun;
    ts->arg = arg;

    JS_SetPrivate(cx, obj, ts);

    pthread_create(&ts->t, NULL, thread_start, ts);

    return JS_TRUE;
}
示例#18
0
JSBool PJS_invoke_perl_object_method(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
    PJS_Context *pcx;
    PJS_Class *pcls;
    PJS_Function *pfunc;
    JSFunction *jfunc = PJS_FUNC_SELF;
    SV *caller;
    char *name;
    U8 invocation_mode;
    
    if((pcx = PJS_GET_CONTEXT(cx)) == NULL) {
        JS_ReportError(cx, "Can't find context %d", cx);
        return JS_FALSE;
    }

    if (JS_TypeOfValue(cx, OBJECT_TO_JSVAL(obj)) == JSTYPE_OBJECT) {
        /* Called as instsance */
        JSClass *clasp = PJS_GET_CLASS(cx, obj);
        name = (char *) clasp->name;
        invocation_mode = 1;
    }
    else {
        /* Called as static */
        JSFunction *parent_jfunc = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj));
        if (parent_jfunc == NULL) {
            JS_ReportError(cx, "Failed to extract class for static property getter");
            return JS_FALSE;
        }
        name = (char *) JS_GetFunctionName(parent_jfunc);
        invocation_mode = 0;
    }

    if (!(pcls = PJS_GetClassByName(pcx, name))) {
        JS_ReportError(cx, "Can't find class '%s'", name);
        return JS_FALSE;
    }

    name = (char *) JS_GetFunctionName(jfunc);

    if((pfunc = PJS_get_method_by_name(pcls, name)) == NULL) {
        JS_ReportError(cx, "Can't find method '%s' in '%s'", name, pcls->clasp->name);
        return JS_FALSE;
    }

    if (invocation_mode) {
        caller = (SV *) JS_GetPrivate(cx, obj);
    }
    else {
        caller = newSVpv(pcls->pkg, 0);
    }

    /* XXX: the original invocation here has slightly different
       retrun value handling.  if the returned value is reference
       same as priv, don't return it.  While the case is not
       covered by the tets */
    
    if (perl_call_sv_with_jsvals(cx, obj, pfunc->callback,
                                 caller, argc, argv, rval) < 0) {
        return JS_FALSE;
    }

    return JS_TRUE;
}
示例#19
0
static JSBool curl_run(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
{
	struct curl_obj *co = JS_GetPrivate(cx, obj);
	char *method = NULL, *url, *cred = NULL;
	char *url_p = NULL, *data = NULL, *durl = NULL;
	long httpRes = 0;
	struct curl_slist *headers = NULL;
	int32 timeout = 0;
	char ct[80] = "Content-Type: application/x-www-form-urlencoded";

	if (argc < 2 || !co) {
		return JS_FALSE;
	}


	method = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
	url = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));

	co->curl_handle = switch_curl_easy_init();
	if (!strncasecmp(url, "https", 5)) {
		switch_curl_easy_setopt(co->curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
		switch_curl_easy_setopt(co->curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
	}


	if (argc > 2) {
		data = JS_GetStringBytes(JS_ValueToString(cx, argv[2]));
	}

	if (argc > 3) {
		co->function = JS_ValueToFunction(cx, argv[3]);
	}

	if (argc > 4) {
		JS_ValueToObject(cx, argv[4], &co->user_data);
	}

	if (argc > 5) {
		cred = JS_GetStringBytes(JS_ValueToString(cx, argv[5]));
		if (!zstr(cred)) {
			switch_curl_easy_setopt(co->curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
			switch_curl_easy_setopt(co->curl_handle, CURLOPT_USERPWD, cred);
		}
	}

	if (argc > 6) {
		JS_ValueToInt32(cx, argv[6], &timeout);
		if (timeout > 0) {
			switch_curl_easy_setopt(co->curl_handle, CURLOPT_TIMEOUT, timeout);
		}
	}

	if (argc > 7) {
		char *content_type = JS_GetStringBytes(JS_ValueToString(cx, argv[7]));
		switch_snprintf(ct, sizeof(ct), "Content-Type: %s", content_type);
	}

	headers = curl_slist_append(headers, ct);

	switch_curl_easy_setopt(co->curl_handle, CURLOPT_HTTPHEADER, headers);

	url_p = url;

	if (!strcasecmp(method, "post")) {
		switch_curl_easy_setopt(co->curl_handle, CURLOPT_POST, 1);
		if (!data) {
			data = "";
		}
		switch_curl_easy_setopt(co->curl_handle, CURLOPT_POSTFIELDS, data);
	} else if (!zstr(data)) {
		durl = switch_mprintf("%s?%s", url, data);
		url_p = durl;
	}

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Running: method: [%s] url: [%s] data: [%s] cred=[%s] cb: [%s]\n",
					  method, url_p, data, switch_str_nil(cred), co->function ? "yes" : "no");

	switch_curl_easy_setopt(co->curl_handle, CURLOPT_URL, url_p);
	switch_curl_easy_setopt(co->curl_handle, CURLOPT_NOSIGNAL, 1);
	switch_curl_easy_setopt(co->curl_handle, CURLOPT_WRITEFUNCTION, file_callback);
	switch_curl_easy_setopt(co->curl_handle, CURLOPT_WRITEDATA, (void *) co);

	switch_curl_easy_setopt(co->curl_handle, CURLOPT_USERAGENT, "freeswitch-spidermonkey-curl/1.0");

	co->saveDepth = JS_SuspendRequest(cx);
	switch_curl_easy_perform(co->curl_handle);

	switch_curl_easy_getinfo(co->curl_handle, CURLINFO_RESPONSE_CODE, &httpRes);
	switch_curl_easy_cleanup(co->curl_handle);
	curl_slist_free_all(headers);
	co->curl_handle = NULL;
	co->function = NULL;
	JS_ResumeRequest(cx, co->saveDepth);
	switch_safe_free(durl);


	return JS_TRUE;
}
示例#20
0
void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
{
	JSContext* cx = m_ScriptInterface.GetContext();
	JSAutoRequest rq(cx);

	switch (JS_TypeOfValue(cx, val))
	{
	case JSTYPE_VOID:
	{
		m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_VOID);
		break;
	}
	case JSTYPE_NULL: // This type is never actually returned (it's a JS2 feature)
	{
		m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_NULL);
		break;
	}
	case JSTYPE_OBJECT:
	{
		if (val.isNull())
		{
			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_NULL);
			break;
		}

		JS::RootedObject obj(cx, &val.toObject());

		// If we've already serialized this object, just output a reference to it
		u32 tag = GetScriptBackrefTag(obj);
		if (tag)
		{
			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BACKREF);
			m_Serializer.NumberU32_Unbounded("tag", tag);
			break;
		}

		// Arrays are special cases of Object
		if (JS_IsArrayObject(cx, obj))
		{
			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY);
			// TODO: probably should have a more efficient storage format

			// Arrays like [1, 2, ] have an 'undefined' at the end which is part of the
			// length but seemingly isn't enumerated, so store the length explicitly
			uint length = 0;
			if (!JS_GetArrayLength(cx, obj, &length))
				throw PSERROR_Serialize_ScriptError("JS_GetArrayLength failed");
			m_Serializer.NumberU32_Unbounded("array length", length);
		}
		else if (JS_IsTypedArrayObject(obj))
		{
			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_TYPED_ARRAY);

			m_Serializer.NumberU8_Unbounded("array type", GetArrayType(JS_GetArrayBufferViewType(obj)));
			m_Serializer.NumberU32_Unbounded("byte offset", JS_GetTypedArrayByteOffset(obj));
			m_Serializer.NumberU32_Unbounded("length", JS_GetTypedArrayLength(obj));

			// Now handle its array buffer
			// this may be a backref, since ArrayBuffers can be shared by multiple views
			JS::RootedValue bufferVal(cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(cx, obj)));
			HandleScriptVal(bufferVal);
			break;
		}
		else if (JS_IsArrayBufferObject(obj))
		{
			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY_BUFFER);

#if BYTE_ORDER != LITTLE_ENDIAN
#error TODO: need to convert JS ArrayBuffer data to little-endian
#endif

			u32 length = JS_GetArrayBufferByteLength(obj);
			m_Serializer.NumberU32_Unbounded("buffer length", length);
			JS::AutoCheckCannotGC nogc;
			m_Serializer.RawBytes("buffer data", (const u8*)JS_GetArrayBufferData(obj, nogc), length);
			break;
		}
		else
		{
			// Find type of object
			const JSClass* jsclass = JS_GetClass(obj);
			if (!jsclass)
				throw PSERROR_Serialize_ScriptError("JS_GetClass failed");
// TODO: Remove this workaround for upstream API breakage when updating SpiderMonkey
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1236373
#define JSCLASS_CACHED_PROTO_WIDTH js::JSCLASS_CACHED_PROTO_WIDTH
			JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass);
#undef JSCLASS_CACHED_PROTO_WIDTH

			if (protokey == JSProto_Object)
			{
				// Object class - check for user-defined prototype
				JS::RootedObject proto(cx);
				JS_GetPrototype(cx, obj, &proto);
				if (!proto)
					throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed");

				if (m_SerializablePrototypes->empty() || !IsSerializablePrototype(proto))
				{
					// Standard Object prototype
					m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT);

					// TODO: maybe we should throw an error for unrecognized non-Object prototypes?
					//	(requires fixing AI serialization first and excluding component scripts)
				}
				else
				{
					// User-defined custom prototype
					m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_PROTOTYPE);

					const std::wstring prototypeName = GetPrototypeName(proto);
					m_Serializer.String("proto name", prototypeName, 0, 256);

					// Does it have custom Serialize function?
					// if so, we serialize the data it returns, rather than the object's properties directly
					bool hasCustomSerialize;
					if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize))
						throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");

					if (hasCustomSerialize)
					{
						JS::RootedValue serialize(cx);
						if (!JS_GetProperty(cx, obj, "Serialize", &serialize))
							throw PSERROR_Serialize_ScriptError("JS_GetProperty failed");

						// If serialize is null, so don't serialize anything more
						if (!serialize.isNull())
						{
							JS::RootedValue data(cx);
							if (!m_ScriptInterface.CallFunction(val, "Serialize", &data))
								throw PSERROR_Serialize_ScriptError("Prototype Serialize function failed");
							HandleScriptVal(data);
						}
						break;
					}
				}
			}
			else if (protokey == JSProto_Number)
			{
				// Standard Number object
				m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_NUMBER);
				// Get primitive value
				double d;
				if (!JS::ToNumber(cx, val, &d))
					throw PSERROR_Serialize_ScriptError("JS::ToNumber failed");
				m_Serializer.NumberDouble_Unbounded("value", d);
				break;
			}
			else if (protokey == JSProto_String)
			{
				// Standard String object
				m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_STRING);
				// Get primitive value
				JS::RootedString str(cx, JS::ToString(cx, val));
				if (!str)
					throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
				ScriptString("value", str);
				break;
			}
			else if (protokey == JSProto_Boolean)
			{
				// Standard Boolean object
				m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_BOOLEAN);
				// Get primitive value
				bool b = JS::ToBoolean(val);
				m_Serializer.Bool("value", b);
				break;
			}
			// TODO: Follow upstream progresses about a JS::IsMapObject
			// https://bugzilla.mozilla.org/show_bug.cgi?id=1285909
			else if (protokey == JSProto_Map)
			{
				m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_MAP);
				m_Serializer.NumberU32_Unbounded("map size", JS::MapSize(cx, obj));

				JS::RootedValue keyValueIterator(cx);
				if (!JS::MapEntries(cx, obj, &keyValueIterator))
					throw PSERROR_Serialize_ScriptError("JS::MapEntries failed");

				JS::ForOfIterator it(cx);
				if (!it.init(keyValueIterator))
					throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::init failed");

				JS::RootedValue keyValuePair(cx);
				bool done;
				while (true)
				{
					if (!it.next(&keyValuePair, &done))
						throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::next failed");

					if (done)
						break;

					JS::RootedObject keyValuePairObj(cx, &keyValuePair.toObject());
					JS::RootedValue key(cx);
					JS::RootedValue value(cx);
					ENSURE(JS_GetElement(cx, keyValuePairObj, 0, &key));
					ENSURE(JS_GetElement(cx, keyValuePairObj, 1, &value));

					HandleScriptVal(key);
					HandleScriptVal(value);
				}
				break;
			}
			// TODO: Follow upstream progresses about a JS::IsSetObject
			// https://bugzilla.mozilla.org/show_bug.cgi?id=1285909
			else if (protokey == JSProto_Set)
			{
				// TODO: When updating SpiderMonkey to a release after 38 use the C++ API for Sets.
				// https://bugzilla.mozilla.org/show_bug.cgi?id=1159469
				u32 setSize;
				m_ScriptInterface.GetProperty(val, "size", setSize);

				m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_SET);
				m_Serializer.NumberU32_Unbounded("set size", setSize);

				JS::RootedValue valueIterator(cx);
				m_ScriptInterface.CallFunction(val, "values", &valueIterator);
				for (u32 i=0; i<setSize; ++i)
				{
					JS::RootedValue currentIterator(cx);
					JS::RootedValue value(cx);
					ENSURE(m_ScriptInterface.CallFunction(valueIterator, "next", &currentIterator));

					m_ScriptInterface.GetProperty(currentIterator, "value", &value);

					HandleScriptVal(value);
				}

				break;
			}
			else
			{
				// Unrecognized class
				LOGERROR("Cannot serialise JS objects with unrecognized class '%s'", jsclass->name);
				throw PSERROR_Serialize_InvalidScriptValue();
			}
		}

		// Find all properties (ordered by insertion time)
		JS::AutoIdArray ida (cx, JS_Enumerate(cx, obj));
		if (!ida)
			throw PSERROR_Serialize_ScriptError("JS_Enumerate failed");

		m_Serializer.NumberU32_Unbounded("num props", (u32)ida.length());

		for (size_t i = 0; i < ida.length(); ++i)
		{
			JS::RootedId id(cx, ida[i]);

			JS::RootedValue idval(cx);
			JS::RootedValue propval(cx);

			// Forbid getters, which might delete values and mess things up.
			JS::Rooted<JSPropertyDescriptor> desc(cx);
			if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
				throw PSERROR_Serialize_ScriptError("JS_GetPropertyDescriptorById failed");
			if (desc.hasGetterObject())
				throw PSERROR_Serialize_ScriptError("Cannot serialize property getters");

			// Get the property name as a string
			if (!JS_IdToValue(cx, id, &idval))
				throw PSERROR_Serialize_ScriptError("JS_IdToValue failed");
			JS::RootedString idstr(cx, JS::ToString(cx, idval));
			if (!idstr)
				throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");

			ScriptString("prop name", idstr);

			if (!JS_GetPropertyById(cx, obj, id, &propval))
				throw PSERROR_Serialize_ScriptError("JS_GetPropertyById failed");

			HandleScriptVal(propval);
		}

		break;
	}
	case JSTYPE_FUNCTION:
	{
		// We can't serialise functions, but we can at least name the offender (hopefully)
		std::wstring funcname(L"(unnamed)");
		JS::RootedFunction func(cx, JS_ValueToFunction(cx, val));
		if (func)
		{
			JS::RootedString string(cx, JS_GetFunctionId(func));
			if (string)
			{
				if (JS_StringHasLatin1Chars(string))
				{
					size_t length;
					JS::AutoCheckCannotGC nogc;
					const JS::Latin1Char* ch = JS_GetLatin1StringCharsAndLength(cx, nogc, string, &length);
					if (ch && length > 0)
						funcname.assign(ch, ch + length);
				}
				else
				{
					size_t length;
					JS::AutoCheckCannotGC nogc;
					const char16_t* ch = JS_GetTwoByteStringCharsAndLength(cx, nogc, string, &length);
					if (ch && length > 0)
						funcname.assign(ch, ch + length);
				}
			}
		}

		LOGERROR("Cannot serialise JS objects of type 'function': %s", utf8_from_wstring(funcname));
		throw PSERROR_Serialize_InvalidScriptValue();
	}
	case JSTYPE_STRING:
	{
		m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_STRING);
		JS::RootedString stringVal(cx, val.toString());
		ScriptString("string", stringVal);
		break;
	}
	case JSTYPE_NUMBER:
	{
		// To reduce the size of the serialized data, we handle integers and doubles separately.
		// We can't check for val.isInt32 and val.isDouble directly, because integer numbers are not guaranteed
		// to be represented as integers. A number like 33 could be stored as integer on the computer of one player
		// and as double on the other player's computer. That would cause out of sync errors in multiplayer games because
		// their binary representation and thus the hash would be different.

		double d;
		d = val.toNumber();
		i32 integer;

		if (JS_DoubleIsInt32(d, &integer))
		{
			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_INT);
			m_Serializer.NumberI32_Unbounded("value", integer);
		}
		else
		{
			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE);
			m_Serializer.NumberDouble_Unbounded("value", d);
		}
		break;
	}
	case JSTYPE_BOOLEAN:
	{
		m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BOOLEAN);
		bool b = val.toBoolean();
		m_Serializer.NumberU8_Unbounded("value", b ? 1 : 0);
		break;
	}
	default:
	{
		debug_warn(L"Invalid TypeOfValue");
		throw PSERROR_Serialize_InvalidScriptValue();
	}
	}
}
void
WrapperPromiseCallback::Call(JSContext* aCx,
                             JS::Handle<JS::Value> aValue)
{
  JSAutoCompartment ac(aCx, mGlobal);
  JS::Rooted<JS::Value> value(aCx, aValue);
  if (!JS_WrapValue(aCx, &value)) {
    NS_WARNING("Failed to wrap value into the right compartment.");
    return;
  }

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  JS::Rooted<JS::Value> retValue(aCx);
  mCallback->Call(value, &retValue, rv, CallbackObject::eRethrowExceptions);

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    JS::Rooted<JS::Value> value(aCx);
    rv.StealJSException(aCx, &value);

    if (!JS_WrapValue(aCx, &value)) {
      NS_WARNING("Failed to wrap value into the right compartment.");
      return;
    }

    mNextPromise->RejectInternal(aCx, value, Promise::SyncTask);
    return;
  }

  // If the return value is the same as the promise itself, throw TypeError.
  if (retValue.isObject()) {
    JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject());
    Promise* returnedPromise;
    nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);

    if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) {
      const char* fileName = nullptr;
      uint32_t lineNumber = 0;

      // Try to get some information about the callback to report a sane error,
      // but don't try too hard (only deals with scripted functions).
      JS::Rooted<JSObject*> unwrapped(aCx,
        js::CheckedUnwrap(mCallback->Callback()));

      if (unwrapped) {
        JSAutoCompartment ac(aCx, unwrapped);
        if (JS_ObjectIsFunction(aCx, unwrapped)) {
          JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped));
          JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue));

          MOZ_ASSERT(func);
          JSScript* script = JS_GetFunctionScript(aCx, func);
          if (script) {
            fileName = JS_GetScriptFilename(script);
            lineNumber = JS_GetScriptBaseLineNumber(aCx, script);
          }
        }
      }

      // We're back in aValue's compartment here.
      JS::Rooted<JSString*> stack(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
      JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName));
      if (!fn) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return;
      }

      JS::Rooted<JSString*> message(aCx,
        JS_NewStringCopyZ(aCx,
          "then() cannot return same Promise that it resolves."));
      if (!message) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return;
      }

      JS::Rooted<JS::Value> typeError(aCx);
      if (!JS::CreateTypeError(aCx, stack, fn, lineNumber, 0,
                               nullptr, message, &typeError)) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return;
      }

      mNextPromise->RejectInternal(aCx, typeError, Promise::SyncTask);
      return;
    }
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  if (!JS_WrapValue(aCx, &retValue)) {
    NS_WARNING("Failed to wrap value into the right compartment.");
    return;
  }

  mNextPromise->ResolveInternal(aCx, retValue, Promise::SyncTask);
}
JSBool
WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp)
{
  // This might be redundant if called from XPC_SJOW_Construct, but it should
  // be cheap in that case.
  JSObject *objToWrap = UnsafeUnwrapSecurityWrapper(cx, JSVAL_TO_OBJECT(v));
  if (!objToWrap ||
      JS_TypeOfValue(cx, OBJECT_TO_JSVAL(objToWrap)) == JSTYPE_XML) {
    return ThrowException(NS_ERROR_INVALID_ARG, cx);
  }

  // Prevent script created Script objects from ever being wrapped
  // with XPCSafeJSObjectWrapper, and never let the eval function
  // object be directly wrapped.

  if (objToWrap->getClass() == &js_ScriptClass ||
      (JS_ObjectIsFunction(cx, objToWrap) &&
       JS_GetFunctionFastNative(cx, JS_ValueToFunction(cx, v)) ==
       XPCWrapper::sEvalNative)) {
    return ThrowException(NS_ERROR_INVALID_ARG, cx);
  }

  XPCWrappedNativeScope *xpcscope =
    XPCWrappedNativeScope::FindInJSObjectScope(cx, scope);
  NS_ASSERTION(xpcscope, "what crazy scope are we in?");

  XPCWrappedNative *wrappedNative;
  WrapperType type = xpcscope->GetWrapperFor(cx, objToWrap, SJOW,
                                             &wrappedNative);

  // NB: We allow XOW here because we're as restrictive as it is (and we know
  // we're same origin here).
  if (type != NONE && type != XOW && !(type & SJOW)) {
    return ThrowException(NS_ERROR_INVALID_ARG, cx);
  }

  SLIM_LOG_WILL_MORPH(cx, objToWrap);
  if (IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) {
    return ThrowException(NS_ERROR_FAILURE, cx);
  }

  XPCWrappedNative *wn =
    XPCWrappedNative::GetWrappedNativeOfJSObject(cx, objToWrap);
  if (wn) {
    CheckWindow(wn);
  }

  JSObject *wrapperObj =
    JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SJOWClass), nsnull, scope);

  if (!wrapperObj) {
    // JS_NewObjectWithGivenProto already threw.
    return JS_FALSE;
  }

  *vp = OBJECT_TO_JSVAL(wrapperObj);
  if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot,
                          OBJECT_TO_JSVAL(objToWrap)) ||
      !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO)) {
    return JS_FALSE;
  }

  return JS_TRUE;
}
示例#23
0
JSFunction*
elixir_get_fct(JSContext *cx, jsval arg)
{
   return JS_ValueToFunction(cx, arg);
}
示例#24
0
//---------------------------------------------------------------------------
static JSBool function_handler(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
    int                    count, i;
    char                   *fun_name;
    INVOKE_CALL            Invoke      = InvokePtr;
    CALL_BACK_VARIABLE_SET SetVariable = _SetVariable;
    void                   *HANDLER    = CONCEPT_HANDLER;

    /* Differetiate between direct and method-like call */
    if ((JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION) && strcmp("call", JS_GetFunctionName(JS_ValueToFunction(cx, argv[-2])))) {
        fun_name = (char *)JS_GetFunctionName((JSFunction *)JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2])));
        i        = 0;
    } else {
        fun_name = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
        i        = 1;
    }
    //std::cerr << fun_name;
    FunctionTypes *ft = FindFunction(fun_name, cx, obj);
    if (!ft)
        return JS_FALSE;

    int len = argc - i;
    // antibug
    if (len < 0)
        len = 0;
    void **PARAMETERS = new void * [len + 1];
    PARAMETERS[len] = 0;


    int first_arg = i;
    int index     = 0;
    for ( ; i < argc; i++) {
        jsval param = argv[i];
        CREATE_VARIABLE(PARAMETERS[index]);
        JS_TO_CONCEPT(PARAMETERS[index], param);
        index++;
    }

    // -1 in parameter count means that we will prvide a parameter list;
    void *EXCEPTION = 0;
    void *RES       = 0;
    Invoke(INVOKE_CALL_DELEGATE, ft->DELEGATE, &RES, &EXCEPTION, (INTEGER)-1, PARAMETERS);
    if (RES) {
        *rval = CONCEPT_TO_JS(cx, RES);
        Invoke(INVOKE_FREE_VARIABLE, RES);
    }
    if (EXCEPTION) {
        ejs_throw_error(cx, obj, CONCEPT_TO_STRING(cx, EXCEPTION).c_str());
        Invoke(INVOKE_FREE_VARIABLE, EXCEPTION);
    }

    for (i = 0; i < index; i++) {
        //argv[i+first_arg]=CONCEPT_TO_JS(cx, PARAMETERS[i]);
        FREE_VARIABLE(PARAMETERS[i]);
    }
    if (PARAMETERS)
        delete[] PARAMETERS;

    /*jsdouble x, z;
       if (!JS_ValueToNumber(cx, argv[0], &x))
        return JS_FALSE;
       z = (x < 0) ? -x : x;
        return JS_NewDoubleValue(cx, z, rval);*/

    return JS_TRUE;
}
示例#25
0
/*
 * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
 * Method:    _invoke
 * Signature: (ILjava/lang/String;I[I)I
 */
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1invoke
(JNIEnv* env, jclass, jint scriptObjInt, jstring methodName, jint jsThisInt,
 jintArray jsArgsInt, jint jsRetValInt)
{
    Tracer tracer("LowLevelMoz._invoke");

    JStringWrap methodStr(env, methodName);
    if (!methodStr.str()) {
        tracer.setFail("null method name");
        return JNI_FALSE;
    }
    JsRootedValue* jsThisRV = reinterpret_cast<JsRootedValue*>(jsThisInt);
    jint jsArgc = env->GetArrayLength(jsArgsInt);
    tracer.log("method=%s, jsthis=%08x, #args=%d", methodStr.str(), jsThisInt,
               jsArgc);
    JSContext* cx = JsRootedValue::currentContext();
    nsIScriptGlobalObject* scriptObject =
        NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
    JSObject* scriptWindow
        = reinterpret_cast<JSObject*>(scriptObject->GetGlobalJSObject());

    jsval fval;
    if (!JS_GetProperty(cx, scriptWindow, methodStr.str(), &fval)) {
        tracer.setFail("JS_GetProperty(method) failed");
        return JNI_FALSE;
    }
    JSFunction* jsFunction = JS_ValueToFunction(cx, fval);
    if (!jsFunction) {
        tracer.setFail("JS_ValueToFunction failed");
        return JNI_FALSE;
    }

    // extract arguments in jsval form
    nsAutoArrayPtr<jint> jsargvals(new jint[jsArgc]);
    if (!jsargvals) {
        tracer.setFail("failed to allocate arg array");
        return JNI_FALSE;
    }
    env->GetIntArrayRegion(jsArgsInt, 0, jsArgc, jsargvals);
    if (env->ExceptionCheck()) {
        tracer.setFail("copy from Java array failed");
        return JNI_FALSE;
    }
    nsAutoArrayPtr<jsval> jsargs(new jsval[jsArgc]);
    for (int i = 0; i < jsArgc; ++i) {
        JsRootedValue* arg = reinterpret_cast<JsRootedValue*>(jsargvals[i]);
        jsargs[i] = arg->getValue();
    }

    jsval jsrval;
    JSObject* jsThis;
    if (jsThisRV->isNull()) {
        jsThis = scriptWindow;
    } else {
        jsThis = jsThisRV->getObject();
    }

    PrintJSValue(cx, OBJECT_TO_JSVAL(jsThis), "jsThis=");
    for (int i = 0; i < jsArgc; ++i) {
        char buf[256];
        snprintf(buf, sizeof(buf), "arg[%d]=", i);
        PrintJSValue(cx, jsargs[i], buf);
    }
    //tracer.log("fval = %08x, args=%08x", fval, jsargs.get());
    if (!JS_CallFunctionValue(cx, jsThis, fval, jsArgc, jsargs.get(), &jsrval)) {
        tracer.setFail("JS_CallFunctionValue failed");
        return JNI_FALSE;
    }

    PrintJSValue(cx, jsrval, "return value=");
    JsRootedValue* returnVal = reinterpret_cast<JsRootedValue*>(jsRetValInt);
    returnVal->setValue(jsrval);
    return JNI_TRUE;
}
示例#26
0
void
WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
{
  // AutoCxPusher and co. interact with xpconnect, which crashes on
  // workers. On workers we'll get the right context from
  // GetDefaultJSContextForThread(), and since there is only one context, we
  // don't need to push or pop it from the stack.
  JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();

  Maybe<AutoCxPusher> pusher;
  if (NS_IsMainThread()) {
    pusher.construct(cx);
  }

  Maybe<JSAutoCompartment> ac;
  EnterCompartment(ac, cx, aValue);

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  JS::Rooted<JS::Value> value(cx,
    mCallback->Call(aValue, rv, CallbackObject::eRethrowExceptions));

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    JS::Rooted<JS::Value> value(cx);
    rv.StealJSException(cx, &value);

    Maybe<JSAutoCompartment> ac2;
    EnterCompartment(ac2, cx, value);
    mNextPromise->RejectInternal(cx, value, Promise::SyncTask);
    return;
  }

  // If the return value is the same as the promise itself, throw TypeError.
  if (value.isObject()) {
    JS::Rooted<JSObject*> valueObj(cx, &value.toObject());
    Promise* returnedPromise;
    nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);

    if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) {
      const char* fileName = nullptr;
      uint32_t lineNumber = 0;

      // Try to get some information about the callback to report a sane error,
      // but don't try too hard (only deals with scripted functions).
      JS::Rooted<JSObject*> unwrapped(cx,
        js::CheckedUnwrap(mCallback->Callback()));

      if (unwrapped) {
        JSAutoCompartment ac(cx, unwrapped);
        if (JS_ObjectIsFunction(cx, unwrapped)) {
          JS::Rooted<JS::Value> asValue(cx, JS::ObjectValue(*unwrapped));
          JS::Rooted<JSFunction*> func(cx, JS_ValueToFunction(cx, asValue));

          MOZ_ASSERT(func);
          JSScript* script = JS_GetFunctionScript(cx, func);
          if (script) {
            fileName = JS_GetScriptFilename(cx, script);
            lineNumber = JS_GetScriptBaseLineNumber(cx, script);
          }
        }
      }

      // We're back in aValue's compartment here.
      JS::Rooted<JSString*> stack(cx, JS_GetEmptyString(JS_GetRuntime(cx)));
      JS::Rooted<JSString*> fn(cx, JS_NewStringCopyZ(cx, fileName));
      if (!fn) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(cx);
        return;
      }

      JS::Rooted<JSString*> message(cx,
        JS_NewStringCopyZ(cx,
          "then() cannot return same Promise that it resolves."));
      if (!message) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(cx);
        return;
      }

      JS::Rooted<JS::Value> typeError(cx);
      if (!JS::CreateTypeError(cx, stack, fn, lineNumber, 0,
                               nullptr, message, &typeError)) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(cx);
        return;
      }

      mNextPromise->RejectInternal(cx, typeError, Promise::SyncTask);
      return;
    }
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  Maybe<JSAutoCompartment> ac2;
  EnterCompartment(ac2, cx, value);
  mNextPromise->ResolveInternal(cx, value, Promise::SyncTask);
}
static JSBool
XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp,
                         JSBool isSet)
{
  if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) {
    return JS_TRUE;
  }

  // Don't do anything if we already resolved to a wrapped function in
  // NewResolve. In practice, this means that this is a wrapped eval
  // function.
  jsval v = *vp;
  if (!JSVAL_IS_PRIMITIVE(v) &&
      JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v)) &&
      JS_GetFunctionNative(cx, JS_ValueToFunction(cx, v)) ==
      XPC_XOW_FunctionWrapper) {
    return JS_TRUE;
  }

  JSObject *origObj = obj;
  obj = GetWrapper(obj);
  if (!obj) {
    return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
  }

  XPCCallContext ccx(JS_CALLER, cx);
  if (!ccx.IsValid()) {
    return ThrowException(NS_ERROR_FAILURE, cx);
  }

  AUTO_MARK_JSVAL(ccx, vp);

  JSObject *wrappedObj = GetWrappedObject(cx, obj);
  if (!wrappedObj) {
    return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx);
  }

  JSBool privilegeEnabled;
  nsresult rv = CanAccessWrapper(cx, wrappedObj, &privilegeEnabled);
  if (NS_FAILED(rv)) {
    if (rv != NS_ERROR_DOM_PROP_ACCESS_DENIED) {
      return JS_FALSE;
    }

    // This is a request to get a property across origins. We need to
    // determine if this property is allAccess. If it is, then we need to
    // actually get the property. If not, we simply need to throw an
    // exception.

    XPCWrappedNative *wn =
      XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj);
    NS_ASSERTION(wn, "How did we wrap a non-WrappedNative?");
    if (!IsValFrame(wrappedObj, id, wn)) {
      nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
      if (!ssm) {
        return ThrowException(NS_ERROR_NOT_INITIALIZED, cx);
      }
      rv = ssm->CheckPropertyAccess(cx, wrappedObj,
                                    STOBJ_GET_CLASS(wrappedObj)->name,
                                    id, isSet ? XPCWrapper::sSecMgrSetProp
                                              : XPCWrapper::sSecMgrGetProp);
      if (NS_FAILED(rv)) {
        // The security manager threw an exception for us.
        return JS_FALSE;
      }
    }

    return XPCWrapper::GetOrSetNativeProperty(cx, obj, wn, id, vp, isSet,
                                              JS_FALSE);
  }

  JSObject *proto = nsnull; // Initialize this to quiet GCC.
  JSBool checkProto =
    (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO));
  if (checkProto) {
    proto = STOBJ_GET_PROTO(wrappedObj);
  }

  // Same origin, pass this request along as though nothing interesting
  // happened.
  jsid asId;

  if (!JS_ValueToId(cx, id, &asId)) {
    return JS_FALSE;
  }

  JSBool ok = isSet
              ? JS_SetPropertyById(cx, wrappedObj, asId, vp)
              : JS_GetPropertyById(cx, wrappedObj, asId, vp);
  if (!ok) {
    return JS_FALSE;
  }

  if (checkProto) {
    JSObject *newProto = STOBJ_GET_PROTO(wrappedObj);

    // If code is trying to set obj.__proto__ and we're on obj's
    // prototype chain, then the JS_GetPropertyById above will do the
    // wrong thing if wrappedObj still delegates to Object.prototype.
    // However, it's hard to figure out if wrappedObj still does
    // delegate to Object.prototype so check to see if proto changed as a
    // result of setting __proto__.

    if (origObj != obj) {
      // Undo the damage.
      if (!JS_SetPrototype(cx, wrappedObj, proto) ||
          !JS_SetPrototype(cx, origObj, newProto)) {
        return JS_FALSE;
      }
    } else if (newProto) {
      // __proto__ setting is a bad hack, people shouldn't do it. In
      // this case we're setting the direct prototype of a XOW object,
      // in the interests of sanity only allow it to be set to null in
      // this case.

      JS_SetPrototype(cx, wrappedObj, proto);
      JS_ReportError(cx, "invalid __proto__ value (can only be set to null)");
      return JS_FALSE;
    }
  }

  return WrapSameOriginProp(cx, obj, vp);
}
示例#28
0
nsresult
leakmonJSObjectInfo::Init(leakmonObjectsInReportTable &aObjectsInReport)
{
	mIsInitialized = PR_TRUE;

	JSContext *cx = leakmonService::GetJSContext();
	NS_ENSURE_TRUE(cx, NS_ERROR_UNEXPECTED);

	JSAutoRequest ar(cx);

	if (!JSVAL_IS_PRIMITIVE(mJSValue)) {
		JSObject *obj = JSVAL_TO_OBJECT(mJSValue);

		// All of the objects in obj's prototype chain, and all
		// objects reachable from JS_NewPropertyIterator should
		// (I think?) be in the same compartment.
		JSAutoEnterCompartment ac;
		if (!ac.enter(cx, obj)) {
			return NS_ERROR_FAILURE;
		}

		JSObject *p;

		for (p = obj; p; p = JS_GetPrototype(cx, p)) {
			// Stack-scanning protects newly-created objects
			// (etor) from GC.  (And protecting |etor|
			// should in turn protect |id|.)

			// JS_NewPropertyIterator has the nice property that it
			// avoids JS_Enumerate on native objects (where it can
			// execute code) and uses the scope properties, but doesn't
			// require this code to use the unstable OBJ_IS_NATIVE API.
			JSObject *etor = JS_NewPropertyIterator(cx, p);
			if (!etor)
			    return NS_ERROR_OUT_OF_MEMORY;

			jsid id;
			while (JS_NextProperty(cx, etor, &id) && !JSID_IS_VOID(id)) {
				nsresult rv = AppendProperty(id, cx, aObjectsInReport);
				NS_ENSURE_SUCCESS(rv, rv);
			}
		}

		if (JS_ObjectIsFunction(cx, obj)) {
			JSFunction *fun = JS_ValueToFunction(cx, mJSValue);
			NS_ENSURE_TRUE(fun, NS_ERROR_UNEXPECTED);
			JSScript *script = JS_GetFunctionScript(cx, fun);
			if (script) { // null for native code
				const char *fname = JS_GetScriptFilename(cx, script);
				// XXX Do we know the encoding of this file name?
				mFileName = NS_ConvertUTF8toUTF16(fname);

				mLineStart = JS_GetScriptBaseLineNumber(cx, script);
				mLineEnd = mLineStart + JS_GetScriptLineExtent(cx, script) - 1;
			}
		}
	}

	ValueToString(cx, mJSValue, mString);

	return NS_OK;
}
示例#29
0
JSBool PJS_invoke_perl_property_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) {
    dSP;
    PJS_Context *pcx;
    PJS_Class *pcls;
    PJS_Property *pprop;
    SV *caller;
    char *name;
    jsint slot;
    U8 invocation_mode;

    if (!(JSVAL_IS_INT(id) || JSVAL_IS_STRING(id))) {
        return JS_TRUE;
    }
    
    if((pcx = PJS_GET_CONTEXT(cx)) == NULL) {
        JS_ReportError(cx, "Can't find context %d", cx);
        return JS_FALSE;
    }

    if (JS_TypeOfValue(cx, OBJECT_TO_JSVAL(obj)) == JSTYPE_OBJECT) {
        /* Called as instsance */
        JSClass *clasp = PJS_GET_CLASS(cx, obj);
        name = (char *) clasp->name;
        invocation_mode = 1;
    }
    else {
        /* Called as static */
        JSFunction *parent_jfunc = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj));
        if (parent_jfunc == NULL) {
            JS_ReportError(cx, "Failed to extract class for static property getter");
            return JS_FALSE;
        }
        name = (char *) JS_GetFunctionName(parent_jfunc);
        invocation_mode = 0;
    }
    
    if ((pcls = PJS_GetClassByName(pcx, name)) == NULL) {
        JS_ReportError(cx, "Can't find class '%s'", name);
        return JS_FALSE;
    }
    
    if (invocation_mode) {
        caller = (SV *) JS_GetPrivate(cx, obj);
    }
    else {
        caller = newSVpv(pcls->pkg, 0);
    }
    
    if (JSVAL_IS_INT(id)) {
      slot = JSVAL_TO_INT(id);
    
      if ((pprop = PJS_get_property_by_id(pcls,  (int8) slot)) == NULL) {
        if (SvTRUE(pcls->property_getter)) {
            if (perl_call_sv_with_jsvals(cx, obj, pcls->property_getter, caller, 1, &id, vp) < 0) {
                return JS_FALSE;
            }
            return JS_TRUE;
        }
        JS_ReportError(cx, "Can't find property handler");
        return JS_FALSE;
      }

      if (pprop->getter == NULL) {
        JS_ReportError(cx, "Property is write-only");
        return JS_FALSE;
      }

      if (perl_call_sv_with_jsvals(cx, obj, pprop->getter, caller, 0, NULL, vp) < 0) {
        return JS_FALSE;
      }
    }
    else if (JSVAL_IS_STRING(id) && SvTRUE(pcls->property_getter)) {
      SV *sv = sv_newmortal();
#ifdef JS_C_STRINGS_ARE_UTF8
      char *tmp = JS_smprintf("%hs", JS_GetStringChars(JSVAL_TO_STRING(id)));
      sv_setpv(sv, tmp);
      SvUTF8_on(sv);
      free(tmp);
#else
      sv_setpv(sv, JS_GetStringBytes(JSVAL_TO_STRING(id)));
#endif         

      if (PJS_get_method_by_name(pcls, SvPV_nolen(sv))) {
        return JS_TRUE;
      }
      
      if (perl_call_sv_with_jsvals(cx, obj, pcls->property_getter, caller, 1, &id, vp) < 0) {
        return JS_FALSE;
      }      
    }

    return JS_TRUE;
}
示例#30
0
文件: jsexn.c 项目: artcom/y60
static JSBool
InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message,
                    JSString *filename, uintN lineno)
{
    JSCheckAccessOp checkAccess;
    JSErrorReporter older;
    JSExceptionState *state;
    jschar *stackbuf;
    size_t stacklen, stackmax;
    JSStackFrame *fp;
    jsval callerid, v;
    JSBool ok;
    JSString *argsrc, *stack;
    uintN i, ulineno;
    const char *cp;
    char ulnbuf[11];

    if (!JS_DefineProperty(cx, obj, js_message_str, STRING_TO_JSVAL(message),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return JS_FALSE;
    }

    if (!JS_DefineProperty(cx, obj, js_filename_str,
                           STRING_TO_JSVAL(filename),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return JS_FALSE;
    }

    if (!JS_DefineProperty(cx, obj, js_lineno_str,
                           INT_TO_JSVAL(lineno),
                           NULL, NULL, JSPROP_ENUMERATE)) {
        return JS_FALSE;
    }

    /*
     * Set the 'stack' property.
     *
     * First, set aside any error reporter for cx and save its exception state
     * so we can suppress any checkAccess failures.  Such failures should stop
     * the backtrace procedure, not result in a failure of this constructor.
     */
    checkAccess = cx->runtime->checkObjectAccess;
    if (checkAccess) {
        older = JS_SetErrorReporter(cx, NULL);
        state = JS_SaveExceptionState(cx);
    }
#ifdef __GNUC__         /* suppress bogus gcc warnings */
    else {
        older = NULL;
        state = NULL;
    }
#endif
    callerid = ATOM_KEY(cx->runtime->atomState.callerAtom);

    /*
     * Prepare to allocate a jschar buffer at stackbuf, where stacklen indexes
     * the next free jschar slot, and with room for at most stackmax non-null
     * jschars.  If stackbuf is non-null, it always contains an extra slot for
     * the null terminator we'll store at the end, as a backstop.
     *
     * All early returns must goto done after this point, till the after-loop
     * cleanup code has run!
     */
    stackbuf = NULL;
    stacklen = stackmax = 0;
    ok = JS_TRUE;

#define APPEND_CHAR_TO_STACK(c)                                               \
    JS_BEGIN_MACRO                                                            \
        if (stacklen == stackmax) {                                           \
            void *ptr_;                                                       \
            stackmax = stackmax ? 2 * stackmax : 64;                          \
            ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar));   \
            if (!ptr_) {                                                      \
                ok = JS_FALSE;                                                \
                goto done;                                                    \
            }                                                                 \
            stackbuf = ptr_;                                                  \
        }                                                                     \
        stackbuf[stacklen++] = (c);                                           \
    JS_END_MACRO

#define APPEND_STRING_TO_STACK(str)                                           \
    JS_BEGIN_MACRO                                                            \
        JSString *str_ = str;                                                 \
        size_t length_ = JSSTRING_LENGTH(str_);                               \
        if (stacklen + length_ > stackmax) {                                  \
            void *ptr_;                                                       \
            stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_));            \
            ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar));   \
            if (!ptr_) {                                                      \
                ok = JS_FALSE;                                                \
                goto done;                                                    \
            }                                                                 \
            stackbuf = ptr_;                                                  \
        }                                                                     \
        js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_);       \
        stacklen += length_;                                                  \
    JS_END_MACRO

    for (fp = cx->fp; fp; fp = fp->down) {
        if (checkAccess) {
            v = (fp->fun && fp->argv) ? fp->argv[-2] : JSVAL_NULL;
            if (!JSVAL_IS_PRIMITIVE(v)) {
                ok = checkAccess(cx, fp->fun->object, callerid, JSACC_READ, &v);
                if (!ok) {
                    ok = JS_TRUE;
                    break;
                }
            }
        }

        if (fp->fun) {
            if (fp->fun->atom)
                APPEND_STRING_TO_STACK(ATOM_TO_STRING(fp->fun->atom));

            APPEND_CHAR_TO_STACK('(');
            for (i = 0; i < fp->argc; i++) {
                /* Avoid toSource bloat and fallibility for object types. */
                v = fp->argv[i];
                if (JSVAL_IS_PRIMITIVE(v)) {
                    argsrc = js_ValueToSource(cx, v);
                } else if (JSVAL_IS_FUNCTION(cx, v)) {
                    /* XXX Avoid function decompilation bloat for now. */
                    argsrc = JS_GetFunctionId(JS_ValueToFunction(cx, v));
                    if (!argsrc)
                        argsrc = js_ValueToSource(cx, v);
                } else {
                    /* XXX Avoid toString on objects, it takes too long and
                           uses too much memory, for too many classes (see
                           Mozilla bug 166743). */
                    char buf[100];
                    JS_snprintf(buf, sizeof buf, "[object %s]",
                                OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v))->name);
                    argsrc = JS_NewStringCopyZ(cx, buf);
                }
                if (!argsrc) {
                    ok = JS_FALSE;
                    goto done;
                }
                if (i > 0)
                    APPEND_CHAR_TO_STACK(',');
                APPEND_STRING_TO_STACK(argsrc);
            }
            APPEND_CHAR_TO_STACK(')');
        }

        APPEND_CHAR_TO_STACK('@');
        if (fp->script && fp->script->filename) {
            for (cp = fp->script->filename; *cp; cp++)
                APPEND_CHAR_TO_STACK(*cp);
        }
        APPEND_CHAR_TO_STACK(':');
        if (fp->script && fp->pc) {
            ulineno = js_PCToLineNumber(fp->script, fp->pc);
            JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", ulineno);
            for (cp = ulnbuf; *cp; cp++)
                APPEND_CHAR_TO_STACK(*cp);
        } else {
            APPEND_CHAR_TO_STACK('0');
        }
        APPEND_CHAR_TO_STACK('\n');
    }

#undef APPEND_CHAR_TO_STACK
#undef APPEND_STRING_TO_STACK

done:
    if (checkAccess) {
        if (ok)
            JS_RestoreExceptionState(cx, state);
        else
            JS_DropExceptionState(cx, state);
        JS_SetErrorReporter(cx, older);
    }
    if (!ok) {
        JS_free(cx, stackbuf);
        return JS_FALSE;
    }

    if (!stackbuf) {
        stack = cx->runtime->emptyString;
    } else {
        /* NB: if stackbuf was allocated, it has room for the terminator. */
        JS_ASSERT(stacklen <= stackmax);
        if (stacklen < stackmax) {
            /*
             * Realloc can fail when shrinking on some FreeBSD versions, so
             * don't use JS_realloc here; simply let the oversized allocation
             * be owned by the string in that rare case.
             */
            void *shrunk = realloc(stackbuf, (stacklen+1) * sizeof(jschar));
            if (shrunk)
                stackbuf = shrunk;
        }
        stackbuf[stacklen] = 0;
        stack = js_NewString(cx, stackbuf, stacklen, 0);
        if (!stack) {
            JS_free(cx, stackbuf);
            return JS_FALSE;
        }
    }
    return JS_DefineProperty(cx, obj, js_stack_str,
                             STRING_TO_JSVAL(stack),
                             NULL, NULL, JSPROP_ENUMERATE);
}