Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    uintN i;
    JSString *str;
    const char *filename;
    JSScript *script;
    JSBool ok;
    jsval result;
    FILE *file;

    for (i = 0; i < argc; i++) {
        str = JS_ValueToString(cx, argv[i]);
        if (!str)
            return JS_FALSE;
        argv[i] = STRING_TO_JSVAL(str);
        filename = JS_GetStringBytes(str);
        file = fopen(filename, "r");
        script = JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
                                                   gJSPrincipals);
        if (!script)
            ok = JS_FALSE;
        else {
            ok = !compileOnly
                 ? JS_ExecuteScript(cx, obj, script, &result)
                 : JS_TRUE;
            JS_DestroyScript(cx, script);
        }
        if (!ok)
            return JS_FALSE;
    }
    return JS_TRUE;
}
JS_STATIC_DLL_CALLBACK(JSBool) js__load(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
{
    uintN i;
    JSString * str;
    const char * filename;
    JSScript * script;
    JSBool ok;
    jsval result;

    for (i = 0; i < argc; i++) {
        str = JS_ValueToString(cx, argv[i]);
        if (!str) return JS_FALSE;
        argv[i] = STRING_TO_JSVAL(str);
        filename = JS_GetStringBytes(str);
        script = JS_CompileFile(cx, obj, filename);
        if (!script) {
            ok = JS_FALSE;
        } else {
            ok = JS_ExecuteScript(cx, obj, script, &result);
            JS_DestroyScript(cx, script);
        }
        if (!ok) return JS_FALSE;
    }
    return JS_TRUE;
}
Exemple #3
0
/* Execute a string in its own context (away from Synchronet objects) */
static JSBool
js_eval(JSContext *parent_cx, JSObject *parent_obj, uintN argc, jsval *argv, jsval *rval)
{
    char*			buf;
    size_t			buflen;
    JSString*		str;
    JSScript*		script;
    JSContext*		cx;
    JSObject*		obj;
    JSErrorReporter	reporter;
#ifndef EVAL_BRANCH_CALLBACK
    JSBranchCallback callback;
#endif

    if(argc<1)
        return(JS_TRUE);

    if((str=JS_ValueToString(parent_cx, argv[0]))==NULL)
        return(JS_FALSE);
    if((buf=JS_GetStringBytes(str))==NULL)
        return(JS_FALSE);
    buflen=JS_GetStringLength(str);

    if((cx=JS_NewContext(JS_GetRuntime(parent_cx),JAVASCRIPT_CONTEXT_STACK))==NULL)
        return(JS_FALSE);

    /* Use the error reporter from the parent context */
    reporter=JS_SetErrorReporter(parent_cx,NULL);
    JS_SetErrorReporter(parent_cx,reporter);
    JS_SetErrorReporter(cx,reporter);

#ifdef EVAL_BRANCH_CALLBACK
    JS_SetContextPrivate(cx, JS_GetPrivate(parent_cx, parent_obj));
    JS_SetBranchCallback(cx, js_BranchCallback);
#else	/* Use the branch callback from the parent context */
    JS_SetContextPrivate(cx, JS_GetContextPrivate(parent_cx));
    callback=JS_SetBranchCallback(parent_cx,NULL);
    JS_SetBranchCallback(parent_cx, callback);
    JS_SetBranchCallback(cx, callback);
#endif

    if((obj=JS_NewObject(cx, NULL, NULL, NULL))==NULL
            || !JS_InitStandardClasses(cx,obj)) {
        JS_DestroyContext(cx);
        return(JS_FALSE);
    }

    if((script=JS_CompileScript(cx, obj, buf, buflen, NULL, 0))!=NULL) {
        JS_ExecuteScript(cx, obj, script, rval);
        JS_DestroyScript(cx, script);
    }

    JS_DestroyContext(cx);

    return(JS_TRUE);
}
char *sm_eval(jaegermonkey_vm *vm, const char *filename, const char *code, int handle_retval) {
  char *retval = NULL;
  JSScript *script;
  jsval result;

  begin_request(vm);
  script = JS_CompileScript(vm->context,
			    vm->global,
			    code, strlen(code),
			    filename, 1);
  jaegermonkey_error *error = (jaegermonkey_error *) JS_GetContextPrivate(vm->context);
  if (error == NULL) {
    JS_ClearPendingException(vm->context);
    JS_ExecuteScript(vm->context, vm->global, script, &result);
    vm->invoke_count++;
    error = (jaegermonkey_error *) JS_GetContextPrivate(vm->context);
    if (error == NULL) {
      if (handle_retval) {
	if (JSVAL_IS_STRING(result)) {
	  JSString *str = JS_ValueToString(vm->context, result);
	  retval = copy_jsstring(str);
	}
	else if(strcmp(JS_GetStringBytes(JS_ValueToString(vm->context, result)), "undefined") == 0) {
	  retval = copy_string("{\"error\": \"Expression returned undefined\", \"lineno\": 0, \"source\": \"unknown\"}");
	}
	else {
	  retval = copy_string("{\"error\": \"non-JSON return value\", \"lineno\": 0, \"source\": \"unknown\"}");
	}
      }
      JS_DestroyScript(vm->context, script);
    }
    else {
      retval = error_to_json(error);
      free_error(error);
      JS_SetContextPrivate(vm->context, NULL);
    }
  }
  else {
    retval = error_to_json(error);
    free_error(error);
    JS_SetContextPrivate(vm->context, NULL);
  }
  if (vm->invoke_count > 200) {
    JS_GC(vm->context);
    vm->invoke_count = 0;
  }
  else {
    JS_MaybeGC(vm->context);
  }

  end_request(vm);
  return retval;
}
JSBool systemInclude(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{// begin systemInclude
	// default return value
	*rval = BOOLEAN_TO_JSVAL(false);
	if(argc != 1)
		return JS_FALSE;
	if(JSVAL_IS_STRING(argv[0]) == false)
		return JS_FALSE;

	struct stat sbFileInfo;
	const char *pIncludeFile = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
	// make sure we haven't included this already to avoid a recursive
	// dependency loop
	char *pTempStr = new char[PATH_MAX+1];
	if(realpath(pIncludeFile,pTempStr) == NULL)
	{// begin can't resolve path
		JS_ReportError(cx, "include() can't resolve the path of \"%s\".", pIncludeFile);
		return JS_FALSE;
	}// end can't resolve path

	std::string sRealPath = pTempStr;
	if(stat(sRealPath.c_str() , &sbFileInfo) != 0)
	{// begin can't stat file
		JS_ReportError(cx, "include() Can't stat \"%s\" errno(%i).", sRealPath.c_str(), errno);
		return JS_FALSE;
	}// end can't stat file

	for(int i = 0;i < g_vIncludes.size();i++)
	{// begin check previous includes
		if(g_vIncludes[i] == sRealPath)
		{// begin found
			printf("include() Warning: Duplicated include of \"%s\"...ignoring.\n",sRealPath.c_str());
			return JS_TRUE;
		}// end found
	}// end check previous includes
	g_vIncludes.push_back(sRealPath);

	JSScript *pJSScript = JS_CompileFile(cx, obj, sRealPath.c_str());
	jsval lastRval;
	if(pJSScript != NULL)
	{// begin execute external file
		JSBool ok = JS_ExecuteScript(cx, obj, pJSScript, &lastRval);
		JS_DestroyScript(cx,pJSScript);
		*rval = BOOLEAN_TO_JSVAL(ok);
	}// end execute external file
	else
	{// begin error including
		JS_ReportError(cx, "include() Cannot compile file \"%s\"", pIncludeFile);
		return JS_FALSE;
	}// end error including
	return JS_TRUE;
}// end systemInclude
Exemple #6
0
void js_usescript_gc(JSContext *cx, JSObject *obj) {
  func("%u:%s:%s",__LINE__,__FILE__,__FUNCTION__);
  JSScript *script;
  void *p = JS_GetInstancePrivate(cx, obj, &UseScriptClass, NULL);
  if(!p)
    return;

  script = (JSScript*)p;
  notice("destroy script %p of %p", script, obj);
  JS_SetPrivate(cx, obj, NULL);
  JS_ClearScope(cx, obj);
  JS_DestroyScript(cx, script);
}
Exemple #7
0
void DLLCALL js_EvalOnExit(JSContext *cx, JSObject *obj, js_branch_t* branch)
{
    char*	p;
    jsval	rval;
    JSScript* script;

    while((p=strListPop(&branch->exit_func))!=NULL) {
        if((script=JS_CompileScript(cx, obj, p, strlen(p), NULL, 0))!=NULL) {
            JS_ExecuteScript(cx, obj, script, &rval);
            JS_DestroyScript(cx, script);
        }
    }

    strListFree(&branch->exit_func);
}
Exemple #8
0
NS_IMETHODIMP nsJSSh::ExecuteBuffer()
{
#ifdef DEBUG
//     nsCOMPtr<nsIThread> thread;
//     nsIThread::GetCurrent(getter_AddRefs(thread));
//     printf("executing on thread %p\n", thread.get());
#endif

  JS_BeginRequest(mJSContext);
  JS_ClearPendingException(mJSContext);
  JSPrincipals *jsprincipals;
  mPrincipal->GetJSPrincipals(mJSContext, &jsprincipals);

  if(NS_FAILED(mContextStack->Push(mJSContext))) {
    NS_ERROR("failed to push the current JSContext on the nsThreadJSContextStack");
    return NS_ERROR_FAILURE;
  }
  
  JSScript *script = JS_CompileScriptForPrincipals(mJSContext, mContextObj, jsprincipals, mBuffer, mBufferPtr, "interactive", 0);

  if (script) {
    jsval result;
    if (JS_ExecuteScript(mJSContext, mContextObj, script, &result) && result!=JSVAL_VOID && mOutput) {
      // XXX for some wrapped native objects the following code will crash; probably because the
      // native object is getting released before we reach this:
       JSString *str = JS_ValueToString(mJSContext, result);
       if (str) {
         nsDependentString chars(reinterpret_cast<const PRUnichar*>
                                 (JS_GetStringChars(str)),
                                 JS_GetStringLength(str));
         NS_ConvertUTF16toUTF8 cstr(chars);
         PRUint32 bytesWritten;
         mOutput->Write(cstr.get(), cstr.Length(), &bytesWritten);
       }
    }
    JS_DestroyScript(mJSContext, script);
  }

  JSContext *oldcx;
  mContextStack->Pop(&oldcx);
  NS_ASSERTION(oldcx == mJSContext, "JS thread context push/pop mismatch");

  JSPRINCIPALS_DROP(mJSContext, jsprincipals);
  
  JS_EndRequest(mJSContext);
  
  return NS_OK;
}
bool parseECMAScript(const char *name)
{// begin parseECMAScript
	jsval rval;
	uintN lineno = 0;
        jscu=0;
	printf("Spidermonkey compiling \"%s\"\n",name);
	JSScript *pJSScript = JS_CompileFile(g_pCx, g_pObject, name);
	if(pJSScript != NULL)
	{// begin execute external file
		printf("Spidermonkey executing \"%s\"\n",name);
		JSBool ok = JS_ExecuteScript(g_pCx, g_pObject, pJSScript, &rval);
		JS_DestroyScript(g_pCx,pJSScript);
	}// end execute external file
        A_Resync();
        return jscu;
                        
}// end parseECMAScript
bool parseECMAScript(const char *name)
{// begin parseECMAScript
	jsval rval;
	uintN lineno = 0;
	g_bJSSuccess = 0;
	printf("Spidermonkey compiling \"%s\"...",name);

	FILE *file = fopen(name, "r");
	JSScript *pJSScript = JS_CompileFileHandle(g_pCx, g_pObject, name, file);;
#warning potential leak here
/*
In normal operation the file is closed by 
JS_CompileFileHandle (jsapi.c:3772)
JS_CompileFileHandleForPrincipals (jsapi.c:3795)
CompileTokenStream (jsapi.c:3609)
js_CloseTokenStream (jsscan.c:322)
*/
	/* DOUBLE CLOSE fclose(file); */
	printf("Done.\n");

	if(pJSScript != NULL)
	{// begin execute external file
		char curDir[PATH_MAX + 1];
		char scriptPath[strlen(name) + 1];

		strcpy(scriptPath, name);
		ADM_PathStripName(scriptPath);
		getcwd(curDir, PATH_MAX);
		chdir(scriptPath);

		printf("Spidermonkey executing \"%s\"...",name);
		JSBool ok = JS_ExecuteScript(g_pCx, g_pObject, pJSScript, &rval);
		JS_DestroyScript(g_pCx,pJSScript);
		printf("Done.\n");

		chdir(curDir);
	}// end execute external file
        // Run garbage collector now, it is safe
        JS_GC(g_pCx);
	A_Resync();
	return g_bJSSuccess;
}// end parseECMAScript
Exemple #11
0
long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* scope)
{
	char*		p;
	char*		args=NULL;
	char*		fname;
	int			argc=0;
	char		cmdline[MAX_PATH+1];
	char		path[MAX_PATH+1];
	JSObject*	js_scope=scope;
	JSObject*	js_script=NULL;
	jsval		rval;
	int32		result=0;

	if(js_cx==NULL) {
		errormsg(WHERE,ERR_CHK,"JavaScript support",0);
		errormsg(WHERE,ERR_EXEC,cmd,0);
		return -1;
	}

	SAFECOPY(cmdline,cmd);
	p=strchr(cmdline,' ');
	if(p!=NULL) {
		*p=0;
		args=p+1;
	}
	fname=cmdline;

	path[0]=0;
	if(strcspn(fname,"/\\")==strlen(fname)) {
		if(startup_dir!=NULL && *startup_dir)
			SAFEPRINTF3(path,"%s%s%s",startup_dir,fname,js_ext(fname));
		if(path[0]==0 || !fexistcase(path)) {
			SAFEPRINTF3(path,"%s%s%s",cfg.mods_dir,fname,js_ext(fname));
			if(cfg.mods_dir[0]==0 || !fexistcase(path))
				SAFEPRINTF3(path,"%s%s%s",cfg.exec_dir,fname,js_ext(fname));
		}
	} else
		SAFECOPY(path,fname);

	if(!fexistcase(path)) {
		errormsg(WHERE,ERR_OPEN,path,O_RDONLY);
		return -1;
	}

	JS_BEGINREQUEST(js_cx);
	if(js_scope==NULL)
		js_scope=JS_NewObject(js_cx, NULL, NULL, js_glob);

	if(js_scope!=NULL) {

		JSObject* argv=JS_NewArrayObject(js_cx, 0, NULL);

		JS_DefineProperty(js_cx, js_scope, "argv", OBJECT_TO_JSVAL(argv)
			,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);

		/* TODO: Handle quoted "one arg" syntax here? */
		if(args!=NULL && argv!=NULL) {
			while(*args) {
				p=strchr(args,' ');
				if(p!=NULL)
					*p=0;
				while(*args && *args==' ') args++; /* Skip spaces */
				JSString* arg = JS_NewStringCopyZ(js_cx, args);
				if(arg==NULL)
					break;
				jsval val=STRING_TO_JSVAL(arg);
				if(!JS_SetElement(js_cx, argv, argc, &val))
					break;
				argc++;
				if(p==NULL)	/* last arg */
					break;
				args+=(strlen(args)+1);
			}
		}
		JS_DefineProperty(js_cx, js_scope, "argc", INT_TO_JSVAL(argc)
			,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);

		JS_ClearPendingException(js_cx);

		js_script=JS_CompileFile(js_cx, js_scope, path);
	}

	if(js_scope==NULL || js_script==NULL) {
		JS_ReportPendingException(js_cx);	/* Added Feb-2-2006, rswindell */
		JS_ENDREQUEST(js_cx);
		errormsg(WHERE,"compiling",path,0);
		return -1;
	}

	if(scope==NULL) {
		js_callback.counter=0;	// Reset loop counter

#if JS_VERSION>180
		JS_SetOperationCallback(js_cx, js_OperationCallback);
#else
		JS_SetBranchCallback(js_cx, js_BranchCallback);
#endif

		js_PrepareToExecute(js_cx, js_glob, path, startup_dir);
	}
	JS_ExecuteScript(js_cx, js_scope, js_script, &rval);

	if(scope==NULL) {
		JS_GetProperty(js_cx, js_scope, "exit_code", &rval);
		if(rval!=JSVAL_VOID)
			JS_ValueToInt32(js_cx,rval,&result);

		js_EvalOnExit(js_cx, js_scope, &js_callback);
	}

	JS_ReportPendingException(js_cx);	/* Added Dec-4-2005, rswindell */

	JS_DestroyScript(js_cx, js_script);

	if(scope==NULL)
		JS_ClearScope(js_cx, js_scope);

	JS_GC(js_cx);

	JS_ENDREQUEST(js_cx);

	return(result);
}
static void
ProcessFile(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
            JSBool forceTTY)
{
    JSScript *script;
    jsval result;
    int lineno, startline;
    JSBool ok, hitEOF;
    char *bufp, buffer[4096];
    JSString *str;

    if (forceTTY) {
        file = stdin;
    } else if (!isatty(fileno(file))) {
        /*
         * It's not interactive - just execute it.
         *
         * Support the UNIX #! shell hack; gobble the first line if it starts
         * with '#'.  TODO - this isn't quite compatible with sharp variables,
         * as a legal js program (using sharp variables) might start with '#'.
         * But that would require multi-character lookahead.
         */
        int ch = fgetc(file);
        if (ch == '#') {
            while((ch = fgetc(file)) != EOF) {
                if(ch == '\n' || ch == '\r')
                    break;
            }
        }
        ungetc(ch, file);
        DoBeginRequest(cx);

        script = JS_CompileFileHandleForPrincipals(cx, obj, filename, file,
                                                   gJSPrincipals);

        if (script) {
            if (!compileOnly)
                (void)JS_ExecuteScript(cx, obj, script, &result);
            JS_DestroyScript(cx, script);
        }
        DoEndRequest(cx);

        return;
    }

    /* It's an interactive filehandle; drop into read-eval-print loop. */
    lineno = 1;
    hitEOF = JS_FALSE;
    do {
        bufp = buffer;
        *bufp = '\0';

        /*
         * Accumulate lines until we get a 'compilable unit' - one that either
         * generates an error (before running out of source) or that compiles
         * cleanly.  This should be whenever we get a complete statement that
         * coincides with the end of a line.
         */
        startline = lineno;
        do {
            if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
                hitEOF = JS_TRUE;
                break;
            }
            bufp += strlen(bufp);
            lineno++;
        } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
        
        DoBeginRequest(cx);
        /* Clear any pending exception from previous failed compiles.  */
        JS_ClearPendingException(cx);
        script = JS_CompileScriptForPrincipals(cx, obj, gJSPrincipals, buffer,
                                               strlen(buffer), "typein", startline);
        if (script) {
            JSErrorReporter older;

            if (!compileOnly) {
                ok = JS_ExecuteScript(cx, obj, script, &result);
                if (ok && result != JSVAL_VOID) {
                    /* Suppress error reports from JS_ValueToString(). */
                    older = JS_SetErrorReporter(cx, NULL);
                    str = JS_ValueToString(cx, result);
                    JS_SetErrorReporter(cx, older);
    
                    if (str)
                        fprintf(gOutFile, "%s\n", JS_GetStringBytes(str));
                    else
                        ok = JS_FALSE;
                }
            }
            JS_DestroyScript(cx, script);
        }
        DoEndRequest(cx);
    } while (!hitEOF && !gQuitting);

    fprintf(gOutFile, "\n");
}
PRBool CreateFakeBrowserWindow(JSContext* cx, JSObject* parent, nsIPrincipal* systemPrincipal) {
  nsresult rv;
  jsval value;

  nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
  if (xpc == nsnull) {
    JS_ReportError(cx, "Adblock Plus: Coult not retrieve nsIXPConnect - wrong Gecko version?");
    return PR_FALSE;
  }
  rv = xpc->FlagSystemFilenamePrefix("adblockplus.dll/");
  if (NS_FAILED(rv)) {
    JS_ReportError(cx, "Adblock Plus: Failed to enable protection for inline JavaScript");
    return PR_FALSE;
  }

  JSObject* obj = JS_NewObject(cx, nsnull, nsnull, parent);
  if (obj == nsnull) {
    JS_ReportError(cx, "Adblock Plus: Failed to create fake browser window object - out of memory?");
    return PR_FALSE;
  }
  JS_SetGlobalObject(cx, obj);

  // Have to loop through the methods manually because JS_DefineFunctions won't do anything for some reason
  for (JSFunctionSpec *fs = window_methods; fs->name; fs++) {
    JSFunction *fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, fs->flags);
    if (!fun) {
      JS_ReportError(cx, "Adblock Plus: Failed to attach native methods to fake browser window");
      return PR_FALSE;
    }
  }

  if (!JS_DefineProperties(cx, obj, window_properties)) {
    JS_ReportError(cx, "Adblock Plus: Failed to attach native properties to fake browser window");
    return PR_FALSE;
  }

  JSPrincipals* principals;
  rv = systemPrincipal->GetJSPrincipals(cx, &principals);
  if (NS_FAILED(rv)) {
    JS_ReportError(cx, "Adblock Plus: Could not convert system principal into JavaScript principals");
    return PR_FALSE;
  }

  for (int i = 0; includes[i]; i += 2) {
    JSScript* inlineScript = JS_CompileScriptForPrincipals(cx, obj, principals, includes[i+1], strlen(includes[i+1]), includes[i], 1);
    if (inlineScript == nsnull) {
      JS_ReportError(cx, "Adblock Plus: Failed to compile %s", includes[i]);
      return PR_FALSE;
    }

    if (!JS_ExecuteScript(cx, obj, inlineScript, &value)) {
      JS_ReportError(cx, "Adblock Plus: Failed to execute %s", includes[i]);
      return PR_FALSE;
    }
    JS_DestroyScript(cx, inlineScript);
  }
  JSPRINCIPALS_DROP(cx, principals);

  nsCOMPtr<nsISupports> wrapped;
  rv = xpc->WrapJS(cx, obj, NS_GET_IID(nsISupports), getter_AddRefs(wrapped));
  if (NS_FAILED(rv)) {
    JS_ReportError(cx, "Adblock Plus: Failed to create XPConnect wrapper for fake browser window");
    return PR_FALSE;
  }

  fakeBrowserWindow = do_QueryInterface(wrapped);
  if (fakeBrowserWindow == nsnull) {
    JS_ReportError(cx, "Adblock Plus: Failed to QI fake browser window");
    return PR_FALSE;
  }

  jsval readerVal;
  JS_GetProperty(cx, obj, "_dtdReader", &readerVal);
  if (readerVal == JSVAL_VOID) {
    JS_ReportError(cx, "Adblock Plus: Failed to retrieve DTD reader object");
    return PR_FALSE;
  }

  JSObject* reader = JSVAL_TO_OBJECT(readerVal);
  for (int i = 0; i < NUM_LABELS; i++) {
    JSString* str = JS_NewStringCopyZ(cx, context_labels[i]);
    if (str == nsnull) {
      JS_ReportError(cx, "Adblock Plus: Could not create JavaScript string for '%s' - out of memory?", context_labels[i]);
      return PR_FALSE;
    }

    jsval args[] = {STRING_TO_JSVAL(str)};
    jsval retval;
    if (!JS_CallFunctionName(cx, reader, "getEntity", 1, args, &retval)) {
      JS_ReportError(cx, "Adblock Plus: Failed to retrieve entity '%s' from overlay.dtd", context_labels[i]);
      return PR_FALSE;
    }

    str = JS_ValueToString(cx, retval);
    if (str == nsnull) {
      JS_ReportError(cx, "Adblock Plus: Could not convert return value of _dtdReader.getEntity() to string");
      return PR_FALSE;
    }

    strcpy_s(labelValues[i], sizeof(labelValues[i]), JS_GetStringBytes(str));
  }

  return PR_TRUE;
}
Exemple #14
0
static JSBool
obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    JSStackFrame *fp, *caller;
    JSBool ok;
    JSString *str;
    const char *file;
    uintN line;
    JSPrincipals *principals;
    JSScript *script;
#if JS_HAS_EVAL_THIS_SCOPE
    JSObject *callerScopeChain;
    JSBool implicitWith;
#endif

    if (!JSVAL_IS_STRING(argv[0])) {
	*rval = argv[0];
	return JS_TRUE;
    }

    fp = cx->fp;
    caller = fp->down;
#if !JS_BUG_EVAL_THIS_FUN
    /* Ensure that this flows into eval from the calling function, if any. */
    fp->thisp = caller->thisp;
#endif
#if JS_HAS_SHARP_VARS
    fp->sharpArray = caller->sharpArray;
#endif

#if JS_HAS_EVAL_THIS_SCOPE
    /* If obj.eval(str), emulate 'with (obj) eval(str)' in the calling frame. */
    callerScopeChain = caller->scopeChain;
    implicitWith = (callerScopeChain != obj &&
		    (callerScopeChain->map->clasp != &js_WithClass ||
		     OBJ_GET_PROTO(callerScopeChain) != obj));
    if (implicitWith) {
	obj = js_NewObject(cx, &js_WithClass, obj, callerScopeChain);
	if (!obj)
	    return JS_FALSE;
	caller->scopeChain = obj;
    }
#endif

#if !JS_BUG_EVAL_THIS_SCOPE
    /* Compile using caller's current scope object (might be a function). */
    obj = caller->scopeChain;
#endif

    str = JSVAL_TO_STRING(argv[0]);
    if (caller->script) {
	file = caller->script->filename;
	line = js_PCToLineNumber(caller->script, caller->pc);
	principals = caller->script->principals;
    } else {
	file = NULL;
	line = 0;
	principals = NULL;
    }
    script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
					     str->chars, str->length,
					     file, line);
    if (!script) {
	ok = JS_FALSE;
	goto out;
    }

#if !JS_BUG_EVAL_THIS_SCOPE
    /* Interpret using caller's new scope object (might be a Call object). */
    obj = caller->scopeChain;
#endif
    ok = js_Execute(cx, obj, script, fp, rval);
    JS_DestroyScript(cx, script);

out:
#if JS_HAS_EVAL_THIS_SCOPE
    if (implicitWith) {
	/* Restore OBJ_GET_PARENT(obj) not callerScopeChain in case of Call. */
	caller->scopeChain = OBJ_GET_PARENT(obj);
    }
#endif
    return ok;
}