/* -*- 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/. *//* JS shell. */#include"mozilla/ArrayUtils.h"#include"mozilla/Atomics.h"#include"mozilla/DebugOnly.h"#include"mozilla/GuardObjects.h"#include"mozilla/PodOperations.h"#ifdef XP_WIN# include <direct.h># include <process.h>#endif#include<errno.h>#include<fcntl.h>#if defined(XP_WIN)# include <io.h> /* for isatty() */#endif#include<locale.h>#if defined(MALLOC_H)# include MALLOC_H /* for malloc_usable_size, malloc_size, _msize */#endif#include<math.h>#include<signal.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/stat.h>#include<sys/types.h>#ifdef XP_UNIX# include <sys/mman.h># include <sys/stat.h># include <sys/wait.h># include <unistd.h>#endif#include"jsapi.h"#include"jsarray.h"#include"jsatom.h"#include"jscntxt.h"#include"jsfun.h"#include"jslock.h"#include"jsobj.h"#include"jsprf.h"#include"jsscript.h"#include"jstypes.h"#include"jsutil.h"#ifdef XP_WIN# include "jswin.h"#endif#include"jswrapper.h"#include"prmjtime.h"#include"builtin/TestingFunctions.h"#include"frontend/Parser.h"#include"jit/arm/Simulator-arm.h"#include"jit/Ion.h"#include"js/Debug.h"#include"js/GCAPI.h"#include"js/StructuredClone.h"#include"perf/jsperf.h"#include"shell/jsheaptools.h"#include"shell/jsoptparse.h"#include"shell/OSObject.h"#include"vm/ArgumentsObject.h"#include"vm/Debugger.h"#include"vm/HelperThreads.h"#include"vm/Monitor.h"#include"vm/Shape.h"#include"vm/TypedArrayObject.h"#include"vm/WrapperObject.h"#include"jscompartmentinlines.h"#include"jsobjinlines.h"#include"vm/Interpreter-inl.h"#include"vm/Stack-inl.h"#ifdef XP_WIN# define PATH_MAX (MAX_PATH > _MAX_DIR ? MAX_PATH : _MAX_DIR)#else# include <libgen.h>#endifusingnamespacejs;usingnamespacejs::cli;usingmozilla::ArrayLength;usingmozilla::MakeUnique;usingmozilla::Maybe;usingmozilla::NumberEqualsInt32;usingmozilla::PodCopy;usingmozilla::PodEqual;usingmozilla::UniquePtr;enumJSShellExitCode{EXITCODE_RUNTIME_ERROR=3,EXITCODE_FILE_NOT_FOUND=4,EXITCODE_OUT_OF_MEMORY=5,EXITCODE_TIMEOUT=6};enumPathResolutionMode{RootRelative,ScriptRelative};staticsize_tgStackChunkSize=8192;/* * Note: This limit should match the stack limit set by the browser in * js/xpconnect/src/XPCJSRuntime.cpp */#if defined(MOZ_ASAN) || (defined(DEBUG) && !defined(XP_WIN))staticsize_tgMaxStackSize=2*128*sizeof(size_t)*1024;#elsestaticsize_tgMaxStackSize=128*sizeof(size_t)*1024;#endif/* * Limit the timeout to 30 minutes to prevent an overflow on platfoms * that represent the time internally in microseconds using 32-bit int. */staticdoubleMAX_TIMEOUT_INTERVAL=1800.0;staticdoublegTimeoutInterval=-1.0;staticvolatileboolgServiceInterrupt=false;staticJS::PersistentRootedValuegInterruptFunc;staticboolenableDisassemblyDumps=false;staticboolprintTiming=false;staticconstchar*jsCacheDir=nullptr;staticconstchar*jsCacheAsmJSPath=nullptr;staticbooljsCachingEnabled=false;mozilla::Atomic<bool>jsCacheOpened(false);staticboolSetTimeoutValue(JSContext*cx,doublet);staticboolInitWatchdog(JSRuntime*rt);staticvoidKillWatchdog();staticboolScheduleWatchdog(JSRuntime*rt,doublet);staticvoidCancelExecution(JSRuntime*rt);/* * Watchdog thread state. */staticPRLock*gWatchdogLock=nullptr;staticPRCondVar*gWatchdogWakeup=nullptr;staticPRThread*gWatchdogThread=nullptr;staticboolgWatchdogHasTimeout=false;staticint64_tgWatchdogTimeout=0;staticPRCondVar*gSleepWakeup=nullptr;staticintgExitCode=0;staticboolgQuitting=false;staticboolgGotError=false;staticFILE*gErrFile=nullptr;staticFILE*gOutFile=nullptr;staticboolreportWarnings=true;staticboolcompileOnly=false;staticboolfuzzingSafe=false;#ifdef DEBUGstaticbooldumpEntrainedVariables=false;staticboolOOM_printAllocationCount=false;#endifenumJSShellErrNum{#define MSG_DEF(name, count, exception, format) \ name,#include"jsshell.msg"#undef MSG_DEFJSShellErr_Limit};staticJSContext*NewContext(JSRuntime*rt);staticvoidDestroyContext(JSContext*cx,boolwithGC);staticJSObject*NewGlobalObject(JSContext*cx,JS::CompartmentOptions&options,JSPrincipals*principals);staticconstJSErrorFormatString*my_GetErrorMessage(void*userRef,constunsignederrorNumber);staticvoidmy_ErrorReporter(JSContext*cx,constchar*message,JSErrorReport*report);/* * A toy principals type for the shell. * * In the shell, a principal is simply a 32-bit mask: P subsumes Q if the * set bits in P are a superset of those in Q. Thus, the principal 0 is * subsumed by everything, and the principal ~0 subsumes everything. * * As a special case, a null pointer as a principal is treated like 0xffff. * * The 'newGlobal' function takes an option indicating which principal the * new global should have; 'evaluate' does for the new code. */classShellPrincipals:publicJSPrincipals{uint32_tbits;staticuint32_tgetBits(JSPrincipals*p){if(!p)return0xffff;returnstatic_cast<ShellPrincipals*>(p)->bits;}public:explicitShellPrincipals(uint32_tbits,int32_trefcount=0):bits(bits){this->refcount=refcount;}staticvoiddestroy(JSPrincipals*principals){MOZ_ASSERT(principals!=&fullyTrusted);MOZ_ASSERT(principals->refcount==0);js_free(static_cast<ShellPrincipals*>(principals));}staticboolsubsumes(JSPrincipals*first,JSPrincipals*second){uint32_tfirstBits=getBits(first);uint32_tsecondBits=getBits(second);return(firstBits|secondBits)==firstBits;}staticJSSecurityCallbackssecurityCallbacks;// Fully-trusted principals singleton.staticShellPrincipalsfullyTrusted;};JSSecurityCallbacksShellPrincipals::securityCallbacks={nullptr,// contentSecurityPolicyAllowssubsumes};// The fully-trusted principal subsumes all other principals.ShellPrincipalsShellPrincipals::fullyTrusted(-1,1);#ifdef EDITLINEextern"C"{externJS_EXPORT_API(char*)readline(constchar*prompt);externJS_EXPORT_API(void)add_history(char*line);}// extern "C"#endifstaticchar*GetLine(FILE*file,constchar*prompt){size_tsize;char*buffer;#ifdef EDITLINE/* * Use readline only if file is stdin, because there's no way to specify * another handle. Are other filehandles interactive? */if(file==stdin){char*linep=readline(prompt);/* * We set it to zero to avoid complaining about inappropriate ioctl * for device in the case of EOF. Looks like errno == 251 if line is * finished with EOF and errno == 25 (EINVAL on Mac) if there is * nothing left to read. */if(errno==251||errno==25||errno==EINVAL)errno=0;if(!linep)returnnullptr;if(linep[0]!='\0')add_history(linep);returnlinep;}#endifsize_tlen=0;if(*prompt!='\0'){fprintf(gOutFile,"%s",prompt);fflush(gOutFile);}size=80;buffer=(char*)malloc(size);if(!buffer)returnnullptr;char*current=buffer;while(fgets(current,size-len,file)){len+=strlen(current);char*t=buffer+len-1;if(*t=='\n'){/* Line was read. We remove '\n' and exit. */*t='\0';returnbuffer;}if(len+1==size){size=size*2;char*tmp=(char*)js_realloc(buffer,size);if(!tmp){free(buffer);returnnullptr;}buffer=tmp;}current=buffer+len;}if(len&&!ferror(file))returnbuffer;free(buffer);returnnullptr;}/* State to store as JSContext private. */structJSShellContextData{/* Creation timestamp, used by the elapsed() shell builtin. */int64_tstartTime;};staticJSShellContextData*NewContextData(){JSShellContextData*data=(JSShellContextData*)js_calloc(sizeof(JSShellContextData),1);if(!data)returnnullptr;data->startTime=PRMJ_Now();returndata;}staticinlineJSShellContextData*GetContextData(JSContext*cx){JSShellContextData*data=(JSShellContextData*)JS_GetContextPrivate(cx);MOZ_ASSERT(data);returndata;}staticboolShellInterruptCallback(JSContext*cx){if(!gServiceInterrupt)returntrue;// Reset gServiceInterrupt. CancelExecution or InterruptIf will set it to// true to distinguish watchdog or user triggered interrupts.// Do this first to prevent other interrupts that may occur while the// user-supplied callback is executing from re-entering the handler.gServiceInterrupt=false;boolresult;RootedValueinterruptFunc(cx,gInterruptFunc);if(!interruptFunc.isNull()){JS::AutoSaveExceptionStatesavedExc(cx);JSAutoCompartmentac(cx,&interruptFunc.toObject());RootedValuerval(cx);if(!JS_CallFunctionValue(cx,JS::NullPtr(),interruptFunc,JS::HandleValueArray::empty(),&rval)){returnfalse;}if(rval.isBoolean())result=rval.toBoolean();elseresult=false;}else{result=false;}if(!result&&gExitCode==0)gExitCode=EXITCODE_TIMEOUT;returnresult;}/* * Some UTF-8 files, notably those written using Notepad, have a Unicode * Byte-Order-Mark (BOM) as their first character. This is useless (byte-order * is meaningless for UTF-8) but causes a syntax error unless we skip it. */staticvoidSkipUTF8BOM(FILE*file){intch1=fgetc(file);intch2=fgetc(file);intch3=fgetc(file);// Skip the BOMif(ch1==0xEF&&ch2==0xBB&&ch3==0xBF)return;// No BOM - revertif(ch3!=EOF)ungetc(ch3,file);if(ch2!=EOF)ungetc(ch2,file);if(ch1!=EOF)ungetc(ch1,file);}staticvoidRunFile(JSContext*cx,Handle<JSObject*>obj,constchar*filename,FILE*file,boolcompileOnly){SkipUTF8BOM(file);// To support the UNIX #! shell hack, gobble the first line if it starts// with '#'.intch=fgetc(file);if(ch=='#'){while((ch=fgetc(file))!=EOF){if(ch=='\n'||ch=='\r')break;}}ungetc(ch,file);int64_tt1=PRMJ_Now();RootedScriptscript(cx);{CompileOptionsoptions(cx);options.setIntroductionType("js shell file").setUTF8(true).setFileAndLine(filename,1).setCompileAndGo(true).setNoScriptRval(true);gGotError=false;(void)JS::Compile(cx,obj,options,file,&script);MOZ_ASSERT_IF(!script,gGotError);}#ifdef DEBUGif(dumpEntrainedVariables)AnalyzeEntrainedVariables(cx,script);#endifif(script&&!compileOnly){if(!JS_ExecuteScript(cx,obj,script)){if(!gQuitting&&gExitCode!=EXITCODE_TIMEOUT)gExitCode=EXITCODE_RUNTIME_ERROR;}int64_tt2=PRMJ_Now()-t1;if(printTiming)printf("runtime = %.3f ms\n",double(t2)/PRMJ_USEC_PER_MSEC);}}staticboolEvalAndPrint(JSContext*cx,Handle<JSObject*>global,constchar*bytes,size_tlength,intlineno,boolcompileOnly,FILE*out){// Eval.JS::CompileOptionsoptions(cx);options.setIntroductionType("js shell interactive").setUTF8(true).setCompileAndGo(true).setFileAndLine("typein",lineno);RootedScriptscript(cx);if(!JS::Compile(cx,global,options,bytes,length,&script))returnfalse;if(compileOnly)returntrue;RootedValueresult(cx);if(!JS_ExecuteScript(cx,global,script,&result))returnfalse;if(!result.isUndefined()){// Print.RootedStringstr(cx);str=JS_ValueToSource(cx,result);if(!str)returnfalse;char*utf8chars=JS_EncodeStringToUTF8(cx,str);if(!utf8chars)returnfalse;fprintf(out,"%s\n",utf8chars);JS_free(cx,utf8chars);}returntrue;}staticvoidReadEvalPrintLoop(JSContext*cx,Handle<JSObject*>global,FILE*in,FILE*out,boolcompileOnly){intlineno=1;boolhitEOF=false;do{/* * 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. */intstartline=lineno;typedefVector<char,32>CharBuffer;CharBufferbuffer(cx);do{ScheduleWatchdog(cx->runtime(),-1);gServiceInterrupt=false;errno=0;char*line=GetLine(in,startline==lineno?"js> ":"");if(!line){if(errno){JS_ReportError(cx,strerror(errno));return;}hitEOF=true;break;}if(!buffer.append(line,strlen(line))||!buffer.append('\n'))return;lineno++;if(!ScheduleWatchdog(cx->runtime(),gTimeoutInterval)){hitEOF=true;break;}}while(!JS_BufferIsCompilableUnit(cx,global,buffer.begin(),buffer.length()));if(hitEOF&&buffer.empty())break;if(!EvalAndPrint(cx,global,buffer.begin(),buffer.length(),startline,compileOnly,out)){// Catch the error, report it, and keep going.JS_ReportPendingException(cx);}}while(!hitEOF&&!gQuitting);fprintf(out,"\n");}classAutoCloseInputFile{private:FILE*f_;public:explicitAutoCloseInputFile(FILE*f):f_(f){}~AutoCloseInputFile(){if(f_&&f_!=stdin)fclose(f_);}};staticvoidProcess(JSContext*cx,JSObject*obj_,constchar*filename,boolforceTTY){RootedObjectobj(cx,obj_);FILE*file;if(forceTTY||!filename||strcmp(filename,"-")==0){file=stdin;}else{file=fopen(filename,"r");if(!file){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_CANT_OPEN,filename,strerror(errno));gExitCode=EXITCODE_FILE_NOT_FOUND;return;}}AutoCloseInputFileautoClose(file);if(!forceTTY&&!isatty(fileno(file))){// It's not interactive - just execute it.RunFile(cx,obj,filename,file,compileOnly);}else{// It's an interactive filehandle; drop into read-eval-print loop.ReadEvalPrintLoop(cx,obj,file,gOutFile,compileOnly);}}staticboolVersion(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);JSVersionorigVersion=JS_GetVersion(cx);if(args.length()==0||args[0].isUndefined()){/* Get version. */args.rval().setInt32(origVersion);}else{/* Set version. */int32_tv=-1;if(args[0].isInt32()){v=args[0].toInt32();}elseif(args[0].isDouble()){doublefv=args[0].toDouble();int32_tfvi;if(NumberEqualsInt32(fv,&fvi))v=fvi;}if(v<0||v>JSVERSION_LATEST){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"version");returnfalse;}JS_SetVersionForCompartment(js::GetContextCompartment(cx),JSVersion(v));args.rval().setInt32(origVersion);}returntrue;}/* * Resolve a (possibly) relative filename to an absolute path. If * |scriptRelative| is true, then the result will be relative to the directory * containing the currently-running script, or the current working directory if * the currently-running script is "-e" (namely, you're using it from the * command line.) Otherwise, it will be relative to the current working * directory. */staticJSString*ResolvePath(JSContext*cx,HandleStringfilenameStr,PathResolutionModeresolveMode){JSAutoByteStringfilename(cx,filenameStr);if(!filename)returnnullptr;constchar*pathname=filename.ptr();if(pathname[0]=='/')returnfilenameStr;#ifdef XP_WIN// Various forms of absolute paths per http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx// "\..."if(pathname[0]=='\\')returnfilenameStr;// "C:\..."if(strlen(pathname)>3&&isalpha(pathname[0])&&pathname[1]==':'&&pathname[2]=='\\')returnfilenameStr;// "\\..."if(strlen(pathname)>2&&pathname[1]=='\\'&&pathname[2]=='\\')returnfilenameStr;#endif/* Get the currently executing script's name. */JS::AutoFilenamescriptFilename;if(!DescribeScriptedCaller(cx,&scriptFilename))returnnullptr;if(!scriptFilename.get())returnnullptr;if(strcmp(scriptFilename.get(),"-e")==0||strcmp(scriptFilename.get(),"typein")==0)resolveMode=RootRelative;staticcharbuffer[PATH_MAX+1];if(resolveMode==ScriptRelative){#ifdef XP_WIN// The docs say it can return EINVAL, but the compiler says it's void_splitpath(scriptFilename.get(),nullptr,buffer,nullptr,nullptr);#elsestrncpy(buffer,scriptFilename.get(),PATH_MAX+1);if(buffer[PATH_MAX]!='\0')returnnullptr;// dirname(buffer) might return buffer, or it might return a// statically-allocated stringmemmove(buffer,dirname(buffer),strlen(buffer)+1);#endif}else{constchar*cwd=getcwd(buffer,PATH_MAX);if(!cwd)returnnullptr;}size_tlen=strlen(buffer);buffer[len]='/';strncpy(buffer+len+1,pathname,sizeof(buffer)-(len+1));if(buffer[PATH_MAX]!='\0')returnnullptr;returnJS_NewStringCopyZ(cx,buffer);}staticboolCreateMappedArrayBuffer(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1||args.length()>3){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,args.length()<1?JSSMSG_NOT_ENOUGH_ARGS:JSSMSG_TOO_MANY_ARGS,"createMappedArrayBuffer");returnfalse;}RootedStringrawFilenameStr(cx,JS::ToString(cx,args[0]));if(!rawFilenameStr)returnfalse;// It's a little bizarre to resolve relative to the script, but for testing// I need a file at a known location, and the only good way I know of to do// that right now is to include it in the repo alongside the test script.// Bug 944164 would introduce an alternative.JSString*filenameStr=ResolvePath(cx,rawFilenameStr,ScriptRelative);if(!filenameStr)returnfalse;JSAutoByteStringfilename(cx,filenameStr);if(!filename)returnfalse;uint32_toffset=0;if(args.length()>=2){if(!JS::ToUint32(cx,args[1],&offset))returnfalse;}boolsizeGiven=false;uint32_tsize;if(args.length()>=3){if(!JS::ToUint32(cx,args[2],&size))returnfalse;sizeGiven=true;if(offset>size){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_ARG_INDEX_OUT_OF_RANGE,"2");returnfalse;}}FILE*file=fopen(filename.ptr(),"r");if(!file){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_CANT_OPEN,filename.ptr(),strerror(errno));returnfalse;}AutoCloseInputFileautoClose(file);if(!sizeGiven){structstatst;if(fstat(fileno(file),&st)<0){JS_ReportError(cx,"Unable to stat file");returnfalse;}if(st.st_size<off_t(offset)){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_ARG_INDEX_OUT_OF_RANGE,"2");returnfalse;}size=st.st_size-offset;}void*contents=JS_CreateMappedArrayBufferContents(fileno(file),offset,size);if(!contents){JS_ReportError(cx,"failed to allocate mapped array buffer contents (possibly due to bad alignment)");returnfalse;}RootedObjectobj(cx,JS_NewMappedArrayBufferWithContents(cx,size,contents));if(!obj)returnfalse;args.rval().setObject(*obj);returntrue;}staticboolOptions(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);JS::RuntimeOptionsoldRuntimeOptions=JS::RuntimeOptionsRef(cx);for(unsignedi=0;i<args.length();i++){JSString*str=JS::ToString(cx,args[i]);if(!str)returnfalse;args[i].setString(str);JSAutoByteStringopt(cx,str);if(!opt)returnfalse;if(strcmp(opt.ptr(),"strict")==0)JS::RuntimeOptionsRef(cx).toggleExtraWarnings();elseif(strcmp(opt.ptr(),"werror")==0)JS::RuntimeOptionsRef(cx).toggleWerror();elseif(strcmp(opt.ptr(),"strict_mode")==0)JS::RuntimeOptionsRef(cx).toggleStrictMode();else{JS_ReportError(cx,"unknown option name '%s'."" The valid names are strict,"" werror, and strict_mode.",opt.ptr());returnfalse;}}char*names=strdup("");boolfound=false;if(names&&oldRuntimeOptions.extraWarnings()){names=JS_sprintf_append(names,"%s%s",found?",":"","strict");found=true;}if(names&&oldRuntimeOptions.werror()){names=JS_sprintf_append(names,"%s%s",found?",":"","werror");found=true;}if(names&&oldRuntimeOptions.strictMode()){names=JS_sprintf_append(names,"%s%s",found?",":"","strict_mode");found=true;}if(!names){JS_ReportOutOfMemory(cx);returnfalse;}JSString*str=JS_NewStringCopyZ(cx,names);free(names);if(!str)returnfalse;args.rval().setString(str);returntrue;}staticboolLoadScript(JSContext*cx,unsignedargc,jsval*vp,boolscriptRelative){CallArgsargs=CallArgsFromVp(argc,vp);RootedObjectthisobj(cx,JS_THIS_OBJECT(cx,vp));if(!thisobj)returnfalse;RootedStringstr(cx);for(unsignedi=0;i<args.length();i++){str=JS::ToString(cx,args[i]);if(!str){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"load");returnfalse;}str=ResolvePath(cx,str,scriptRelative?ScriptRelative:RootRelative);if(!str){JS_ReportError(cx,"unable to resolve path");returnfalse;}JSAutoByteStringfilename(cx,str);if(!filename)returnfalse;errno=0;CompileOptionsopts(cx);opts.setIntroductionType("js shell load").setUTF8(true).setCompileAndGo(true).setNoScriptRval(true);RootedScriptscript(cx);RootedValueunused(cx);if((compileOnly&&!Compile(cx,thisobj,opts,filename.ptr(),&script))||!Evaluate(cx,thisobj,opts,filename.ptr(),&unused)){returnfalse;}}args.rval().setUndefined();returntrue;}staticboolLoad(JSContext*cx,unsignedargc,jsval*vp){returnLoadScript(cx,argc,vp,false);}staticboolLoadScriptRelativeToScript(JSContext*cx,unsignedargc,jsval*vp){returnLoadScript(cx,argc,vp,true);}// Populate |options| with the options given by |opts|'s properties. If we// need to convert a filename to a C string, let fileNameBytes own the// bytes.staticboolParseCompileOptions(JSContext*cx,CompileOptions&options,HandleObjectopts,JSAutoByteString&fileNameBytes){RootedValuev(cx);RootedStrings(cx);if(!JS_GetProperty(cx,opts,"compileAndGo",&v))returnfalse;if(!v.isUndefined())options.setCompileAndGo(ToBoolean(v));if(!JS_GetProperty(cx,opts,"noScriptRval",&v))returnfalse;if(!v.isUndefined())options.setNoScriptRval(ToBoolean(v));if(!JS_GetProperty(cx,opts,"fileName",&v))returnfalse;if(v.isNull()){options.setFile(nullptr);}elseif(!v.isUndefined()){s=ToString(cx,v);if(!s)returnfalse;char*fileName=fileNameBytes.encodeLatin1(cx,s);if(!fileName)returnfalse;options.setFile(fileName);}if(!JS_GetProperty(cx,opts,"element",&v))returnfalse;if(v.isObject())options.setElement(&v.toObject());if(!JS_GetProperty(cx,opts,"elementAttributeName",&v))returnfalse;if(!v.isUndefined()){s=ToString(cx,v);if(!s)returnfalse;options.setElementAttributeName(s);}if(!JS_GetProperty(cx,opts,"lineNumber",&v))returnfalse;if(!v.isUndefined()){uint32_tu;if(!ToUint32(cx,v,&u))returnfalse;options.setLine(u);}if(!JS_GetProperty(cx,opts,"columnNumber",&v))returnfalse;if(!v.isUndefined()){int32_tc;if(!ToInt32(cx,v,&c))returnfalse;options.setColumn(c);}if(!JS_GetProperty(cx,opts,"sourceIsLazy",&v))returnfalse;if(v.isBoolean())options.setSourceIsLazy(v.toBoolean());returntrue;}classAutoNewContext{private:JSContext*oldcx;JSContext*newcx;Maybe<JSAutoRequest>newRequest;Maybe<AutoCompartment>newCompartment;AutoNewContext(constAutoNewContext&)=delete;public:AutoNewContext():oldcx(nullptr),newcx(nullptr){}boolenter(JSContext*cx){MOZ_ASSERT(!JS_IsExceptionPending(cx));oldcx=cx;newcx=NewContext(JS_GetRuntime(cx));if(!newcx)returnfalse;JS::ContextOptionsRef(newcx).setDontReportUncaught(true);newRequest.emplace(newcx);newCompartment.emplace(newcx,JS::CurrentGlobalOrNull(cx));returntrue;}JSContext*get(){returnnewcx;}~AutoNewContext(){if(newcx){RootedValueexc(oldcx);boolthrowing=JS_IsExceptionPending(newcx);if(throwing)JS_GetPendingException(newcx,&exc);newCompartment.reset();newRequest.reset();if(throwing&&JS_WrapValue(oldcx,&exc))JS_SetPendingException(oldcx,exc);DestroyContext(newcx,false);}}};staticvoidmy_LargeAllocFailCallback(void*data){JSContext*cx=(JSContext*)data;JSRuntime*rt=cx->runtime();if(!cx->isJSContext())return;MOZ_ASSERT(!rt->isHeapBusy());MOZ_ASSERT(!rt->currentThreadHasExclusiveAccess());JS::PrepareForFullGC(rt);AutoKeepAtomskeepAtoms(cx->perThreadData);rt->gc.gc(GC_NORMAL,JS::gcreason::SHARED_MEMORY_LIMIT);}staticconstuint32_tCacheEntry_SOURCE=0;staticconstuint32_tCacheEntry_BYTECODE=1;staticconstJSClassCacheEntry_class={"CacheEntryObject",JSCLASS_HAS_RESERVED_SLOTS(2)};staticboolCacheEntry(JSContext*cx,unsignedargc,JS::Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1||!args[0].isString()){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"CacheEntry");returnfalse;}RootedObjectobj(cx,JS_NewObject(cx,&CacheEntry_class));if(!obj)returnfalse;SetReservedSlot(obj,CacheEntry_SOURCE,args[0]);SetReservedSlot(obj,CacheEntry_BYTECODE,UndefinedValue());args.rval().setObject(*obj);returntrue;}staticboolCacheEntry_isCacheEntry(JSObject*cache){returnJS_GetClass(cache)==&CacheEntry_class;}staticJSString*CacheEntry_getSource(HandleObjectcache){MOZ_ASSERT(CacheEntry_isCacheEntry(cache));Valuev=JS_GetReservedSlot(cache,CacheEntry_SOURCE);if(!v.isString())returnnullptr;returnv.toString();}staticuint8_t*CacheEntry_getBytecode(HandleObjectcache,uint32_t*length){MOZ_ASSERT(CacheEntry_isCacheEntry(cache));Valuev=JS_GetReservedSlot(cache,CacheEntry_BYTECODE);if(!v.isObject()||!v.toObject().is<ArrayBufferObject>())returnnullptr;ArrayBufferObject*arrayBuffer=&v.toObject().as<ArrayBufferObject>();*length=arrayBuffer->byteLength();returnarrayBuffer->dataPointer();}staticboolCacheEntry_setBytecode(JSContext*cx,HandleObjectcache,uint8_t*buffer,uint32_tlength){MOZ_ASSERT(CacheEntry_isCacheEntry(cache));ArrayBufferObject::BufferContentscontents=ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(buffer);Rooted<ArrayBufferObject*>arrayBuffer(cx,ArrayBufferObject::create(cx,length,contents));if(!arrayBuffer)returnfalse;SetReservedSlot(cache,CacheEntry_BYTECODE,OBJECT_TO_JSVAL(arrayBuffer));returntrue;}classAutoSaveFrameChain{JSContext*cx_;boolsaved_;public:explicitAutoSaveFrameChain(JSContext*cx):cx_(cx),saved_(false){}boolsave(){if(!JS_SaveFrameChain(cx_))returnfalse;saved_=true;returntrue;}~AutoSaveFrameChain(){if(saved_)JS_RestoreFrameChain(cx_);}};staticboolEvaluate(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1||args.length()>2){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,args.length()<1?JSSMSG_NOT_ENOUGH_ARGS:JSSMSG_TOO_MANY_ARGS,"evaluate");returnfalse;}RootedStringcode(cx,nullptr);RootedObjectcacheEntry(cx,nullptr);if(args[0].isString()){code=args[0].toString();}elseif(args[0].isObject()&&CacheEntry_isCacheEntry(&args[0].toObject())){cacheEntry=&args[0].toObject();code=CacheEntry_getSource(cacheEntry);}if(!code||(args.length()==2&&args[1].isPrimitive())){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"evaluate");returnfalse;}CompileOptionsoptions(cx);JSAutoByteStringfileNameBytes;boolnewContext=false;RootedStringdisplayURL(cx);RootedStringsourceMapURL(cx);RootedObjectglobal(cx,nullptr);boolcatchTermination=false;boolsaveFrameChain=false;boolloadBytecode=false;boolsaveBytecode=false;boolassertEqBytecode=false;RootedObjectcallerGlobal(cx,cx->global());options.setIntroductionType("js shell evaluate").setFileAndLine("@evaluate",1);global=JS_GetGlobalForObject(cx,&args.callee());if(!global)returnfalse;if(args.length()==2){RootedObjectopts(cx,&args[1].toObject());RootedValuev(cx);if(!ParseCompileOptions(cx,options,opts,fileNameBytes))returnfalse;if(!JS_GetProperty(cx,opts,"newContext",&v))returnfalse;if(!v.isUndefined())newContext=ToBoolean(v);if(!JS_GetProperty(cx,opts,"displayURL",&v))returnfalse;if(!v.isUndefined()){displayURL=ToString(cx,v);if(!displayURL)returnfalse;}if(!JS_GetProperty(cx,opts,"sourceMapURL",&v))returnfalse;if(!v.isUndefined()){sourceMapURL=ToString(cx,v);if(!sourceMapURL)returnfalse;}if(!JS_GetProperty(cx,opts,"global",&v))returnfalse;if(!v.isUndefined()){if(v.isObject()){global=js::UncheckedUnwrap(&v.toObject());if(!global)returnfalse;}if(!global||!(JS_GetClass(global)->flags&JSCLASS_IS_GLOBAL)){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_UNEXPECTED_TYPE,"\"global\" passed to evaluate()","not a global object");returnfalse;}}if(!JS_GetProperty(cx,opts,"catchTermination",&v))returnfalse;if(!v.isUndefined())catchTermination=ToBoolean(v);if(!JS_GetProperty(cx,opts,"saveFrameChain",&v))returnfalse;if(!v.isUndefined())saveFrameChain=ToBoolean(v);if(!JS_GetProperty(cx,opts,"loadBytecode",&v))returnfalse;if(!v.isUndefined())loadBytecode=ToBoolean(v);if(!JS_GetProperty(cx,opts,"saveBytecode",&v))returnfalse;if(!v.isUndefined())saveBytecode=ToBoolean(v);if(!JS_GetProperty(cx,opts,"assertEqBytecode",&v))returnfalse;if(!v.isUndefined())assertEqBytecode=ToBoolean(v);// We cannot load or save the bytecode if we have no object where the// bytecode cache is stored.if(loadBytecode||saveBytecode){if(!cacheEntry){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"evaluate");returnfalse;}}}AutoStableStringCharscodeChars(cx);if(!codeChars.initTwoByte(cx,code))returnfalse;AutoNewContextancx;if(newContext){if(!ancx.enter(cx))returnfalse;cx=ancx.get();}uint32_tloadLength=0;uint8_t*loadBuffer=nullptr;uint32_tsaveLength=0;ScopedJSFreePtr<uint8_t>saveBuffer;if(loadBytecode){loadBuffer=CacheEntry_getBytecode(cacheEntry,&loadLength);if(!loadBuffer)returnfalse;}{AutoSaveFrameChainasfc(cx);if(saveFrameChain&&!asfc.save())returnfalse;JSAutoCompartmentac(cx,global);RootedScriptscript(cx);{if(saveBytecode){if(!JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates()){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_CACHE_SINGLETON_FAILED);returnfalse;}JS::CompartmentOptionsRef(cx).setCloneSingletons(true);}if(loadBytecode){script=JS_DecodeScript(cx,loadBuffer,loadLength);}else{mozilla::Range<constchar16_t>chars=codeChars.twoByteRange();(void)JS::Compile(cx,global,options,chars.start().get(),chars.length(),&script);}if(!script)returnfalse;}if(displayURL&&!script->scriptSource()->hasDisplayURL()){JSFlatString*flat=displayURL->ensureFlat(cx);if(!flat)returnfalse;AutoStableStringCharschars(cx);if(!chars.initTwoByte(cx,flat))returnfalse;constchar16_t*durl=chars.twoByteRange().start().get();if(!script->scriptSource()->setDisplayURL(cx,durl))returnfalse;}if(sourceMapURL&&!script->scriptSource()->hasSourceMapURL()){JSFlatString*flat=sourceMapURL->ensureFlat(cx);if(!flat)returnfalse;AutoStableStringCharschars(cx);if(!chars.initTwoByte(cx,flat))returnfalse;constchar16_t*smurl=chars.twoByteRange().start().get();if(!script->scriptSource()->setSourceMapURL(cx,smurl))returnfalse;}if(!JS_ExecuteScript(cx,global,script,args.rval())){if(catchTermination&&!JS_IsExceptionPending(cx)){JSAutoCompartmentac1(cx,callerGlobal);JSString*str=JS_NewStringCopyZ(cx,"terminated");if(!str)returnfalse;args.rval().setString(str);returntrue;}returnfalse;}if(saveBytecode){saveBuffer=reinterpret_cast<uint8_t*>(JS_EncodeScript(cx,script,&saveLength));if(!saveBuffer)returnfalse;}}if(saveBytecode){// If we are both loading and saving, we assert that we are going to// replace the current bytecode by the same stream of bytes.if(loadBytecode&&assertEqBytecode){if(saveLength!=loadLength){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_CACHE_EQ_SIZE_FAILED,loadLength,saveLength);}elseif(!PodEqual(loadBuffer,saveBuffer.get(),loadLength)){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_CACHE_EQ_CONTENT_FAILED);}}if(!CacheEntry_setBytecode(cx,cacheEntry,saveBuffer,saveLength))returnfalse;saveBuffer.forget();}returnJS_WrapValue(cx,args.rval());}staticJSString*FileAsString(JSContext*cx,constchar*pathname){FILE*file;RootedStringstr(cx);size_tlen,cc;char*buf;file=fopen(pathname,"rb");if(!file){JS_ReportError(cx,"can't open %s: %s",pathname,strerror(errno));returnnullptr;}AutoCloseInputFileautoClose(file);if(fseek(file,0,SEEK_END)!=0){JS_ReportError(cx,"can't seek end of %s",pathname);}else{len=ftell(file);if(fseek(file,0,SEEK_SET)!=0){JS_ReportError(cx,"can't seek start of %s",pathname);}else{buf=(char*)JS_malloc(cx,len+1);if(buf){cc=fread(buf,1,len,file);if(cc!=len){JS_ReportError(cx,"can't read %s: %s",pathname,(ptrdiff_t(cc)<0)?strerror(errno):"short read");}else{char16_t*ucbuf=JS::UTF8CharsToNewTwoByteCharsZ(cx,JS::UTF8Chars(buf,len),&len).get();if(!ucbuf){JS_ReportError(cx,"Invalid UTF-8 in file '%s'",pathname);gExitCode=EXITCODE_RUNTIME_ERROR;returnnullptr;}str=JS_NewUCStringCopyN(cx,ucbuf,len);free(ucbuf);}JS_free(cx,buf);}}}returnstr;}staticJSObject*FileAsTypedArray(JSContext*cx,constchar*pathname){FILE*file=fopen(pathname,"rb");if(!file){JS_ReportError(cx,"can't open %s: %s",pathname,strerror(errno));returnnullptr;}AutoCloseInputFileautoClose(file);RootedObjectobj(cx);if(fseek(file,0,SEEK_END)!=0){JS_ReportError(cx,"can't seek end of %s",pathname);}else{size_tlen=ftell(file);if(fseek(file,0,SEEK_SET)!=0){JS_ReportError(cx,"can't seek start of %s",pathname);}else{obj=JS_NewUint8Array(cx,len);if(!obj)returnnullptr;char*buf=(char*)obj->as<TypedArrayObject>().viewData();size_tcc=fread(buf,1,len,file);if(cc!=len){JS_ReportError(cx,"can't read %s: %s",pathname,(ptrdiff_t(cc)<0)?strerror(errno):"short read");obj=nullptr;}}}returnobj;}/* * Function to run scripts and return compilation + execution time. Semantics * are closely modelled after the equivalent function in WebKit, as this is used * to produce benchmark timings by SunSpider. */staticboolRun(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"run");returnfalse;}RootedObjectthisobj(cx,JS_THIS_OBJECT(cx,vp));if(!thisobj)returnfalse;RootedStringstr(cx,JS::ToString(cx,args[0]));if(!str)returnfalse;args[0].setString(str);JSAutoByteStringfilename(cx,str);if(!filename)returnfalse;str=FileAsString(cx,filename.ptr());if(!str)returnfalse;AutoStableStringCharschars(cx);if(!chars.initTwoByte(cx,str))returnfalse;constchar16_t*ucbuf=chars.twoByteRange().start().get();size_tbuflen=str->length();RootedScriptscript(cx);int64_tstartClock=PRMJ_Now();{JS::CompileOptionsoptions(cx);options.setIntroductionType("js shell run").setFileAndLine(filename.ptr(),1).setCompileAndGo(true).setNoScriptRval(true);if(!JS_CompileUCScript(cx,thisobj,ucbuf,buflen,options,&script))returnfalse;}if(!JS_ExecuteScript(cx,thisobj,script))returnfalse;int64_tendClock=PRMJ_Now();args.rval().setDouble((endClock-startClock)/double(PRMJ_USEC_PER_MSEC));returntrue;}/* * function readline() * Provides a hook for scripts to read a line from stdin. */staticboolReadLine(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);#define BUFSIZE 256FILE*from=stdin;size_tbuflength=0;size_tbufsize=BUFSIZE;char*buf=(char*)JS_malloc(cx,bufsize);if(!buf)returnfalse;boolsawNewline=false;size_tgotlength;while((gotlength=js_fgets(buf+buflength,bufsize-buflength,from))>0){buflength+=gotlength;/* Are we done? */if(buf[buflength-1]=='\n'){buf[buflength-1]='\0';sawNewline=true;break;}elseif(buflength<bufsize-1){break;}/* Else, grow our buffer for another pass. */char*tmp;bufsize*=2;if(bufsize>buflength){tmp=static_cast<char*>(JS_realloc(cx,buf,bufsize/2,bufsize));}else{JS_ReportOutOfMemory(cx);tmp=nullptr;}if(!tmp){JS_free(cx,buf);returnfalse;}buf=tmp;}/* Treat the empty string specially. */if(buflength==0){args.rval().set(feof(from)?NullValue():JS_GetEmptyStringValue(cx));JS_free(cx,buf);returntrue;}/* Shrink the buffer to the real size. */char*tmp=static_cast<char*>(JS_realloc(cx,buf,bufsize,buflength));if(!tmp){JS_free(cx,buf);returnfalse;}buf=tmp;/* * Turn buf into a JSString. Note that buflength includes the trailing null * character. */JSString*str=JS_NewStringCopyN(cx,buf,sawNewline?buflength-1:buflength);JS_free(cx,buf);if(!str)returnfalse;args.rval().setString(str);returntrue;}staticboolPutStr(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=0){RootedStringstr(cx,JS::ToString(cx,args[0]));if(!str)returnfalse;char*bytes=JS_EncodeStringToUTF8(cx,str);if(!bytes)returnfalse;fputs(bytes,gOutFile);JS_free(cx,bytes);fflush(gOutFile);}args.rval().setUndefined();returntrue;}staticboolNow(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);doublenow=PRMJ_Now()/double(PRMJ_USEC_PER_MSEC);args.rval().setDouble(now);returntrue;}staticboolPrintInternal(JSContext*cx,constCallArgs&args,FILE*file){for(unsignedi=0;i<args.length();i++){RootedStringstr(cx,JS::ToString(cx,args[i]));if(!str)returnfalse;char*bytes=JS_EncodeStringToUTF8(cx,str);if(!bytes)returnfalse;fprintf(file,"%s%s",i?" ":"",bytes);JS_free(cx,bytes);}fputc('\n',file);fflush(file);args.rval().setUndefined();returntrue;}staticboolPrint(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);returnPrintInternal(cx,args,gOutFile);}staticboolPrintErr(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);returnPrintInternal(cx,args,gErrFile);}staticboolHelp(JSContext*cx,unsignedargc,jsval*vp);staticboolQuit(JSContext*cx,unsignedargc,jsval*vp){#ifdef JS_MORE_DETERMINISTIC// Print a message to stderr in more-deterministic builds to help jsfunfuzz// find uncatchable-exception bugs.fprintf(stderr,"quit called\n");#endifCallArgsargs=CallArgsFromVp(argc,vp);int32_tcode;if(!ToInt32(cx,args.get(0),&code))returnfalse;// The fuzzers check the shell's exit code and assume a value >= 128 means// the process crashed (for instance, SIGSEGV will result in code 139). On// POSIX platforms, the exit code is 8-bit and negative values can also// result in an exit code >= 128. We restrict the value to range [0, 127] to// avoid false positives.if(code<0||code>=128){JS_ReportError(cx,"quit exit code should be in range 0-127");returnfalse;}gExitCode=code;gQuitting=true;returnfalse;}namespacegcCallback{structMajorGC{int32_tdepth;int32_tphases;};staticvoidmajorGC(JSRuntime*rt,JSGCStatusstatus,void*data){autoinfo=static_cast<MajorGC*>(data);if(!(info->phases&(1<<status)))return;if(info->depth>0){info->depth--;JS::PrepareForFullGC(rt);JS::GCForReason(rt,GC_NORMAL,JS::gcreason::API);info->depth++;}}structMinorGC{int32_tphases;boolactive;};staticvoidminorGC(JSRuntime*rt,JSGCStatusstatus,void*data){autoinfo=static_cast<MinorGC*>(data);if(!(info->phases&(1<<status)))return;if(info->active){info->active=false;rt->gc.evictNursery(JS::gcreason::DEBUG_GC);info->active=true;}}// Process global, should really be runtime-local. Also, the final one of these// is currently leaked, since they are only deleted when changing.MajorGC*prevMajorGC=nullptr;MinorGC*prevMinorGC=nullptr;}/* namespace gcCallback */staticboolSetGCCallback(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1){JS_ReportError(cx,"Wrong number of arguments");returnfalse;}RootedObjectopts(cx,ToObject(cx,args[0]));if(!opts)returnfalse;RootedValuev(cx);if(!JS_GetProperty(cx,opts,"action",&v))returnfalse;JSString*str=JS::ToString(cx,v);if(!str)returnfalse;JSAutoByteStringaction(cx,str);if(!action)returnfalse;int32_tphases=0;if((strcmp(action.ptr(),"minorGC")==0)||(strcmp(action.ptr(),"majorGC")==0)){if(!JS_GetProperty(cx,opts,"phases",&v))returnfalse;if(v.isUndefined()){phases=(1<<JSGC_END);}else{JSString*str=JS::ToString(cx,v);if(!str)returnfalse;JSAutoByteStringphasesStr(cx,str);if(!phasesStr)returnfalse;if(strcmp(phasesStr.ptr(),"begin")==0)phases=(1<<JSGC_BEGIN);elseif(strcmp(phasesStr.ptr(),"end")==0)phases=(1<<JSGC_END);elseif(strcmp(phasesStr.ptr(),"both")==0)phases=(1<<JSGC_BEGIN)|(1<<JSGC_END);else{JS_ReportError(cx,"Invalid callback phase");returnfalse;}}}if(gcCallback::prevMajorGC){JS_SetGCCallback(cx->runtime(),nullptr,nullptr);js_delete<gcCallback::MajorGC>(gcCallback::prevMajorGC);gcCallback::prevMajorGC=nullptr;}if(gcCallback::prevMinorGC){JS_SetGCCallback(cx->runtime(),nullptr,nullptr);js_delete<gcCallback::MinorGC>(gcCallback::prevMinorGC);gcCallback::prevMinorGC=nullptr;}if(strcmp(action.ptr(),"minorGC")==0){autoinfo=js_new<gcCallback::MinorGC>();info->phases=phases;info->active=true;JS_SetGCCallback(cx->runtime(),gcCallback::minorGC,info);}elseif(strcmp(action.ptr(),"majorGC")==0){if(!JS_GetProperty(cx,opts,"depth",&v))returnfalse;int32_tdepth=1;if(!v.isUndefined()){if(!ToInt32(cx,v,&depth))returnfalse;}if(depth>int32_t(gcstats::Statistics::MAX_NESTING-4)){JS_ReportError(cx,"Nesting depth too large, would overflow");returnfalse;}autoinfo=js_new<gcCallback::MajorGC>();info->phases=phases;info->depth=depth;JS_SetGCCallback(cx->runtime(),gcCallback::majorGC,info);}else{JS_ReportError(cx,"Unknown GC callback action");returnfalse;}args.rval().setUndefined();returntrue;}staticboolStartTimingMutator(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()>0){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_TOO_MANY_ARGS,"startTimingMutator");returnfalse;}cx->runtime()->gc.stats.startTimingMutator();args.rval().setUndefined();returntrue;}staticboolStopTimingMutator(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()>0){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_TOO_MANY_ARGS,"stopTimingMutator");returnfalse;}doublemutator_ms,gc_ms;if(!cx->runtime()->gc.stats.stopTimingMutator(mutator_ms,gc_ms)){JS_ReportError(cx,"stopTimingMutator called when not timing the mutator");returnfalse;}doubletotal_ms=mutator_ms+gc_ms;if(total_ms>0){fprintf(gOutFile,"Mutator: %.3fms (%.1f%%), GC: %.3fms (%.1f%%)\n",mutator_ms,mutator_ms/total_ms*100.0,gc_ms,gc_ms/total_ms*100.0);}args.rval().setUndefined();returntrue;}staticconstchar*ToSource(JSContext*cx,MutableHandleValuevp,JSAutoByteString*bytes){JSString*str=JS_ValueToSource(cx,vp);if(str){vp.setString(str);if(bytes->encodeLatin1(cx,str))returnbytes->ptr();}JS_ClearPendingException(cx);return"<<error converting value to string>>";}staticboolAssertEq(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(!(args.length()==2||(args.length()==3&&args[2].isString()))){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,(args.length()<2)?JSSMSG_NOT_ENOUGH_ARGS:(args.length()==3)?JSSMSG_INVALID_ARGS:JSSMSG_TOO_MANY_ARGS,"assertEq");returnfalse;}boolsame;if(!JS_SameValue(cx,args[0],args[1],&same))returnfalse;if(!same){JSAutoByteStringbytes0,bytes1;constchar*actual=ToSource(cx,args[0],&bytes0);constchar*expected=ToSource(cx,args[1],&bytes1);if(args.length()==2){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_ASSERT_EQ_FAILED,actual,expected);}else{JSAutoByteStringbytes2(cx,args[2].toString());if(!bytes2)returnfalse;JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_ASSERT_EQ_FAILED_MSG,actual,expected,bytes2.ptr());}returnfalse;}args.rval().setUndefined();returntrue;}staticJSScript*ValueToScript(JSContext*cx,jsvalvArg,JSFunction**funp=nullptr){RootedValuev(cx,vArg);RootedFunctionfun(cx,JS_ValueToFunction(cx,v));if(!fun)returnnullptr;// Unwrap bound functions.while(fun->isBoundFunction()){JSObject*target=fun->getBoundFunctionTarget();if(target&&target->is<JSFunction>())fun=&target->as<JSFunction>();elsebreak;}if(!fun->isInterpreted()){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_SCRIPTS_ONLY);returnnullptr;}JSScript*script=fun->getOrCreateScript(cx);if(!script)returnnullptr;if(fun&&funp)*funp=fun;returnscript;}staticJSScript*GetTopScript(JSContext*cx){NonBuiltinScriptFrameIteriter(cx);returniter.done()?nullptr:iter.script();}staticboolGetScriptAndPCArgs(JSContext*cx,unsignedargc,jsval*argv,MutableHandleScriptscriptp,int32_t*ip){RootedScriptscript(cx,GetTopScript(cx));*ip=0;if(argc!=0){jsvalv=argv[0];unsignedintarg=0;if(v.isObject()&&JS_GetClass(&v.toObject())==Jsvalify(&JSFunction::class_)){script=ValueToScript(cx,v);if(!script)returnfalse;intarg++;}if(argc>intarg){if(!JS::ToInt32(cx,HandleValue::fromMarkedLocation(&argv[intarg]),ip))returnfalse;if((uint32_t)*ip>=script->length()){JS_ReportError(cx,"Invalid PC");returnfalse;}}}scriptp.set(script);returntrue;}staticboolLineToPC(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()==0){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_LINE2PC_USAGE);returnfalse;}RootedScriptscript(cx,GetTopScript(cx));int32_tlineArg=0;if(args[0].isObject()&&args[0].toObject().is<JSFunction>()){script=ValueToScript(cx,args[0]);if(!script)returnfalse;lineArg++;}uint32_tlineno;if(!ToUint32(cx,args.get(lineArg),&lineno))returnfalse;jsbytecode*pc=js_LineNumberToPC(script,lineno);if(!pc)returnfalse;args.rval().setInt32(script->pcToOffset(pc));returntrue;}staticboolPCToLine(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedScriptscript(cx);int32_ti;unsignedlineno;if(!GetScriptAndPCArgs(cx,args.length(),args.array(),&script,&i))returnfalse;lineno=PCToLineNumber(script,script->offsetToPC(i));if(!lineno)returnfalse;args.rval().setInt32(lineno);returntrue;}#ifdef DEBUGstaticvoidUpdateSwitchTableBounds(JSContext*cx,HandleScriptscript,unsignedoffset,unsigned*start,unsigned*end){jsbytecode*pc;JSOpop;ptrdiff_tjmplen;int32_tlow,high,n;pc=script->offsetToPC(offset);op=JSOp(*pc);switch(op){caseJSOP_TABLESWITCH:jmplen=JUMP_OFFSET_LEN;pc+=jmplen;low=GET_JUMP_OFFSET(pc);pc+=JUMP_OFFSET_LEN;high=GET_JUMP_OFFSET(pc);pc+=JUMP_OFFSET_LEN;n=high-low+1;break;default:/* [condswitch] switch does not have any jump or lookup tables. */MOZ_ASSERT(op==JSOP_CONDSWITCH);return;}*start=script->pcToOffset(pc);*end=*start+(unsigned)(n*jmplen);}staticvoidSrcNotes(JSContext*cx,HandleScriptscript,Sprinter*sp){Sprint(sp,"\nSource notes:\n");Sprint(sp,"%4s %4s %5s %6s %-8s %s\n","ofs","line","pc","delta","desc","args");Sprint(sp,"---- ---- ----- ------ -------- ------\n");unsignedoffset=0;unsignedcolspan=0;unsignedlineno=script->lineno();jssrcnote*notes=script->notes();unsignedswitchTableEnd=0,switchTableStart=0;for(jssrcnote*sn=notes;!SN_IS_TERMINATOR(sn);sn=SN_NEXT(sn)){unsigneddelta=SN_DELTA(sn);offset+=delta;SrcNoteTypetype=(SrcNoteType)SN_TYPE(sn);constchar*name=js_SrcNoteSpec[type].name;Sprint(sp,"%3u: %4u %5u [%4u] %-8s",unsigned(sn-notes),lineno,offset,delta,name);switch(type){caseSRC_NULL:caseSRC_IF:caseSRC_CONTINUE:caseSRC_BREAK:caseSRC_BREAK2LABEL:caseSRC_SWITCHBREAK:caseSRC_ASSIGNOP:caseSRC_XDELTA:break;caseSRC_COLSPAN:colspan=SN_OFFSET_TO_COLSPAN(js_GetSrcNoteOffset(sn,0));Sprint(sp,"%d",colspan);break;caseSRC_SETLINE:lineno=js_GetSrcNoteOffset(sn,0);Sprint(sp," lineno %u",lineno);break;caseSRC_NEWLINE:++lineno;break;caseSRC_FOR:Sprint(sp," cond %u update %u tail %u",unsigned(js_GetSrcNoteOffset(sn,0)),unsigned(js_GetSrcNoteOffset(sn,1)),unsigned(js_GetSrcNoteOffset(sn,2)));break;caseSRC_IF_ELSE:Sprint(sp," else %u",unsigned(js_GetSrcNoteOffset(sn,0)));break;caseSRC_FOR_IN:caseSRC_FOR_OF:Sprint(sp," closingjump %u",unsigned(js_GetSrcNoteOffset(sn,0)));break;caseSRC_COND:caseSRC_WHILE:caseSRC_NEXTCASE:Sprint(sp," offset %u",unsigned(js_GetSrcNoteOffset(sn,0)));break;caseSRC_TABLESWITCH:{JSOpop=JSOp(script->code()[offset]);MOZ_ASSERT(op==JSOP_TABLESWITCH);Sprint(sp," length %u",unsigned(js_GetSrcNoteOffset(sn,0)));UpdateSwitchTableBounds(cx,script,offset,&switchTableStart,&switchTableEnd);break;}caseSRC_CONDSWITCH:{JSOpop=JSOp(script->code()[offset]);MOZ_ASSERT(op==JSOP_CONDSWITCH);Sprint(sp," length %u",unsigned(js_GetSrcNoteOffset(sn,0)));unsignedcaseOff=(unsigned)js_GetSrcNoteOffset(sn,1);if(caseOff)Sprint(sp," first case offset %u",caseOff);UpdateSwitchTableBounds(cx,script,offset,&switchTableStart,&switchTableEnd);break;}caseSRC_TRY:MOZ_ASSERT(JSOp(script->code()[offset])==JSOP_TRY);Sprint(sp," offset to jump %u",unsigned(js_GetSrcNoteOffset(sn,0)));break;default:MOZ_ASSERT(0);break;}Sprint(sp,"\n");}}staticboolNotes(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);Sprintersprinter(cx);if(!sprinter.init())returnfalse;for(unsignedi=0;i<args.length();i++){RootedScriptscript(cx,ValueToScript(cx,args[i]));if(!script)returnfalse;SrcNotes(cx,script,&sprinter);}JSString*str=JS_NewStringCopyZ(cx,sprinter.string());if(!str)returnfalse;args.rval().setString(str);returntrue;}JS_STATIC_ASSERT(JSTRY_CATCH==0);JS_STATIC_ASSERT(JSTRY_FINALLY==1);JS_STATIC_ASSERT(JSTRY_ITER==2);staticconstchar*constTryNoteNames[]={"catch","finally","iter","loop"};staticboolTryNotes(JSContext*cx,HandleScriptscript,Sprinter*sp){JSTryNote*tn,*tnlimit;if(!script->hasTrynotes())returntrue;tn=script->trynotes()->vector;tnlimit=tn+script->trynotes()->length;Sprint(sp,"\nException table:\nkind stack start end\n");do{MOZ_ASSERT(tn->kind<ArrayLength(TryNoteNames));Sprint(sp," %-7s %6u %8u %8u\n",TryNoteNames[tn->kind],tn->stackDepth,tn->start,tn->start+tn->length);}while(++tn!=tnlimit);returntrue;}staticboolDisassembleScript(JSContext*cx,HandleScriptscript,HandleFunctionfun,boollines,boolrecursive,Sprinter*sp){if(fun){Sprint(sp,"flags:");if(fun->isLambda())Sprint(sp," LAMBDA");if(fun->isHeavyweight())Sprint(sp," HEAVYWEIGHT");if(fun->isExprClosure())Sprint(sp," EXPRESSION_CLOSURE");if(fun->isFunctionPrototype())Sprint(sp," Function.prototype");if(fun->isSelfHostedBuiltin())Sprint(sp," SELF_HOSTED");if(fun->isSelfHostedConstructor())Sprint(sp," SELF_HOSTED_CTOR");if(fun->isArrow())Sprint(sp," ARROW");Sprint(sp,"\n");}if(!js_Disassemble(cx,script,lines,sp))returnfalse;SrcNotes(cx,script,sp);TryNotes(cx,script,sp);if(recursive&&script->hasObjects()){ObjectArray*objects=script->objects();for(unsignedi=0;i!=objects->length;++i){JSObject*obj=objects->vector[i];if(obj->is<JSFunction>()){Sprint(sp,"\n");RootedFunctionfun(cx,&obj->as<JSFunction>());if(fun->isInterpreted()){RootedScriptscript(cx,fun->getOrCreateScript(cx));if(!script||!DisassembleScript(cx,script,fun,lines,recursive,sp))returnfalse;}else{Sprint(sp,"[native code]\n");}}}}returntrue;}namespace{structDisassembleOptionParser{unsignedargc;jsval*argv;boollines;boolrecursive;DisassembleOptionParser(unsignedargc,jsval*argv):argc(argc),argv(argv),lines(false),recursive(false){}boolparse(JSContext*cx){/* Read options off early arguments */while(argc>0&&argv[0].isString()){JSString*str=argv[0].toString();JSFlatString*flatStr=JS_FlattenString(cx,str);if(!flatStr)returnfalse;if(JS_FlatStringEqualsAscii(flatStr,"-l"))lines=true;elseif(JS_FlatStringEqualsAscii(flatStr,"-r"))recursive=true;elsebreak;argv++,argc--;}returntrue;}};}/* anonymous namespace */staticboolDisassembleToSprinter(JSContext*cx,unsignedargc,jsval*vp,Sprinter*sprinter){CallArgsargs=CallArgsFromVp(argc,vp);DisassembleOptionParserp(args.length(),args.array());if(!p.parse(cx))returnfalse;if(p.argc==0){/* Without arguments, disassemble the current script. */RootedScriptscript(cx,GetTopScript(cx));if(script){JSAutoCompartmentac(cx,script);if(!js_Disassemble(cx,script,p.lines,sprinter))returnfalse;SrcNotes(cx,script,sprinter);TryNotes(cx,script,sprinter);}}else{for(unsignedi=0;i<p.argc;i++){RootedFunctionfun(cx);RootedScriptscript(cx,ValueToScript(cx,p.argv[i],fun.address()));if(!script)returnfalse;if(!DisassembleScript(cx,script,fun,p.lines,p.recursive,sprinter))returnfalse;}}returntrue;}staticboolDisassembleToString(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);Sprintersprinter(cx);if(!sprinter.init())returnfalse;if(!DisassembleToSprinter(cx,args.length(),vp,&sprinter))returnfalse;JSString*str=JS_NewStringCopyZ(cx,sprinter.string());if(!str)returnfalse;args.rval().setString(str);returntrue;}staticboolDisassemble(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);Sprintersprinter(cx);if(!sprinter.init())returnfalse;if(!DisassembleToSprinter(cx,args.length(),vp,&sprinter))returnfalse;fprintf(stdout,"%s\n",sprinter.string());args.rval().setUndefined();returntrue;}staticboolDisassFile(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);/* Support extra options at the start, just like Disassemble. */DisassembleOptionParserp(args.length(),args.array());if(!p.parse(cx))returnfalse;if(!p.argc){args.rval().setUndefined();returntrue;}RootedObjectthisobj(cx,JS_THIS_OBJECT(cx,vp));if(!thisobj)returnfalse;// We should change DisassembleOptionParser to store CallArgs.JSString*str=JS::ToString(cx,HandleValue::fromMarkedLocation(&p.argv[0]));if(!str)returnfalse;JSAutoByteStringfilename(cx,str);if(!filename)returnfalse;RootedScriptscript(cx);{CompileOptionsoptions(cx);options.setIntroductionType("js shell disFile").setUTF8(true).setFileAndLine(filename.ptr(),1).setCompileAndGo(true).setNoScriptRval(true);if(!JS::Compile(cx,thisobj,options,filename.ptr(),&script))returnfalse;}Sprintersprinter(cx);if(!sprinter.init())returnfalse;boolok=DisassembleScript(cx,script,JS::NullPtr(),p.lines,p.recursive,&sprinter);if(ok)fprintf(stdout,"%s\n",sprinter.string());if(!ok)returnfalse;args.rval().setUndefined();returntrue;}staticboolDisassWithSrc(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);#define LINE_BUF_LEN 512unsignedlen,line1,line2,bupline;FILE*file;charlinebuf[LINE_BUF_LEN];jsbytecode*pc,*end;staticconstcharsep[]=";-------------------------";boolok=true;RootedScriptscript(cx);for(unsignedi=0;ok&&i<args.length();i++){script=ValueToScript(cx,args[i]);if(!script)returnfalse;if(!script->filename()){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_FILE_SCRIPTS_ONLY);returnfalse;}file=fopen(script->filename(),"r");if(!file){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_CANT_OPEN,script->filename(),strerror(errno));returnfalse;}pc=script->code();end=script->codeEnd();Sprintersprinter(cx);if(!sprinter.init()){ok=false;gotobail;}/* burn the leading lines */line2=PCToLineNumber(script,pc);for(line1=0;line1<line2-1;line1++){char*tmp=fgets(linebuf,LINE_BUF_LEN,file);if(!tmp){JS_ReportError(cx,"failed to read %s fully",script->filename());ok=false;gotobail;}}bupline=0;while(pc<end){line2=PCToLineNumber(script,pc);if(line2<line1){if(bupline!=line2){bupline=line2;Sprint(&sprinter,"%s %3u: BACKUP\n",sep,line2);}}else{if(bupline&&line1==line2)Sprint(&sprinter,"%s %3u: RESTORE\n",sep,line2);bupline=0;while(line1<line2){if(!fgets(linebuf,LINE_BUF_LEN,file)){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_UNEXPECTED_EOF,script->filename());ok=false;gotobail;}line1++;Sprint(&sprinter,"%s %3u: %s",sep,line1,linebuf);}}len=js_Disassemble1(cx,script,pc,script->pcToOffset(pc),true,&sprinter);if(!len){ok=false;gotobail;}pc+=len;}fprintf(stdout,"%s\n",sprinter.string());bail:fclose(file);}args.rval().setUndefined();returnok;#undef LINE_BUF_LEN}#endif /* DEBUG */staticboolBuildDate(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);fprintf(gOutFile,"built on %s at %s\n",__DATE__,__TIME__);args.rval().setUndefined();returntrue;}staticboolIntern(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);JSString*str=JS::ToString(cx,args.get(0));if(!str)returnfalse;AutoStableStringCharsstrChars(cx);if(!strChars.initTwoByte(cx,str))returnfalse;mozilla::Range<constchar16_t>chars=strChars.twoByteRange();if(!JS_InternUCStringN(cx,chars.start().get(),chars.length()))returnfalse;args.rval().setUndefined();returntrue;}staticboolClone(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedObjectparent(cx);RootedObjectfunobj(cx);if(!args.length()){JS_ReportError(cx,"Invalid arguments to clone");returnfalse;}{Maybe<JSAutoCompartment>ac;RootedObjectobj(cx,args[0].isPrimitive()?nullptr:&args[0].toObject());if(obj&&obj->is<CrossCompartmentWrapperObject>()){obj=UncheckedUnwrap(obj);ac.emplace(cx,obj);args[0].setObject(*obj);}if(obj&&obj->is<JSFunction>()){funobj=obj;}else{JSFunction*fun=JS_ValueToFunction(cx,args[0]);if(!fun)returnfalse;funobj=JS_GetFunctionObject(fun);}}if(funobj->compartment()!=cx->compartment()){JSFunction*fun=&funobj->as<JSFunction>();if(fun->hasScript()&&fun->nonLazyScript()->compileAndGo()){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_UNEXPECTED_TYPE,"function","compile-and-go");returnfalse;}}if(args.length()>1){if(!JS_ValueToObject(cx,args[1],&parent))returnfalse;}else{parent=JS_GetParent(&args.callee());}// Should it worry us that we might be getting with wrappers// around with wrappers here?JS::AutoObjectVectorscopeChain(cx);if(!parent->is<GlobalObject>()&&!scopeChain.append(parent))returnfalse;JSObject*clone=JS::CloneFunctionObject(cx,funobj,scopeChain);if(!clone)returnfalse;args.rval().setObject(*clone);returntrue;}staticboolGetSLX(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedScriptscript(cx);script=ValueToScript(cx,args.get(0));if(!script)returnfalse;args.rval().setInt32(js_GetScriptLineExtent(script));returntrue;}staticboolThrowError(JSContext*cx,unsignedargc,jsval*vp){JS_ReportError(cx,"This is an error");returnfalse;}#define LAZY_STANDARD_CLASSES/* A class for easily testing the inner/outer object callbacks. */typedefstructComplexObject{boolisInner;boolfrozen;JSObject*inner;JSObject*outer;}ComplexObject;staticboolsandbox_enumerate(JSContext*cx,HandleObjectobj){RootedValuev(cx);if(!JS_GetProperty(cx,obj,"lazy",&v))returnfalse;if(!ToBoolean(v))returntrue;returnJS_EnumerateStandardClasses(cx,obj);}staticboolsandbox_resolve(JSContext*cx,HandleObjectobj,HandleIdid,bool*resolvedp){RootedValuev(cx);if(!JS_GetProperty(cx,obj,"lazy",&v))returnfalse;if(ToBoolean(v))returnJS_ResolveStandardClass(cx,obj,id,resolvedp);returntrue;}staticconstJSClasssandbox_class={"sandbox",JSCLASS_GLOBAL_FLAGS,nullptr,nullptr,nullptr,nullptr,sandbox_enumerate,sandbox_resolve,nullptr,nullptr,nullptr,nullptr,nullptr,JS_GlobalObjectTraceHook};staticJSObject*NewSandbox(JSContext*cx,boollazy){RootedObjectobj(cx,JS_NewGlobalObject(cx,&sandbox_class,nullptr,JS::DontFireOnNewGlobalHook));if(!obj)returnnullptr;{JSAutoCompartmentac(cx,obj);if(!lazy&&!JS_InitStandardClasses(cx,obj))returnnullptr;RootedValuevalue(cx,BooleanValue(lazy));if(!JS_SetProperty(cx,obj,"lazy",value))returnnullptr;}JS_FireOnNewGlobalObject(cx,obj);if(!cx->compartment()->wrap(cx,&obj))returnnullptr;returnobj;}staticboolEvalInContext(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedStringstr(cx);RootedObjectsobj(cx);if(!JS_ConvertArguments(cx,args,"S / o",str.address(),sobj.address()))returnfalse;AutoStableStringCharsstrChars(cx);if(!strChars.initTwoByte(cx,str))returnfalse;mozilla::Range<constchar16_t>chars=strChars.twoByteRange();size_tsrclen=chars.length();constchar16_t*src=chars.start().get();boollazy=false;if(srclen==4){if(src[0]=='l'&&src[1]=='a'&&src[2]=='z'&&src[3]=='y'){lazy=true;srclen=0;}}if(!sobj){sobj=NewSandbox(cx,lazy);if(!sobj)returnfalse;}if(srclen==0){args.rval().setObject(*sobj);returntrue;}JS::AutoFilenamefilename;unsignedlineno;DescribeScriptedCaller(cx,&filename,&lineno);{Maybe<JSAutoCompartment>ac;unsignedflags;JSObject*unwrapped=UncheckedUnwrap(sobj,true,&flags);if(flags&Wrapper::CROSS_COMPARTMENT){sobj=unwrapped;ac.emplace(cx,sobj);}sobj=GetInnerObject(sobj);if(!sobj)returnfalse;if(!(sobj->getClass()->flags&JSCLASS_IS_GLOBAL)){JS_ReportError(cx,"Invalid scope argument to evalcx");returnfalse;}JS::CompileOptionsopts(cx);opts.setFileAndLine(filename.get(),lineno);if(!JS::Evaluate(cx,sobj,opts,src,srclen,args.rval())){returnfalse;}}if(!cx->compartment()->wrap(cx,args.rval()))returnfalse;returntrue;}structWorkerInput{JSRuntime*runtime;char16_t*chars;size_tlength;WorkerInput(JSRuntime*runtime,char16_t*chars,size_tlength):runtime(runtime),chars(chars),length(length){}~WorkerInput(){js_free(chars);}};staticvoidWorkerMain(void*arg){WorkerInput*input=(WorkerInput*)arg;JSRuntime*rt=JS_NewRuntime(8L*1024L*1024L,2L*1024L*1024L,input->runtime);if(!rt){js_delete(input);return;}JS_SetErrorReporter(rt,my_ErrorReporter);JSContext*cx=NewContext(rt);if(!cx){JS_DestroyRuntime(rt);js_delete(input);return;}JS::SetLargeAllocationFailureCallback(rt,my_LargeAllocFailCallback,(void*)cx);do{JSAutoRequestar(cx);JS::CompartmentOptionscompartmentOptions;compartmentOptions.setVersion(JSVERSION_LATEST);RootedObjectglobal(cx,NewGlobalObject(cx,compartmentOptions,nullptr));if(!global)break;JSAutoCompartmentac(cx,global);JS::CompileOptionsoptions(cx);options.setFileAndLine("<string>",1).setCompileAndGo(true);RootedScriptscript(cx);if(!JS::Compile(cx,global,options,input->chars,input->length,&script))break;RootedValueresult(cx);JS_ExecuteScript(cx,global,script,&result);}while(0);JS::SetLargeAllocationFailureCallback(rt,nullptr,nullptr);DestroyContext(cx,false);JS_DestroyRuntime(rt);js_delete(input);}Vector<PRThread*,0,SystemAllocPolicy>workerThreads;staticboolEvalInWorker(JSContext*cx,unsignedargc,jsval*vp){if(!CanUseExtraThreads()){JS_ReportError(cx,"Can't create worker threads with --no-threads");returnfalse;}CallArgsargs=CallArgsFromVp(argc,vp);if(!args.get(0).isString()){JS_ReportError(cx,"Invalid arguments to evalInWorker");returnfalse;}if(!args[0].toString()->ensureLinear(cx))returnfalse;JSLinearString*str=&args[0].toString()->asLinear();char16_t*chars=(char16_t*)js_malloc(str->length()*sizeof(char16_t));if(!chars)returnfalse;CopyChars(chars,*str);WorkerInput*input=js_new<WorkerInput>(cx->runtime(),chars,str->length());if(!input)returnfalse;PRThread*thread=PR_CreateThread(PR_USER_THREAD,WorkerMain,input,PR_PRIORITY_NORMAL,PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,0);if(!thread||!workerThreads.append(thread))returnfalse;returntrue;}staticboolShapeOf(JSContext*cx,unsignedargc,JS::Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(!args.get(0).isObject()){JS_ReportError(cx,"shapeOf: object expected");returnfalse;}JSObject*obj=&args[0].toObject();args.rval().set(JS_NumberValue(double(uintptr_t(obj->lastProperty())>>3)));returntrue;}/* * Check that t1 comes strictly before t2. The function correctly deals with * wrap-around between t2 and t1 assuming that t2 and t1 stays within INT32_MAX * from each other. We use MAX_TIMEOUT_INTERVAL to enforce this restriction. */staticboolIsBefore(int64_tt1,int64_tt2){returnint32_t(t1-t2)<0;}staticboolSleep_fn(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);int64_tt_ticks;if(args.length()==0){t_ticks=0;}else{doublet_secs;if(!ToNumber(cx,args[0],&t_secs))returnfalse;/* NB: The next condition also filter out NaNs. */if(!(t_secs<=MAX_TIMEOUT_INTERVAL)){JS_ReportError(cx,"Excessive sleep interval");returnfalse;}t_ticks=(t_secs<=0.0)?0:int64_t(PRMJ_USEC_PER_SEC*t_secs);}PR_Lock(gWatchdogLock);int64_tto_wakeup=PRMJ_Now()+t_ticks;for(;;){PR_WaitCondVar(gSleepWakeup,PR_MillisecondsToInterval(t_ticks/1000));if(gServiceInterrupt)break;int64_tnow=PRMJ_Now();if(!IsBefore(now,to_wakeup))break;t_ticks=to_wakeup-now;}PR_Unlock(gWatchdogLock);args.rval().setUndefined();return!gServiceInterrupt;}staticboolInitWatchdog(JSRuntime*rt){MOZ_ASSERT(!gWatchdogThread);gWatchdogLock=PR_NewLock();if(gWatchdogLock){gWatchdogWakeup=PR_NewCondVar(gWatchdogLock);if(gWatchdogWakeup){gSleepWakeup=PR_NewCondVar(gWatchdogLock);if(gSleepWakeup)returntrue;PR_DestroyCondVar(gWatchdogWakeup);}PR_DestroyLock(gWatchdogLock);}returnfalse;}staticvoidKillWatchdog(){PRThread*thread;PR_Lock(gWatchdogLock);thread=gWatchdogThread;if(thread){/* * The watchdog thread is running, tell it to terminate waking it up * if necessary. */gWatchdogThread=nullptr;PR_NotifyCondVar(gWatchdogWakeup);}PR_Unlock(gWatchdogLock);if(thread)PR_JoinThread(thread);PR_DestroyCondVar(gSleepWakeup);PR_DestroyCondVar(gWatchdogWakeup);PR_DestroyLock(gWatchdogLock);}staticvoidWatchdogMain(void*arg){PR_SetCurrentThreadName("JS Watchdog");JSRuntime*rt=(JSRuntime*)arg;PR_Lock(gWatchdogLock);while(gWatchdogThread){int64_tnow=PRMJ_Now();if(gWatchdogHasTimeout&&!IsBefore(now,gWatchdogTimeout)){/* * The timeout has just expired. Request an interrupt callback * outside the lock. */gWatchdogHasTimeout=false;PR_Unlock(gWatchdogLock);CancelExecution(rt);PR_Lock(gWatchdogLock);/* Wake up any threads doing sleep. */PR_NotifyAllCondVar(gSleepWakeup);}else{if(gWatchdogHasTimeout){/* * Time hasn't expired yet. Simulate an interrupt callback * which doesn't abort execution. */JS_RequestInterruptCallback(rt);}uint64_tsleepDuration=PR_INTERVAL_NO_TIMEOUT;if(gWatchdogHasTimeout)sleepDuration=PR_TicksPerSecond()/10;mozilla::DebugOnly<PRStatus>status=PR_WaitCondVar(gWatchdogWakeup,sleepDuration);MOZ_ASSERT(status==PR_SUCCESS);}}PR_Unlock(gWatchdogLock);}staticboolScheduleWatchdog(JSRuntime*rt,doublet){if(t<=0){PR_Lock(gWatchdogLock);gWatchdogHasTimeout=false;PR_Unlock(gWatchdogLock);returntrue;}int64_tinterval=int64_t(ceil(t*PRMJ_USEC_PER_SEC));int64_ttimeout=PRMJ_Now()+interval;PR_Lock(gWatchdogLock);if(!gWatchdogThread){MOZ_ASSERT(!gWatchdogHasTimeout);gWatchdogThread=PR_CreateThread(PR_USER_THREAD,WatchdogMain,rt,PR_PRIORITY_NORMAL,PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,0);if(!gWatchdogThread){PR_Unlock(gWatchdogLock);returnfalse;}}elseif(!gWatchdogHasTimeout||IsBefore(timeout,gWatchdogTimeout)){PR_NotifyCondVar(gWatchdogWakeup);}gWatchdogHasTimeout=true;gWatchdogTimeout=timeout;PR_Unlock(gWatchdogLock);returntrue;}staticvoidCancelExecution(JSRuntime*rt){gServiceInterrupt=true;JS_RequestInterruptCallback(rt);if(!gInterruptFunc.isNull()){staticconstcharmsg[]="Script runs for too long, terminating.\n";fputs(msg,stderr);}}staticboolSetTimeoutValue(JSContext*cx,doublet){/* NB: The next condition also filter out NaNs. */if(!(t<=MAX_TIMEOUT_INTERVAL)){JS_ReportError(cx,"Excessive timeout value");returnfalse;}gTimeoutInterval=t;if(!ScheduleWatchdog(cx->runtime(),t)){JS_ReportError(cx,"Failed to create the watchdog");returnfalse;}returntrue;}staticboolTimeout(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()==0){args.rval().setNumber(gTimeoutInterval);returntrue;}if(args.length()>2){JS_ReportError(cx,"Wrong number of arguments");returnfalse;}doublet;if(!ToNumber(cx,args[0],&t))returnfalse;if(args.length()>1){RootedValuevalue(cx,args[1]);if(!value.isObject()||!value.toObject().is<JSFunction>()){JS_ReportError(cx,"Second argument must be a timeout function");returnfalse;}gInterruptFunc=value;}args.rval().setUndefined();returnSetTimeoutValue(cx,t);}staticboolInterruptIf(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1){JS_ReportError(cx,"Wrong number of arguments");returnfalse;}if(ToBoolean(args[0])){gServiceInterrupt=true;JS_RequestInterruptCallback(cx->runtime());}args.rval().setUndefined();returntrue;}staticboolInvokeInterruptCallbackWrapper(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1){JS_ReportError(cx,"Wrong number of arguments");returnfalse;}gServiceInterrupt=true;JS_RequestInterruptCallback(cx->runtime());boolinterruptRv=CheckForInterrupt(cx);// The interrupt handler could have set a pending exception. Since we call// back into JS, don't have it see the pending exception. If we have an// uncatchable exception that's not propagating a debug mode forced// return, return.if(!interruptRv&&!cx->isExceptionPending()&&!cx->isPropagatingForcedReturn())returnfalse;JS::AutoSaveExceptionStatesavedExc(cx);Valueargv[1]={BooleanValue(interruptRv)};RootedValuerv(cx);if(!Invoke(cx,UndefinedValue(),args[0],1,argv,&rv))returnfalse;args.rval().setUndefined();returninterruptRv;}staticboolSetInterruptCallback(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1){JS_ReportError(cx,"Wrong number of arguments");returnfalse;}RootedValuevalue(cx,args[0]);if(!value.isObject()||!value.toObject().is<JSFunction>()){JS_ReportError(cx,"Argument must be a function");returnfalse;}gInterruptFunc=value;args.rval().setUndefined();returntrue;}#ifdef DEBUGstaticboolStackDump(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);boolshowArgs=ToBoolean(args.get(0));boolshowLocals=ToBoolean(args.get(1));boolshowThisProps=ToBoolean(args.get(2));char*buf=JS::FormatStackDump(cx,nullptr,showArgs,showLocals,showThisProps);if(!buf){fputs("Failed to format JavaScript stack for dump\n",gOutFile);}else{fputs(buf,gOutFile);JS_smprintf_free(buf);}args.rval().setUndefined();returntrue;}#endifstaticboolElapsed(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()==0){doubled=0.0;JSShellContextData*data=GetContextData(cx);if(data)d=PRMJ_Now()-data->startTime;args.rval().setDouble(d);returntrue;}JS_ReportError(cx,"Wrong number of arguments");returnfalse;}staticboolParent(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1){JS_ReportError(cx,"Wrong number of arguments");returnfalse;}Valuev=args[0];if(v.isPrimitive()){JS_ReportError(cx,"Only objects have parents!");returnfalse;}Rooted<JSObject*>parent(cx,JS_GetParent(&v.toObject()));/* Outerize if necessary. */if(parent){parent=GetOuterObject(cx,parent);if(!parent)returnfalse;}args.rval().setObjectOrNull(parent);returntrue;}staticboolCompile(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_MORE_ARGS_NEEDED,"compile","0","s");returnfalse;}if(!args[0].isString()){constchar*typeName=InformalValueTypeName(args[0]);JS_ReportError(cx,"expected string to compile, got %s",typeName);returnfalse;}RootedObjectglobal(cx,JS::CurrentGlobalOrNull(cx));JSFlatString*scriptContents=args[0].toString()->ensureFlat(cx);if(!scriptContents)returnfalse;AutoStableStringCharsstableChars(cx);if(!stableChars.initTwoByte(cx,scriptContents))returnfalse;JS::CompileOptionsoptions(cx);options.setIntroductionType("js shell compile").setFileAndLine("<string>",1).setCompileAndGo(true).setNoScriptRval(true);RootedScriptscript(cx);constchar16_t*chars=stableChars.twoByteRange().start().get();boolok=JS_CompileUCScript(cx,global,chars,scriptContents->length(),options,&script);args.rval().setUndefined();returnok;}staticboolParse(JSContext*cx,unsignedargc,jsval*vp){usingnamespacejs::frontend;CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_MORE_ARGS_NEEDED,"parse","0","s");returnfalse;}if(!args[0].isString()){constchar*typeName=InformalValueTypeName(args[0]);JS_ReportError(cx,"expected string to parse, got %s",typeName);returnfalse;}JSFlatString*scriptContents=args[0].toString()->ensureFlat(cx);if(!scriptContents)returnfalse;AutoStableStringCharsstableChars(cx);if(!stableChars.initTwoByte(cx,scriptContents))returnfalse;size_tlength=scriptContents->length();constchar16_t*chars=stableChars.twoByteRange().start().get();CompileOptionsoptions(cx);options.setIntroductionType("js shell parse").setFileAndLine("<string>",1).setCompileAndGo(false);Parser<FullParseHandler>parser(cx,&cx->tempLifoAlloc(),options,chars,length,/* foldConstants = */true,nullptr,nullptr);if(!parser.checkOptions())returnfalse;ParseNode*pn=parser.parse(nullptr);if(!pn)returnfalse;#ifdef DEBUGDumpParseTree(pn);fputc('\n',stderr);#endifargs.rval().setUndefined();returntrue;}staticboolSyntaxParse(JSContext*cx,unsignedargc,jsval*vp){usingnamespacejs::frontend;CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_MORE_ARGS_NEEDED,"parse","0","s");returnfalse;}if(!args[0].isString()){constchar*typeName=InformalValueTypeName(args[0]);JS_ReportError(cx,"expected string to parse, got %s",typeName);returnfalse;}JSFlatString*scriptContents=args[0].toString()->ensureFlat(cx);if(!scriptContents)returnfalse;CompileOptionsoptions(cx);options.setIntroductionType("js shell syntaxParse").setFileAndLine("<string>",1).setCompileAndGo(false);AutoStableStringCharsstableChars(cx);if(!stableChars.initTwoByte(cx,scriptContents))returnfalse;constchar16_t*chars=stableChars.twoByteRange().start().get();size_tlength=scriptContents->length();Parser<frontend::SyntaxParseHandler>parser(cx,&cx->tempLifoAlloc(),options,chars,length,false,nullptr,nullptr);if(!parser.checkOptions())returnfalse;boolsucceeded=parser.parse(nullptr);if(cx->isExceptionPending())returnfalse;if(!succeeded&&!parser.hadAbortedSyntaxParse()){// If no exception is posted, either there was an OOM or a language// feature unhandled by the syntax parser was encountered.MOZ_ASSERT(cx->runtime()->hadOutOfMemory);returnfalse;}args.rval().setBoolean(succeeded);returntrue;}classOffThreadState{public:enumState{IDLE,/* ready to work; no token, no source */COMPILING,/* working; no token, have source */DONE/* compilation done: have token and source */};OffThreadState():monitor(),state(IDLE),token(),source(nullptr){}boolinit(){returnmonitor.init();}boolstartIfIdle(JSContext*cx,ScopedJSFreePtr<char16_t>&newSource){AutoLockMonitoralm(monitor);if(state!=IDLE)returnfalse;MOZ_ASSERT(!token);source=newSource.forget();state=COMPILING;returntrue;}voidabandon(JSContext*cx){AutoLockMonitoralm(monitor);MOZ_ASSERT(state==COMPILING);MOZ_ASSERT(!token);MOZ_ASSERT(source);js_free(source);source=nullptr;state=IDLE;}voidmarkDone(void*newToken){AutoLockMonitoralm(monitor);MOZ_ASSERT(state==COMPILING);MOZ_ASSERT(!token);MOZ_ASSERT(source);MOZ_ASSERT(newToken);token=newToken;state=DONE;alm.notify();}void*waitUntilDone(JSContext*cx){AutoLockMonitoralm(monitor);if(state==IDLE)returnnullptr;if(state==COMPILING){while(state!=DONE)alm.wait();}MOZ_ASSERT(source);js_free(source);source=nullptr;MOZ_ASSERT(token);void*holdToken=token;token=nullptr;state=IDLE;returnholdToken;}private:Monitormonitor;Statestate;void*token;char16_t*source;};staticOffThreadStateoffThreadState;staticvoidOffThreadCompileScriptCallback(void*token,void*callbackData){offThreadState.markDone(token);}staticboolOffThreadCompileScript(JSContext*cx,unsignedargc,jsval*vp){if(!CanUseExtraThreads()){JS_ReportError(cx,"Can't use offThreadCompileScript with --no-threads");returnfalse;}CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_MORE_ARGS_NEEDED,"offThreadCompileScript","0","s");returnfalse;}if(!args[0].isString()){constchar*typeName=InformalValueTypeName(args[0]);JS_ReportError(cx,"expected string to parse, got %s",typeName);returnfalse;}JSAutoByteStringfileNameBytes;CompileOptionsoptions(cx);options.setIntroductionType("js shell offThreadCompileScript").setFileAndLine("<string>",1);if(args.length()>=2){if(args[1].isPrimitive()){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"evaluate");returnfalse;}RootedObjectopts(cx,&args[1].toObject());if(!ParseCompileOptions(cx,options,opts,fileNameBytes))returnfalse;}// These option settings must override whatever the caller requested.options.setCompileAndGo(true).setSourceIsLazy(false);// We assume the caller wants caching if at all possible, ignoring// heuristics that make sense for a real browser.options.forceAsync=true;JSString*scriptContents=args[0].toString();AutoStableStringCharsstableChars(cx);if(!stableChars.initTwoByte(cx,scriptContents))returnfalse;size_tlength=scriptContents->length();constchar16_t*chars=stableChars.twoByteRange().start().get();// Make sure we own the string's chars, so that they are not freed before// the compilation is finished.ScopedJSFreePtr<char16_t>ownedChars;if(stableChars.maybeGiveOwnershipToCaller()){ownedChars=const_cast<char16_t*>(chars);}else{char16_t*copy=cx->pod_malloc<char16_t>(length);if(!copy)returnfalse;mozilla::PodCopy(copy,chars,length);ownedChars=copy;chars=copy;}if(!JS::CanCompileOffThread(cx,options,length)){JS_ReportError(cx,"cannot compile code on worker thread");returnfalse;}if(!offThreadState.startIfIdle(cx,ownedChars)){JS_ReportError(cx,"called offThreadCompileScript without calling runOffThreadScript"" to receive prior off-thread compilation");returnfalse;}if(!JS::CompileOffThread(cx,options,chars,length,OffThreadCompileScriptCallback,nullptr)){offThreadState.abandon(cx);returnfalse;}args.rval().setUndefined();returntrue;}staticboolrunOffThreadScript(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);void*token=offThreadState.waitUntilDone(cx);if(!token){JS_ReportError(cx,"called runOffThreadScript when no compilation is pending");returnfalse;}RootedScriptscript(cx,JS::FinishOffThreadScript(cx,cx->runtime(),token));if(!script)returnfalse;returnJS_ExecuteScript(cx,cx->global(),script,args.rval());}structFreeOnReturn{JSContext*cx;constchar*ptr;MOZ_DECL_USE_GUARD_OBJECT_NOTIFIERexplicitFreeOnReturn(JSContext*cx,constchar*ptr=nullptrMOZ_GUARD_OBJECT_NOTIFIER_PARAM):cx(cx),ptr(ptr){MOZ_GUARD_OBJECT_NOTIFIER_INIT;}voidinit(constchar*ptr){MOZ_ASSERT(!this->ptr);this->ptr=ptr;}~FreeOnReturn(){JS_free(cx,(void*)ptr);}};staticboolReadFile(JSContext*cx,unsignedargc,jsval*vp,boolscriptRelative){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1||args.length()>2){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,args.length()<1?JSSMSG_NOT_ENOUGH_ARGS:JSSMSG_TOO_MANY_ARGS,"snarf");returnfalse;}if(!args[0].isString()||(args.length()==2&&!args[1].isString())){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"snarf");returnfalse;}RootedStringgivenPath(cx,args[0].toString());RootedStringstr(cx,ResolvePath(cx,givenPath,scriptRelative?ScriptRelative:RootRelative));if(!str)returnfalse;JSAutoByteStringfilename(cx,str);if(!filename)returnfalse;if(args.length()>1){JSString*opt=JS::ToString(cx,args[1]);if(!opt)returnfalse;boolmatch;if(!JS_StringEqualsAscii(cx,opt,"binary",&match))returnfalse;if(match){JSObject*obj;if(!(obj=FileAsTypedArray(cx,filename.ptr())))returnfalse;args.rval().setObject(*obj);returntrue;}}if(!(str=FileAsString(cx,filename.ptr())))returnfalse;args.rval().setString(str);returntrue;}staticboolSnarf(JSContext*cx,unsignedargc,jsval*vp){returnReadFile(cx,argc,vp,false);}staticboolReadRelativeToScript(JSContext*cx,unsignedargc,jsval*vp){returnReadFile(cx,argc,vp,true);}staticboolredirect(JSContext*cx,FILE*fp,HandleStringrelFilename){RootedStringfilename(cx,ResolvePath(cx,relFilename,RootRelative));if(!filename)returnfalse;JSAutoByteStringfilenameABS(cx,filename);if(!filenameABS)returnfalse;if(freopen(filenameABS.ptr(),"wb",fp)==nullptr){JS_ReportError(cx,"cannot redirect to %s: %s",filenameABS.ptr(),strerror(errno));returnfalse;}returntrue;}staticboolRedirectOutput(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1||args.length()>2){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"redirect");returnfalse;}if(args[0].isString()){RootedStringstdoutPath(cx,args[0].toString());if(!stdoutPath)returnfalse;if(!redirect(cx,stdout,stdoutPath))returnfalse;}if(args.length()>1&&args[1].isString()){RootedStringstderrPath(cx,args[1].toString());if(!stderrPath)returnfalse;if(!redirect(cx,stderr,stderrPath))returnfalse;}args.rval().setUndefined();returntrue;}staticintsArgc;staticchar**sArgv;classAutoCStringVector{Vector<char*>argv_;public:explicitAutoCStringVector(JSContext*cx):argv_(cx){}~AutoCStringVector(){for(size_ti=0;i<argv_.length();i++)js_free(argv_[i]);}boolappend(char*arg){if(!argv_.append(arg)){js_free(arg);returnfalse;}returntrue;}char*const*get()const{returnargv_.begin();}size_tlength()const{returnargv_.length();}char*operator[](size_ti)const{returnargv_[i];}voidreplace(size_ti,char*arg){js_free(argv_[i]);argv_[i]=arg;}char*back()const{returnargv_.back();}voidreplaceBack(char*arg){js_free(argv_.back());argv_.back()=arg;}};#if defined(XP_WIN)staticboolEscapeForShell(AutoCStringVector&argv){// Windows will break arguments in argv by various spaces, so we wrap each// argument in quotes and escape quotes within. Even with quotes, \ will be// treated like an escape character, so inflate each \ to \\.for(size_ti=0;i<argv.length();i++){if(!argv[i])continue;size_tnewLen=3;// quotes before and after and null-terminatorfor(char*p=argv[i];*p;p++){newLen++;if(*p=='\"'||*p=='\\')newLen++;}char*escaped=(char*)js_malloc(newLen);if(!escaped)returnfalse;char*src=argv[i];char*dst=escaped;*dst++='\"';while(*src){if(*src=='\"'||*src=='\\')*dst++='\\';*dst++=*src++;}*dst++='\"';*dst++='\0';MOZ_ASSERT(escaped+newLen==dst);argv.replace(i,escaped);}returntrue;}#endifstaticVector<constchar*,4,js::SystemAllocPolicy>sPropagatedFlags;#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)staticboolPropagateFlagToNestedShells(constchar*flag){returnsPropagatedFlags.append(flag);}#endifstaticboolNestedShell(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);AutoCStringVectorargv(cx);// The first argument to the shell is its path, which we assume is our own// argv[0].if(sArgc<1){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_NESTED_FAIL);returnfalse;}if(!argv.append(strdup(sArgv[0])))returnfalse;// Propagate selected flags from the current shellfor(unsignedi=0;i<sPropagatedFlags.length();i++){char*cstr=strdup(sPropagatedFlags[i]);if(!cstr||!argv.append(cstr))returnfalse;}// The arguments to nestedShell are stringified and append to argv.RootedStringstr(cx);for(unsignedi=0;i<args.length();i++){str=ToString(cx,args[i]);if(!str||!argv.append(JS_EncodeString(cx,str)))returnfalse;// As a special case, if the caller passes "--js-cache", replace that// with "--js-cache=$(jsCacheDir)"if(!strcmp(argv.back(),"--js-cache")&&jsCacheDir){char*newArg=JS_smprintf("--js-cache=%s",jsCacheDir);if(!newArg)returnfalse;argv.replaceBack(newArg);}}// execv assumes argv is null-terminatedif(!argv.append(nullptr))returnfalse;intstatus=0;#if defined(XP_WIN)if(!EscapeForShell(argv))returnfalse;status=_spawnv(_P_WAIT,sArgv[0],argv.get());#elsepid_tpid=fork();switch(pid){case-1:JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_NESTED_FAIL);returnfalse;case0:(void)execv(sArgv[0],argv.get());exit(-1);default:{while(waitpid(pid,&status,0)<0&&errno==EINTR)continue;break;}}#endifif(status!=0){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_NESTED_FAIL);returnfalse;}args.rval().setUndefined();returntrue;}staticboolDecompileFunctionSomehow(JSContext*cx,unsignedargc,Value*vp,JSString*(*decompiler)(JSContext*,HandleFunction,unsigned)){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()<1||!args[0].isObject()||!args[0].toObject().is<JSFunction>()){args.rval().setUndefined();returntrue;}RootedFunctionfun(cx,&args[0].toObject().as<JSFunction>());JSString*result=decompiler(cx,fun,0);if(!result)returnfalse;args.rval().setString(result);returntrue;}staticboolDecompileBody(JSContext*cx,unsignedargc,Value*vp){returnDecompileFunctionSomehow(cx,argc,vp,JS_DecompileFunctionBody);}staticboolDecompileFunction(JSContext*cx,unsignedargc,Value*vp){returnDecompileFunctionSomehow(cx,argc,vp,JS_DecompileFunction);}staticboolDecompileThisScript(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);NonBuiltinScriptFrameIteriter(cx);if(iter.done()){args.rval().setString(cx->runtime()->emptyString);returntrue;}{JSAutoCompartmentac(cx,iter.script());RootedScriptscript(cx,iter.script());JSString*result=JS_DecompileScript(cx,script,"test",0);if(!result)returnfalse;args.rval().setString(result);}returnJS_WrapValue(cx,args.rval());}staticboolThisFilename(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);JS::AutoFilenamefilename;if(!DescribeScriptedCaller(cx,&filename)||!filename.get()){args.rval().setString(cx->runtime()->emptyString);returntrue;}JSString*str=JS_NewStringCopyZ(cx,filename.get());if(!str)returnfalse;args.rval().setString(str);returntrue;}staticboolWrap(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);Valuev=args.get(0);if(v.isPrimitive()){args.rval().set(v);returntrue;}RootedObjectobj(cx,v.toObjectOrNull());JSObject*wrapped=Wrapper::New(cx,obj,&obj->global(),&Wrapper::singleton);if(!wrapped)returnfalse;args.rval().setObject(*wrapped);returntrue;}staticboolWrapWithProto(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);Valueobj=UndefinedValue(),proto=UndefinedValue();if(args.length()==2){obj=args[0];proto=args[1];}if(!obj.isObject()||!proto.isObjectOrNull()){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"wrapWithProto");returnfalse;}WrapperOptionsoptions(cx);options.setProto(proto.toObjectOrNull());JSObject*wrapped=Wrapper::New(cx,&obj.toObject(),&obj.toObject().global(),&Wrapper::singletonWithPrototype,options);if(!wrapped)returnfalse;args.rval().setObject(*wrapped);returntrue;}staticboolNewGlobal(JSContext*cx,unsignedargc,jsval*vp){JSPrincipals*principals=nullptr;JS::CompartmentOptionsoptions;options.setVersion(JSVERSION_LATEST);CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()==1&&args[0].isObject()){RootedObjectopts(cx,&args[0].toObject());RootedValuev(cx);if(!JS_GetProperty(cx,opts,"sameZoneAs",&v))returnfalse;if(v.isObject())options.setSameZoneAs(UncheckedUnwrap(&v.toObject()));if(!JS_GetProperty(cx,opts,"invisibleToDebugger",&v))returnfalse;if(v.isBoolean())options.setInvisibleToDebugger(v.toBoolean());if(!JS_GetProperty(cx,opts,"principal",&v))returnfalse;if(!v.isUndefined()){uint32_tbits;if(!ToUint32(cx,v,&bits))returnfalse;principals=cx->new_<ShellPrincipals>(bits);if(!principals)returnfalse;JS_HoldPrincipals(principals);}}RootedObjectglobal(cx,NewGlobalObject(cx,options,principals));if(principals)JS_DropPrincipals(cx->runtime(),principals);if(!global)returnfalse;if(!JS_WrapObject(cx,&global))returnfalse;args.rval().setObject(*global);returntrue;}staticboolGetMaxArgs(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);args.rval().setInt32(ARGS_LENGTH_MAX);returntrue;}staticboolObjectEmulatingUndefined(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);staticconstJSClasscls={"ObjectEmulatingUndefined",JSCLASS_EMULATES_UNDEFINED};RootedObjectobj(cx,JS_NewObject(cx,&cls));if(!obj)returnfalse;args.rval().setObject(*obj);returntrue;}staticboolGetSelfHostedValue(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(args.length()!=1||!args[0].isString()){JS_ReportErrorNumber(cx,my_GetErrorMessage,nullptr,JSSMSG_INVALID_ARGS,"getSelfHostedValue");returnfalse;}RootedAtomsrcAtom(cx,ToAtom<CanGC>(cx,args[0]));if(!srcAtom)returnfalse;RootedPropertyNamesrcName(cx,srcAtom->asPropertyName());returncx->runtime()->cloneSelfHostedValue(cx,srcName,args.rval());}classShellSourceHook:publicSourceHook{// The function we should call to lazily retrieve source code.PersistentRootedFunctionfun;public:ShellSourceHook(JSContext*cx,JSFunction&fun):fun(cx,&fun){}boolload(JSContext*cx,constchar*filename,char16_t**src,size_t*length){RootedStringstr(cx,JS_NewStringCopyZ(cx,filename));if(!str)returnfalse;RootedValuefilenameValue(cx,StringValue(str));RootedValueresult(cx);if(!Call(cx,UndefinedHandleValue,fun,HandleValueArray(filenameValue),&result))returnfalse;str=JS::ToString(cx,result);if(!str)returnfalse;*length=JS_GetStringLength(str);*src=cx->pod_malloc<char16_t>(*length);if(!*src)returnfalse;JSLinearString*linear=str->ensureLinear(cx);if(!linear)returnfalse;CopyChars(*src,*linear);returntrue;}};staticboolWithSourceHook(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedObjectcallee(cx,&args.callee());if(args.length()!=2){ReportUsageError(cx,callee,"Wrong number of arguments.");returnfalse;}if(!args[0].isObject()||!args[0].toObject().is<JSFunction>()||!args[1].isObject()||!args[1].toObject().is<JSFunction>()){ReportUsageError(cx,callee,"First and second arguments must be functions.");returnfalse;}UniquePtr<ShellSourceHook>hook=MakeUnique<ShellSourceHook>(cx,args[0].toObject().as<JSFunction>());if(!hook)returnfalse;UniquePtr<SourceHook>savedHook=js::ForgetSourceHook(cx->runtime());js::SetSourceHook(cx->runtime(),Move(hook));RootedObjectfun(cx,&args[1].toObject());boolresult=Call(cx,UndefinedHandleValue,fun,JS::HandleValueArray::empty(),args.rval());js::SetSourceHook(cx->runtime(),Move(savedHook));returnresult;}staticboolIsCachingEnabled(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);args.rval().setBoolean(jsCachingEnabled&&jsCacheAsmJSPath!=nullptr);returntrue;}staticboolSetCachingEnabled(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);jsCachingEnabled=ToBoolean(args.get(0));args.rval().setUndefined();returntrue;}staticvoidPrintProfilerEvents_Callback(constchar*msg){fprintf(stderr,"PROFILER EVENT: %s\n",msg);}staticboolPrintProfilerEvents(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);if(cx->runtime()->spsProfiler.enabled())js::RegisterRuntimeProfilingEventMarker(cx->runtime(),&PrintProfilerEvents_Callback);args.rval().setUndefined();returntrue;}#if defined(JS_ARM_SIMULATOR)typedefVector<char16_t,0,SystemAllocPolicy>StackChars;Vector<StackChars,0,SystemAllocPolicy>stacks;staticvoidSingleStepCallback(void*arg,jit::Simulator*sim,void*pc){JSRuntime*rt=reinterpret_cast<JSRuntime*>(arg);// If profiling is not enabled, don't do anything.if(!rt->spsProfiler.enabled())return;JS::ProfilingFrameIterator::RegisterStatestate;state.pc=pc;state.sp=(void*)sim->get_register(jit::Simulator::sp);state.lr=(void*)sim->get_register(jit::Simulator::lr);DebugOnly<void*>lastStackAddress=nullptr;StackCharsstack;uint32_tframeNo=0;for(JS::ProfilingFrameIteratori(rt,state);!i.done();++i){MOZ_ASSERT(i.stackAddress()!=nullptr);MOZ_ASSERT(lastStackAddress<=i.stackAddress());lastStackAddress=i.stackAddress();JS::ProfilingFrameIterator::Frameframes[16];uint32_tnframes=i.extractStack(frames,0,16);for(uint32_ti=0;i<nframes;i++){if(frameNo>0)stack.append(",",1);stack.append(frames[i].label,strlen(frames[i].label));frameNo++;}}// Only append the stack if it differs from the last stack.if(stacks.empty()||stacks.back().length()!=stack.length()||!PodEqual(stacks.back().begin(),stack.begin(),stack.length())){stacks.append(Move(stack));}}#endifstaticboolEnableSingleStepProfiling(JSContext*cx,unsignedargc,Value*vp){#if defined(JS_ARM_SIMULATOR)CallArgsargs=CallArgsFromVp(argc,vp);jit::Simulator*sim=cx->runtime()->simulator();sim->enable_single_stepping(SingleStepCallback,cx->runtime());args.rval().setUndefined();returntrue;#elseJS_ReportError(cx,"single-step profiling not enabled on this platform");returnfalse;#endif}staticboolDisableSingleStepProfiling(JSContext*cx,unsignedargc,Value*vp){#if defined(JS_ARM_SIMULATOR)CallArgsargs=CallArgsFromVp(argc,vp);jit::Simulator*sim=cx->runtime()->simulator();sim->disable_single_stepping();AutoValueVectorelems(cx);for(size_ti=0;i<stacks.length();i++){JSString*stack=JS_NewUCStringCopyN(cx,stacks[i].begin(),stacks[i].length());if(!stack)returnfalse;if(!elems.append(StringValue(stack)))returnfalse;}JSObject*array=JS_NewArrayObject(cx,elems);if(!array)returnfalse;stacks.clear();args.rval().setObject(*array);returntrue;#elseJS_ReportError(cx,"single-step profiling not enabled on this platform");returnfalse;#endif}staticboolIsLatin1(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);boolisLatin1=args.get(0).isString()&&args[0].toString()->hasLatin1Chars();args.rval().setBoolean(isLatin1);returntrue;}staticconstJSFunctionSpecWithHelpshell_functions[]={JS_FN_HELP("version",Version,0,0,"version([number])"," Get or force a script compilation version number."),JS_FN_HELP("options",Options,0,0,"options([option ...])"," Get or toggle JavaScript options."),JS_FN_HELP("load",Load,1,0,"load(['foo.js' ...])"," Load files named by string arguments. Filename is relative to the\n"" current working directory."),JS_FN_HELP("loadRelativeToScript",LoadScriptRelativeToScript,1,0,"loadRelativeToScript(['foo.js' ...])"," Load files named by string arguments. Filename is relative to the\n"" calling script."),JS_FN_HELP("evaluate",Evaluate,2,0,"evaluate(code[, options])"," Evaluate code as though it were the contents of a file.\n"" options is an optional object that may have these properties:\n"" compileAndGo: use the compile-and-go compiler option (default: true)\n"" noScriptRval: use the no-script-rval compiler option (default: false)\n"" fileName: filename for error messages and debug info\n"" lineNumber: starting line number for error messages and debug info\n"" columnNumber: starting column number for error messages and debug info\n"" global: global in which to execute the code\n"" newContext: if true, create and use a new cx (default: false)\n"" saveFrameChain: if true, save the frame chain before evaluating code\n"" and restore it afterwards\n"" catchTermination: if true, catch termination (failure without\n"" an exception value, as for slow scripts or out-of-memory)\n"" and return 'terminated'\n"" element: if present with value |v|, convert |v| to an object |o| and\n"" mark the source as being attached to the DOM element |o|. If the\n"" property is omitted or |v| is null, don't attribute the source to\n"" any DOM element.\n"" elementAttributeName: if present and not undefined, the name of\n"" property of 'element' that holds this code. This is what\n"" Debugger.Source.prototype.elementAttributeName returns.\n"" sourceMapURL: if present with value |v|, convert |v| to a string, and\n"" provide that as the code's source map URL. If omitted, attach no\n"" source map URL to the code (although the code may provide one itself,\n"" via a //#sourceMappingURL comment).\n"" sourceIsLazy: if present and true, indicates that, after compilation, \n""script source should not be cached by the JS engine and should be \n""lazily loaded from the embedding as-needed.\n"" loadBytecode: if true, and if the source is a CacheEntryObject,\n"" the bytecode would be loaded and decoded from the cache entry instead\n"" of being parsed, then it would be executed as usual.\n"" saveBytecode: if true, and if the source is a CacheEntryObject,\n"" the bytecode would be encoded and saved into the cache entry after\n"" the script execution.\n"" assertEqBytecode: if true, and if both loadBytecode and saveBytecode are \n"" true, then the loaded bytecode and the encoded bytecode are compared.\n"" and an assertion is raised if they differ.\n"),JS_FN_HELP("run",Run,1,0,"run('foo.js')"," Run the file named by the first argument, returning the number of\n"" of milliseconds spent compiling and executing it."),JS_FN_HELP("readline",ReadLine,0,0,"readline()"," Read a single line from stdin."),JS_FN_HELP("print",Print,0,0,"print([exp ...])"," Evaluate and print expressions to stdout."),JS_FN_HELP("printErr",PrintErr,0,0,"printErr([exp ...])"," Evaluate and print expressions to stderr."),JS_FN_HELP("putstr",PutStr,0,0,"putstr([exp])"," Evaluate and print expression without newline."),JS_FN_HELP("dateNow",Now,0,0,"dateNow()"," Return the current time with sub-ms precision."),JS_FN_HELP("help",Help,0,0,"help([name ...])"," Display usage and help messages."),JS_FN_HELP("quit",Quit,0,0,"quit()"," Quit the shell."),JS_FN_HELP("assertEq",AssertEq,2,0,"assertEq(actual, expected[, msg])"," Throw if the first two arguments are not the same (both +0 or both -0,\n"" both NaN, or non-zero and ===)."),JS_FN_HELP("setGCCallback",SetGCCallback,1,0,"setGCCallback({action:\"...\", options...})"," Set the GC callback. action may be:\n"" 'minorGC' - run a nursery collection\n"" 'majorGC' - run a major collection, nesting up to a given 'depth'\n"),JS_FN_HELP("startTimingMutator",StartTimingMutator,0,0,"startTimingMutator()"," Start accounting time to mutator vs GC."),JS_FN_HELP("stopTimingMutator",StopTimingMutator,0,0,"stopTimingMutator()"," Stop accounting time to mutator vs GC and dump the results."),JS_FN_HELP("throwError",ThrowError,0,0,"throwError()"," Throw an error from JS_ReportError."),#ifdef DEBUGJS_FN_HELP("disassemble",DisassembleToString,1,0,"disassemble([fun])"," Return the disassembly for the given function."),JS_FN_HELP("dis",Disassemble,1,0,"dis([fun])"," Disassemble functions into bytecodes."),JS_FN_HELP("disfile",DisassFile,1,0,"disfile('foo.js')"," Disassemble script file into bytecodes.\n"" dis and disfile take these options as preceeding string arguments:\n"" \"-r\" (disassemble recursively)\n"" \"-l\" (show line numbers)"),JS_FN_HELP("dissrc",DisassWithSrc,1,0,"dissrc([fun])"," Disassemble functions with source lines."),JS_FN_HELP("notes",Notes,1,0,"notes([fun])"," Show source notes for functions."),JS_FN_HELP("stackDump",StackDump,3,0,"stackDump(showArgs, showLocals, showThisProps)"," Tries to print a lot of information about the current stack. \n"" Similar to the DumpJSStack() function in the browser."),JS_FN_HELP("findReferences",FindReferences,1,0,"findReferences(target)"," Walk the entire heap, looking for references to |target|, and return a\n"" \"references object\" describing what we found.\n""\n"" Each property of the references object describes one kind of reference. The\n"" property's name is the label supplied to MarkObject, JS_CALL_TRACER, or what\n"" have you, prefixed with \"edge: \" to avoid collisions with system properties\n"" (like \"toString\" and \"__proto__\"). The property's value is an array of things\n"" that refer to |thing| via that kind of reference. Ordinary references from\n"" one object to another are named after the property name (with the \"edge: \"\n"" prefix).\n""\n"" Garbage collection roots appear as references from 'null'. We use the name\n"" given to the root (with the \"edge: \" prefix) as the name of the reference.\n""\n"" Note that the references object does record references from objects that are\n"" only reachable via |thing| itself, not just the references reachable\n"" themselves from roots that keep |thing| from being collected. (We could make\n"" this distinction if it is useful.)\n""\n"" If there are any references on the native stack, the references\n"" object will have properties named like \"edge: exact-value \"; the referrers\n"" will be 'null', because they are roots."),#endifJS_FN_HELP("build",BuildDate,0,0,"build()"," Show build date and time."),JS_FN_HELP("intern",Intern,1,0,"intern(str)"," Internalize str in the atom table."),JS_FN_HELP("getslx",GetSLX,1,0,"getslx(obj)"," Get script line extent."),JS_FN_HELP("evalcx",EvalInContext,1,0,"evalcx(s[, o])"," Evaluate s in optional sandbox object o.\n"" if (s == '' && !o) return new o with eager standard classes\n"" if (s == 'lazy' && !o) return new o with lazy standard classes"),JS_FN_HELP("evalInWorker",EvalInWorker,1,0,"evalInWorker(str)"," Evaluate 'str' in a separate thread with its own runtime.\n"),JS_FN_HELP("shapeOf",ShapeOf,1,0,"shapeOf(obj)"," Get the shape of obj (an implementation detail)."),#ifdef DEBUGJS_FN_HELP("arrayInfo",js_ArrayInfo,1,0,"arrayInfo(a1, a2, ...)"," Report statistics about arrays."),#endifJS_FN_HELP("sleep",Sleep_fn,1,0,"sleep(dt)"," Sleep for dt seconds."),JS_FN_HELP("snarf",Snarf,1,0,"snarf(filename, [\"binary\"])"," Read filename into returned string. Filename is relative to the current\n"" working directory."),JS_FN_HELP("read",Snarf,1,0,"read(filename, [\"binary\"])"," Synonym for snarf."),JS_FN_HELP("readRelativeToScript",ReadRelativeToScript,1,0,"readRelativeToScript(filename, [\"binary\"])"," Read filename into returned string. Filename is relative to the directory\n"" containing the current script."),JS_FN_HELP("compile",Compile,1,0,"compile(code)"," Compiles a string to bytecode, potentially throwing."),JS_FN_HELP("parse",Parse,1,0,"parse(code)"," Parses a string, potentially throwing."),JS_FN_HELP("syntaxParse",SyntaxParse,1,0,"syntaxParse(code)"," Check the syntax of a string, returning success value"),JS_FN_HELP("offThreadCompileScript",OffThreadCompileScript,1,0,"offThreadCompileScript(code[, options])"," Compile |code| on a helper thread. To wait for the compilation to finish\n"" and run the code, call |runOffThreadScript|. If present, |options| may\n"" have properties saying how the code should be compiled:\n"" noScriptRval: use the no-script-rval compiler option (default: false)\n"" fileName: filename for error messages and debug info\n"" lineNumber: starting line number for error messages and debug info\n"" columnNumber: starting column number for error messages and debug info\n"" element: if present with value |v|, convert |v| to an object |o| and\n"" mark the source as being attached to the DOM element |o|. If the\n"" property is omitted or |v| is null, don't attribute the source to\n"" any DOM element.\n"" elementAttributeName: if present and not undefined, the name of\n"" property of 'element' that holds this code. This is what\n"" Debugger.Source.prototype.elementAttributeName returns.\n"),JS_FN_HELP("runOffThreadScript",runOffThreadScript,0,0,"runOffThreadScript()"," Wait for off-thread compilation to complete. If an error occurred,\n"" throw the appropriate exception; otherwise, run the script and return\n"" its value."),JS_FN_HELP("timeout",Timeout,1,0,"timeout([seconds], [func])"," Get/Set the limit in seconds for the execution time for the current context.\n"" A negative value (default) means that the execution time is unlimited.\n"" If a second argument is provided, it will be invoked when the timer elapses.\n"" Calling this function will replace any callback set by |setInterruptCallback|.\n"),JS_FN_HELP("interruptIf",InterruptIf,1,0,"interruptIf(cond)"," Requests interrupt callback if cond is true. If a callback function is set via\n"" |timeout| or |setInterruptCallback|, it will be called. No-op otherwise."),JS_FN_HELP("invokeInterruptCallback",InvokeInterruptCallbackWrapper,0,0,"invokeInterruptCallback(fun)"," Forcefully set the interrupt flag and invoke the interrupt handler. If a\n"" callback function is set via |timeout| or |setInterruptCallback|, it will\n"" be called. Before returning, fun is called with the return value of the\n"" interrupt handler."),JS_FN_HELP("setInterruptCallback",SetInterruptCallback,1,0,"setInterruptCallback(func)"," Sets func as the interrupt callback function.\n"" Calling this function will replace any callback set by |timeout|.\n"),JS_FN_HELP("elapsed",Elapsed,0,0,"elapsed()"," Execution time elapsed for the current context."),JS_FN_HELP("decompileFunction",DecompileFunction,1,0,"decompileFunction(func)"," Decompile a function."),JS_FN_HELP("decompileBody",DecompileBody,1,0,"decompileBody(func)"," Decompile a function's body."),JS_FN_HELP("decompileThis",DecompileThisScript,0,0,"decompileThis()"," Decompile the currently executing script."),JS_FN_HELP("thisFilename",ThisFilename,0,0,"thisFilename()"," Return the filename of the current script"),JS_FN_HELP("wrap",Wrap,1,0,"wrap(obj)"," Wrap an object into a noop wrapper."),JS_FN_HELP("wrapWithProto",WrapWithProto,2,0,"wrapWithProto(obj)"," Wrap an object into a noop wrapper with prototype semantics."),JS_FN_HELP("newGlobal",NewGlobal,1,0,"newGlobal([options])"," Return a new global object in a new compartment. If options\n"" is given, it may have any of the following properties:\n"" sameZoneAs: the compartment will be in the same zone as the given object (defaults to a new zone)\n"" invisibleToDebugger: the global will be invisible to the debugger (default false)\n"" principal: if present, its value converted to a number must be an\n"" integer that fits in 32 bits; use that as the new compartment's\n"" principal. Shell principals are toys, meant only for testing; one\n"" shell principal subsumes another if its set bits are a superset of\n"" the other's. Thus, a principal of 0 subsumes nothing, while a\n"" principals of ~0 subsumes all other principals. The absence of a\n"" principal is treated as if its bits were 0xffff, for subsumption\n"" purposes. If this property is omitted, supply no principal."),JS_FN_HELP("createMappedArrayBuffer",CreateMappedArrayBuffer,1,0,"createMappedArrayBuffer(filename, [offset, [size]])"," Create an array buffer that mmaps the given file."),JS_FN_HELP("getMaxArgs",GetMaxArgs,0,0,"getMaxArgs()"," Return the maximum number of supported args for a call."),JS_FN_HELP("objectEmulatingUndefined",ObjectEmulatingUndefined,0,0,"objectEmulatingUndefined()"," Return a new object obj for which typeof obj === \"undefined\", obj == null\n"" and obj == undefined (and vice versa for !=), and ToBoolean(obj) === false.\n"),JS_FN_HELP("isCachingEnabled",IsCachingEnabled,0,0,"isCachingEnabled()"," Return whether JS caching is enabled."),JS_FN_HELP("setCachingEnabled",SetCachingEnabled,1,0,"setCachingEnabled(b)"," Enable or disable JS caching."),JS_FN_HELP("cacheEntry",CacheEntry,1,0,"cacheEntry(code)"," Return a new opaque object which emulates a cache entry of a script. This\n"" object encapsulates the code and its cached content. The cache entry is filled\n"" and read by the \"evaluate\" function by using it in place of the source, and\n"" by setting \"saveBytecode\" and \"loadBytecode\" options."),JS_FN_HELP("printProfilerEvents",PrintProfilerEvents,0,0,"printProfilerEvents()"," Register a callback with the profiler that prints javascript profiler events\n"" to stderr. Callback is only registered if profiling is enabled."),JS_FN_HELP("enableSingleStepProfiling",EnableSingleStepProfiling,0,0,"enableSingleStepProfiling()"," This function will fail on platforms that don't support single-step profiling\n"" (currently everything but ARM-simulator). When enabled, at every instruction a\n"" backtrace will be recorded and stored in an array. Adjacent duplicate backtraces\n"" are discarded."),JS_FN_HELP("disableSingleStepProfiling",DisableSingleStepProfiling,0,0,"disableSingleStepProfiling()"," Return the array of backtraces recorded by enableSingleStepProfiling."),JS_FN_HELP("isLatin1",IsLatin1,1,0,"isLatin1(s)"," Return true iff the string's characters are stored as Latin1."),JS_FS_HELP_END};staticconstJSFunctionSpecWithHelpfuzzing_unsafe_functions[]={JS_FN_HELP("clone",Clone,1,0,"clone(fun[, scope])"," Clone function object."),JS_FN_HELP("getSelfHostedValue",GetSelfHostedValue,1,0,"getSelfHostedValue()"," Get a self-hosted value by its name. Note that these values don't get \n"" cached, so repeatedly getting the same value creates multiple distinct clones."),JS_FN_HELP("parent",Parent,1,0,"parent(obj)"," Returns the parent of obj."),JS_FN_HELP("line2pc",LineToPC,0,0,"line2pc([fun,] line)"," Map line number to PC."),JS_FN_HELP("pc2line",PCToLine,0,0,"pc2line(fun[, pc])"," Map PC to line number."),JS_FN_HELP("redirect",RedirectOutput,2,0,"redirect(stdoutFilename[, stderrFilename])"," Redirect stdout and/or stderr to the named file. Pass undefined to avoid\n"" redirecting. Filenames are relative to the current working directory."),JS_FN_HELP("nestedShell",NestedShell,0,0,"nestedShell(shellArgs...)"," Execute the given code in a new JS shell process, passing this nested shell\n"" the arguments passed to nestedShell. argv[0] of the nested shell will be argv[0]\n"" of the current shell (which is assumed to be the actual path to the shell.\n"" arguments[0] (of the call to nestedShell) will be argv[1], arguments[1] will\n"" be argv[2], etc."),JS_FN_HELP("assertFloat32",testingFunc_assertFloat32,2,0,"assertFloat32(value, isFloat32)"," In IonMonkey only, asserts that value has (resp. hasn't) the MIRType_Float32 if isFloat32 is true (resp. false)."),JS_FN_HELP("withSourceHook",WithSourceHook,1,0,"withSourceHook(hook, fun)"," Set this JS runtime's lazy source retrieval hook (that is, the hook\n"" used to find sources compiled with |CompileOptions::LAZY_SOURCE|) to\n"" |hook|; call |fun| with no arguments; and then restore the runtime's\n"" original hook. Return or throw whatever |fun| did. |hook| gets\n"" passed the requested code's URL, and should return a string.\n""\n"" Notes:\n""\n"" 1) SpiderMonkey may assert if the returned code isn't close enough\n"" to the script's real code, so this function is not fuzzer-safe.\n""\n"" 2) The runtime can have only one source retrieval hook active at a\n"" time. If |fun| is not careful, |hook| could be asked to retrieve the\n"" source code for compilations that occurred long before it was set,\n"" and that it knows nothing about. The reverse applies as well: the\n"" original hook, that we reinstate after the call to |fun| completes,\n"" might be asked for the source code of compilations that |fun|\n"" performed, and which, presumably, only |hook| knows how to find.\n"),JS_FS_HELP_END};staticconstJSFunctionSpecWithHelpconsole_functions[]={JS_FN_HELP("log",Print,0,0,"log([exp ...])"," Evaluate and print expressions to stdout.\n"" This function is an alias of the print() function."),JS_FS_HELP_END};boolDefineConsole(JSContext*cx,HandleObjectglobal){RootedObjectobj(cx,JS_NewPlainObject(cx));returnobj&&JS_DefineFunctionsWithHelp(cx,obj,console_functions)&&JS_DefineProperty(cx,global,"console",obj,0);}#ifdef MOZ_PROFILING# define PROFILING_FUNCTION_COUNT 5# ifdef MOZ_CALLGRIND# define CALLGRIND_FUNCTION_COUNT 3# else# define CALLGRIND_FUNCTION_COUNT 0# endif# ifdef MOZ_VTUNE# define VTUNE_FUNCTION_COUNT 4# else# define VTUNE_FUNCTION_COUNT 0# endif# define EXTERNAL_FUNCTION_COUNT (PROFILING_FUNCTION_COUNT + CALLGRIND_FUNCTION_COUNT + VTUNE_FUNCTION_COUNT)#else# define EXTERNAL_FUNCTION_COUNT 0#endif#undef PROFILING_FUNCTION_COUNT#undef CALLGRIND_FUNCTION_COUNT#undef VTUNE_FUNCTION_COUNT#undef EXTERNAL_FUNCTION_COUNTstaticboolPrintHelpString(JSContext*cx,jsvalv){JSString*str=v.toString();JSLinearString*linear=str->ensureLinear(cx);if(!linear)returnfalse;JS::AutoCheckCannotGCnogc;if(linear->hasLatin1Chars()){for(constLatin1Char*p=linear->latin1Chars(nogc);*p;p++)fprintf(gOutFile,"%c",char(*p));}else{for(constchar16_t*p=linear->twoByteChars(nogc);*p;p++)fprintf(gOutFile,"%c",char(*p));}fprintf(gOutFile,"\n");returntrue;}staticboolPrintHelp(JSContext*cx,HandleObjectobj){RootedValueusage(cx);if(!JS_GetProperty(cx,obj,"usage",&usage))returnfalse;RootedValuehelp(cx);if(!JS_GetProperty(cx,obj,"help",&help))returnfalse;if(usage.isUndefined()||help.isUndefined())returntrue;returnPrintHelpString(cx,usage)&&PrintHelpString(cx,help);}staticboolHelp(JSContext*cx,unsignedargc,jsval*vp){CallArgsargs=CallArgsFromVp(argc,vp);fprintf(gOutFile,"%s\n",JS_GetImplementationVersion());RootedObjectobj(cx);if(args.length()==0){RootedObjectglobal(cx,JS::CurrentGlobalOrNull(cx));AutoIdArrayida(cx,JS_Enumerate(cx,global));if(!ida)returnfalse;for(size_ti=0;i<ida.length();i++){RootedValuev(cx);RootedIdid(cx,ida[i]);if(!JS_GetPropertyById(cx,global,id,&v))returnfalse;if(v.isPrimitive()){JS_ReportError(cx,"primitive arg");returnfalse;}obj=v.toObjectOrNull();if(!PrintHelp(cx,obj))returnfalse;}}else{for(unsignedi=0;i<args.length();i++){if(args[i].isPrimitive()){JS_ReportError(cx,"primitive arg");returnfalse;}obj=args[i].toObjectOrNull();if(!PrintHelp(cx,obj))returnfalse;}}args.rval().setUndefined();returntrue;}staticconstJSErrorFormatStringjsShell_ErrorFormatString[JSShellErr_Limit]={#define MSG_DEF(name, count, exception, format) \ { format, count, JSEXN_ERR } ,#include"jsshell.msg"#undef MSG_DEF};staticconstJSErrorFormatString*my_GetErrorMessage(void*userRef,constunsignederrorNumber){if(errorNumber==0||errorNumber>=JSShellErr_Limit)returnnullptr;return&jsShell_ErrorFormatString[errorNumber];}staticvoidmy_ErrorReporter(JSContext*cx,constchar*message,JSErrorReport*report){gGotError=PrintError(cx,gErrFile,message,report,reportWarnings);if(report->exnType!=JSEXN_NONE&&!JSREPORT_IS_WARNING(report->flags)){if(report->errorNumber==JSMSG_OUT_OF_MEMORY){gExitCode=EXITCODE_OUT_OF_MEMORY;}else{gExitCode=EXITCODE_RUNTIME_ERROR;}}}staticvoidmy_OOMCallback(JSContext*cx,void*data){// If a script is running, the engine is about to throw the string "out of// memory", which may or may not be caught. Otherwise the engine will just// unwind and return null/false, with no exception set.if(!JS_IsRunning(cx))gGotError=true;}staticboolglobal_enumerate(JSContext*cx,HandleObjectobj){#ifdef LAZY_STANDARD_CLASSESreturnJS_EnumerateStandardClasses(cx,obj);#elsereturntrue;#endif}staticboolglobal_resolve(JSContext*cx,HandleObjectobj,HandleIdid,bool*resolvedp){#ifdef LAZY_STANDARD_CLASSESif(!JS_ResolveStandardClass(cx,obj,id,resolvedp))returnfalse;#endifreturntrue;}staticconstJSClassglobal_class={"global",JSCLASS_GLOBAL_FLAGS,nullptr,nullptr,nullptr,nullptr,global_enumerate,global_resolve,nullptr,nullptr,nullptr,nullptr,nullptr,JS_GlobalObjectTraceHook};/* * Define a FakeDOMObject constructor. It returns an object with a getter, * setter and method with attached JitInfo. This object can be used to test * IonMonkey DOM optimizations in the shell. */staticconstuint32_tDOM_OBJECT_SLOT=0;staticbooldom_genericGetter(JSContext*cx,unsignedargc,JS::Value*vp);staticbooldom_genericSetter(JSContext*cx,unsignedargc,JS::Value*vp);staticbooldom_genericMethod(JSContext*cx,unsignedargc,JS::Value*vp);#ifdef DEBUGstaticconstJSClass*GetDomClass();#endifstaticbooldom_get_x(JSContext*cx,HandleObjectobj,void*self,JSJitGetterCallArgsargs){MOZ_ASSERT(JS_GetClass(obj)==GetDomClass());MOZ_ASSERT(self==(void*)0x1234);args.rval().set(JS_NumberValue(double(3.14)));returntrue;}staticbooldom_set_x(JSContext*cx,HandleObjectobj,void*self,JSJitSetterCallArgsargs){MOZ_ASSERT(JS_GetClass(obj)==GetDomClass());MOZ_ASSERT(self==(void*)0x1234);returntrue;}staticbooldom_doFoo(JSContext*cx,HandleObjectobj,void*self,constJSJitMethodCallArgs&args){MOZ_ASSERT(JS_GetClass(obj)==GetDomClass());MOZ_ASSERT(self==(void*)0x1234);/* Just return args.length(). */args.rval().setInt32(args.length());returntrue;}staticconstJSJitInfodom_x_getterinfo={{(JSJitGetterOp)dom_get_x},0,/* protoID */0,/* depth */JSJitInfo::AliasNone,/* aliasSet */JSJitInfo::Getter,JSVAL_TYPE_UNKNOWN,/* returnType */true,/* isInfallible. False in setters. */true,/* isMovable */false,/* isAlwaysInSlot */false,/* isLazilyCachedInSlot */false,/* isTypedMethod */0/* slotIndex */};staticconstJSJitInfodom_x_setterinfo={{(JSJitGetterOp)dom_set_x},0,/* protoID */0,/* depth */JSJitInfo::Setter,JSJitInfo::AliasEverything,/* aliasSet */JSVAL_TYPE_UNKNOWN,/* returnType */false,/* isInfallible. False in setters. */false,/* isMovable. */false,/* isAlwaysInSlot */false,/* isLazilyCachedInSlot */false,/* isTypedMethod */0/* slotIndex */};staticconstJSJitInfodoFoo_methodinfo={{(JSJitGetterOp)dom_doFoo},0,/* protoID */0,/* depth */JSJitInfo::Method,JSJitInfo::AliasEverything,/* aliasSet */JSVAL_TYPE_UNKNOWN,/* returnType */false,/* isInfallible. False in setters. */false,/* isMovable */false,/* isAlwaysInSlot */false,/* isLazilyCachedInSlot */false,/* isTypedMethod */0/* slotIndex */};staticconstJSPropertySpecdom_props[]={{"x",JSPROP_SHARED|JSPROP_ENUMERATE,{{dom_genericGetter,&dom_x_getterinfo}},{{dom_genericSetter,&dom_x_setterinfo}}},JS_PS_END};staticconstJSFunctionSpecdom_methods[]={JS_FNINFO("doFoo",dom_genericMethod,&doFoo_methodinfo,3,JSPROP_ENUMERATE),JS_FS_END};staticconstJSClassdom_class={"FakeDOMObject",JSCLASS_IS_DOMJSCLASS|JSCLASS_HAS_RESERVED_SLOTS(2)};#ifdef DEBUGstaticconstJSClass*GetDomClass(){return&dom_class;}#endifstaticbooldom_genericGetter(JSContext*cx,unsignedargc,JS::Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedObjectobj(cx,JS_THIS_OBJECT(cx,vp));if(!obj)returnfalse;if(JS_GetClass(obj)!=&dom_class){args.rval().set(UndefinedValue());returntrue;}JS::Valueval=js::GetReservedSlot(obj,DOM_OBJECT_SLOT);constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());MOZ_ASSERT(info->type()==JSJitInfo::Getter);JSJitGetterOpgetter=info->getter;returngetter(cx,obj,val.toPrivate(),JSJitGetterCallArgs(args));}staticbooldom_genericSetter(JSContext*cx,unsignedargc,JS::Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedObjectobj(cx,JS_THIS_OBJECT(cx,vp));if(!obj)returnfalse;MOZ_ASSERT(args.length()==1);if(JS_GetClass(obj)!=&dom_class){args.rval().set(UndefinedValue());returntrue;}JS::Valueval=js::GetReservedSlot(obj,DOM_OBJECT_SLOT);constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());MOZ_ASSERT(info->type()==JSJitInfo::Setter);JSJitSetterOpsetter=info->setter;if(!setter(cx,obj,val.toPrivate(),JSJitSetterCallArgs(args)))returnfalse;args.rval().set(UndefinedValue());returntrue;}staticbooldom_genericMethod(JSContext*cx,unsignedargc,JS::Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedObjectobj(cx,JS_THIS_OBJECT(cx,vp));if(!obj)returnfalse;if(JS_GetClass(obj)!=&dom_class){args.rval().set(UndefinedValue());returntrue;}JS::Valueval=js::GetReservedSlot(obj,DOM_OBJECT_SLOT);constJSJitInfo*info=FUNCTION_VALUE_TO_JITINFO(args.calleev());MOZ_ASSERT(info->type()==JSJitInfo::Method);JSJitMethodOpmethod=info->method;returnmethod(cx,obj,val.toPrivate(),JSJitMethodCallArgs(args));}staticvoidInitDOMObject(HandleObjectobj){/* Fow now just initialize to a constant we can check. */SetReservedSlot(obj,DOM_OBJECT_SLOT,PRIVATE_TO_JSVAL((void*)0x1234));}staticbooldom_constructor(JSContext*cx,unsignedargc,JS::Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);RootedObjectcallee(cx,&args.callee());RootedValueprotov(cx);if(!GetProperty(cx,callee,callee,cx->names().prototype,&protov))returnfalse;if(!protov.isObject()){JS_ReportErrorNumber(cx,js_GetErrorMessage,nullptr,JSMSG_BAD_PROTOTYPE,"FakeDOMObject");returnfalse;}RootedObjectproto(cx,&protov.toObject());RootedObjectdomObj(cx,JS_NewObjectWithGivenProto(cx,&dom_class,proto,JS::NullPtr()));if(!domObj)returnfalse;InitDOMObject(domObj);args.rval().setObject(*domObj);returntrue;}staticboolInstanceClassHasProtoAtDepth(constClass*clasp,uint32_tprotoID,uint32_tdepth){/* There's only a single (fake) DOM object in the shell, so just return true. */returntrue;}classScopedFileDesc{intptr_tfd_;public:enumLockType{READ_LOCK,WRITE_LOCK};ScopedFileDesc(intfd,LockTypelockType):fd_(fd){if(fd==-1)return;if(!jsCacheOpened.compareExchange(false,true)){close(fd_);fd_=-1;return;}}~ScopedFileDesc(){if(fd_==-1)return;MOZ_ASSERT(jsCacheOpened==true);jsCacheOpened=false;close(fd_);}operatorintptr_t()const{returnfd_;}intptr_tforget(){intptr_tret=fd_;fd_=-1;returnret;}};// To guard against corrupted cache files generated by previous crashes, write// asmJSCacheCookie to the first uint32_t of the file only after the file is// fully serialized and flushed to disk.staticconstuint32_tasmJSCacheCookie=0xabbadaba;staticboolShellOpenAsmJSCacheEntryForRead(HandleObjectglobal,constchar16_t*begin,constchar16_t*limit,size_t*serializedSizeOut,constuint8_t**memoryOut,intptr_t*handleOut){if(!jsCachingEnabled||!jsCacheAsmJSPath)returnfalse;ScopedFileDescfd(open(jsCacheAsmJSPath,O_RDWR),ScopedFileDesc::READ_LOCK);if(fd==-1)returnfalse;// Get the size and make sure we can dereference at least one uint32_t.off_toff=lseek(fd,0,SEEK_END);if(off==-1||off<(off_t)sizeof(uint32_t))returnfalse;// Map the file into memory.void*memory;#ifdef XP_WINHANDLEfdOsHandle=(HANDLE)_get_osfhandle(fd);HANDLEfileMapping=CreateFileMapping(fdOsHandle,nullptr,PAGE_READWRITE,0,0,nullptr);if(!fileMapping)returnfalse;memory=MapViewOfFile(fileMapping,FILE_MAP_READ,0,0,0);CloseHandle(fileMapping);if(!memory)returnfalse;#elsememory=mmap(nullptr,off,PROT_READ,MAP_SHARED,fd,0);if(memory==MAP_FAILED)returnfalse;#endif// Perform check described by asmJSCacheCookie comment.if(*(uint32_t*)memory!=asmJSCacheCookie){#ifdef XP_WINUnmapViewOfFile(memory);#elsemunmap(memory,off);#endifreturnfalse;}// The embedding added the cookie so strip it off of the buffer returned to// the JS engine.*serializedSizeOut=off-sizeof(uint32_t);*memoryOut=(uint8_t*)memory+sizeof(uint32_t);*handleOut=fd.forget();returntrue;}staticvoidShellCloseAsmJSCacheEntryForRead(size_tserializedSize,constuint8_t*memory,intptr_thandle){// Undo the cookie adjustment done when opening the file.memory-=sizeof(uint32_t);serializedSize+=sizeof(uint32_t);// Release the memory mapping and file.#ifdef XP_WINUnmapViewOfFile(const_cast<uint8_t*>(memory));#elsemunmap(const_cast<uint8_t*>(memory),serializedSize);#endifMOZ_ASSERT(jsCacheOpened==true);jsCacheOpened=false;close(handle);}staticJS::AsmJSCacheResultShellOpenAsmJSCacheEntryForWrite(HandleObjectglobal,boolinstalled,constchar16_t*begin,constchar16_t*end,size_tserializedSize,uint8_t**memoryOut,intptr_t*handleOut){if(!jsCachingEnabled||!jsCacheAsmJSPath)returnJS::AsmJSCache_Disabled_ShellFlags;// Create the cache directory if it doesn't already exist.structstatdirStat;if(stat(jsCacheDir,&dirStat)==0){if(!(dirStat.st_mode&S_IFDIR))returnJS::AsmJSCache_InternalError;}else{#ifdef XP_WINif(mkdir(jsCacheDir)!=0)returnJS::AsmJSCache_InternalError;#elseif(mkdir(jsCacheDir,0777)!=0)returnJS::AsmJSCache_InternalError;#endif}ScopedFileDescfd(open(jsCacheAsmJSPath,O_CREAT|O_RDWR,0660),ScopedFileDesc::WRITE_LOCK);if(fd==-1)returnJS::AsmJSCache_InternalError;// Include extra space for the asmJSCacheCookie.serializedSize+=sizeof(uint32_t);// Resize the file to the appropriate size after zeroing their contents.#ifdef XP_WINif(chsize(fd,0))returnJS::AsmJSCache_InternalError;if(chsize(fd,serializedSize))returnJS::AsmJSCache_InternalError;#elseif(ftruncate(fd,0))returnJS::AsmJSCache_InternalError;if(ftruncate(fd,serializedSize))returnJS::AsmJSCache_InternalError;#endif// Map the file into memory.void*memory;#ifdef XP_WINHANDLEfdOsHandle=(HANDLE)_get_osfhandle(fd);HANDLEfileMapping=CreateFileMapping(fdOsHandle,nullptr,PAGE_READWRITE,0,0,nullptr);if(!fileMapping)returnJS::AsmJSCache_InternalError;memory=MapViewOfFile(fileMapping,FILE_MAP_WRITE,0,0,0);CloseHandle(fileMapping);if(!memory)returnJS::AsmJSCache_InternalError;#elsememory=mmap(nullptr,serializedSize,PROT_WRITE,MAP_SHARED,fd,0);if(memory==MAP_FAILED)returnJS::AsmJSCache_InternalError;#endif// The embedding added the cookie so strip it off of the buffer returned to// the JS engine. The asmJSCacheCookie will be written on close, below.MOZ_ASSERT(*(uint32_t*)memory==0);*memoryOut=(uint8_t*)memory+sizeof(uint32_t);*handleOut=fd.forget();returnJS::AsmJSCache_Success;}staticvoidShellCloseAsmJSCacheEntryForWrite(size_tserializedSize,uint8_t*memory,intptr_thandle){// Undo the cookie adjustment done when opening the file.memory-=sizeof(uint32_t);serializedSize+=sizeof(uint32_t);// Write the magic cookie value after flushing the entire cache entry.#ifdef XP_WINFlushViewOfFile(memory,serializedSize);FlushFileBuffers(HANDLE(_get_osfhandle(handle)));#elsemsync(memory,serializedSize,MS_SYNC);#endifMOZ_ASSERT(*(uint32_t*)memory==0);*(uint32_t*)memory=asmJSCacheCookie;// Free the memory mapping and file.#ifdef XP_WINUnmapViewOfFile(const_cast<uint8_t*>(memory));#elsemunmap(memory,serializedSize);#endifMOZ_ASSERT(jsCacheOpened==true);jsCacheOpened=false;close(handle);}staticboolShellBuildId(JS::BuildIdCharVector*buildId){// The browser embeds the date into the buildid and the buildid is embedded// in the binary, so every 'make' necessarily builds a new firefox binary.// Fortunately, the actual firefox executable is tiny -- all the code is in// libxul.so and other shared modules -- so this isn't a big deal. Not so// for the statically-linked JS shell. To avoid recompmiling js.cpp and// re-linking 'js' on every 'make', we use a constant buildid and rely on// the shell user to manually clear the cache (deleting the dir passed to// --js-cache) between cache-breaking updates. Note: jit_tests.py does this// on every run).constcharbuildid[]="JS-shell";returnbuildId->append(buildid,sizeof(buildid));}staticconstJS::AsmJSCacheOpsasmJSCacheOps={ShellOpenAsmJSCacheEntryForRead,ShellCloseAsmJSCacheEntryForRead,ShellOpenAsmJSCacheEntryForWrite,ShellCloseAsmJSCacheEntryForWrite,ShellBuildId};staticJSContext*NewContext(JSRuntime*rt){JSContext*cx=JS_NewContext(rt,gStackChunkSize);if(!cx)returnnullptr;JSShellContextData*data=NewContextData();if(!data){DestroyContext(cx,false);returnnullptr;}JS_SetContextPrivate(cx,data);returncx;}staticvoidDestroyContext(JSContext*cx,boolwithGC){// Don't use GetContextData as |data| could be a nullptr in the case of// destroying a context precisely because we couldn't create its private// data.JSShellContextData*data=(JSShellContextData*)JS_GetContextPrivate(cx);JS_SetContextPrivate(cx,nullptr);js_free(data);withGC?JS_DestroyContext(cx):JS_DestroyContextNoGC(cx);}staticJSObject*NewGlobalObject(JSContext*cx,JS::CompartmentOptions&options,JSPrincipals*principals){RootedObjectglob(cx,JS_NewGlobalObject(cx,&global_class,principals,JS::DontFireOnNewGlobalHook,options));if(!glob)returnnullptr;{JSAutoCompartmentac(cx,glob);#ifndef LAZY_STANDARD_CLASSESif(!JS_InitStandardClasses(cx,glob))returnnullptr;#endif#ifdef JS_HAS_CTYPESif(!JS_InitCTypesClass(cx,glob))returnnullptr;#endifif(!JS_InitReflect(cx,glob))returnnullptr;if(!JS_DefineDebuggerObject(cx,glob))returnnullptr;if(!JS::RegisterPerfMeasurement(cx,glob))returnnullptr;if(!JS_DefineFunctionsWithHelp(cx,glob,shell_functions)||!JS_DefineProfilingFunctions(cx,glob)){returnnullptr;}if(!js::DefineTestingFunctions(cx,glob,fuzzingSafe))returnnullptr;if(!fuzzingSafe){if(!JS_DefineFunctionsWithHelp(cx,glob,fuzzing_unsafe_functions))returnnullptr;if(!js::DefineOS(cx,glob))returnnullptr;if(!DefineConsole(cx,glob))returnnullptr;}/* Initialize FakeDOMObject. */staticconstjs::DOMCallbacksDOMcallbacks={InstanceClassHasProtoAtDepth};SetDOMCallbacks(cx->runtime(),&DOMcallbacks);RootedObjectdomProto(cx,JS_InitClass(cx,glob,js::NullPtr(),&dom_class,dom_constructor,0,dom_props,dom_methods,nullptr,nullptr));if(!domProto)returnnullptr;/* Initialize FakeDOMObject.prototype */InitDOMObject(domProto);}JS_FireOnNewGlobalObject(cx,glob);returnglob;}staticboolBindScriptArgs(JSContext*cx,JSObject*obj_,OptionParser*op){RootedObjectobj(cx,obj_);MultiStringRangemsr=op->getMultiStringArg("scriptArgs");RootedObjectscriptArgs(cx);scriptArgs=JS_NewArrayObject(cx,0);if(!scriptArgs)returnfalse;if(!JS_DefineProperty(cx,obj,"scriptArgs",scriptArgs,0))returnfalse;for(size_ti=0;!msr.empty();msr.popFront(),++i){constchar*scriptArg=msr.front();JS::RootedStringstr(cx,JS_NewStringCopyZ(cx,scriptArg));if(!str||!JS_DefineElement(cx,scriptArgs,i,str,JSPROP_ENUMERATE)){returnfalse;}}returntrue;}staticboolOptionFailure(constchar*option,constchar*str){fprintf(stderr,"Unrecognized option for %s: %s\n",option,str);returnfalse;}staticintProcessArgs(JSContext*cx,JSObject*obj_,OptionParser*op){RootedObjectobj(cx,obj_);if(op->getBoolOption('s'))JS::RuntimeOptionsRef(cx).toggleExtraWarnings();/* |scriptArgs| gets bound on the global before any code is run. */if(!BindScriptArgs(cx,obj,op))returnEXIT_FAILURE;MultiStringRangefilePaths=op->getMultiStringOption('f');MultiStringRangecodeChunks=op->getMultiStringOption('e');if(filePaths.empty()&&codeChunks.empty()&&!op->getStringArg("script")){Process(cx,obj,nullptr,true);/* Interactive. */returngExitCode;}while(!filePaths.empty()||!codeChunks.empty()){size_tfpArgno=filePaths.empty()?-1:filePaths.argno();size_tccArgno=codeChunks.empty()?-1:codeChunks.argno();if(fpArgno<ccArgno){char*path=filePaths.front();Process(cx,obj,path,false);if(gExitCode)returngExitCode;filePaths.popFront();}else{constchar*code=codeChunks.front();RootedValuerval(cx);JS::CompileOptionsopts(cx);opts.setFileAndLine("-e",1);if(!JS::Evaluate(cx,obj,opts,code,strlen(code),&rval))returngExitCode?gExitCode:EXITCODE_RUNTIME_ERROR;codeChunks.popFront();}}/* The |script| argument is processed after all options. */if(constchar*path=op->getStringArg("script")){Process(cx,obj,path,false);if(gExitCode)returngExitCode;}if(op->getBoolOption('i'))Process(cx,obj,nullptr,true);returngExitCode?gExitCode:EXIT_SUCCESS;}staticboolSetRuntimeOptions(JSRuntime*rt,constOptionParser&op){boolenableBaseline=!op.getBoolOption("no-baseline");boolenableIon=!op.getBoolOption("no-ion");boolenableAsmJS=!op.getBoolOption("no-asmjs");boolenableNativeRegExp=!op.getBoolOption("no-native-regexp");boolenableUnboxedObjects=op.getBoolOption("unboxed-objects");JS::RuntimeOptionsRef(rt).setBaseline(enableBaseline).setIon(enableIon).setAsmJS(enableAsmJS).setNativeRegExp(enableNativeRegExp).setUnboxedObjects(enableUnboxedObjects);if(constchar*str=op.getStringOption("ion-scalar-replacement")){if(strcmp(str,"on")==0)jit::js_JitOptions.disableScalarReplacement=false;elseif(strcmp(str,"off")==0)jit::js_JitOptions.disableScalarReplacement=true;elsereturnOptionFailure("ion-scalar-replacement",str);}if(constchar*str=op.getStringOption("ion-gvn")){if(strcmp(str,"off")==0){jit::js_JitOptions.disableGvn=true;}elseif(strcmp(str,"on")!=0&&strcmp(str,"optimistic")!=0&&strcmp(str,"pessimistic")!=0){// We accept "pessimistic" and "optimistic" as synonyms for "on"// for backwards compatibility.returnOptionFailure("ion-gvn",str);}}if(constchar*str=op.getStringOption("ion-licm")){if(strcmp(str,"on")==0)jit::js_JitOptions.disableLicm=false;elseif(strcmp(str,"off")==0)jit::js_JitOptions.disableLicm=true;elsereturnOptionFailure("ion-licm",str);}if(constchar*str=op.getStringOption("ion-edgecase-analysis")){if(strcmp(str,"on")==0)jit::js_JitOptions.disableEdgeCaseAnalysis=false;elseif(strcmp(str,"off")==0)jit::js_JitOptions.disableEdgeCaseAnalysis=true;elsereturnOptionFailure("ion-edgecase-analysis",str);}if(constchar*str=op.getStringOption("ion-range-analysis")){if(strcmp(str,"on")==0)jit::js_JitOptions.disableRangeAnalysis=false;elseif(strcmp(str,"off")==0)jit::js_JitOptions.disableRangeAnalysis=true;elsereturnOptionFailure("ion-range-analysis",str);}if(constchar*str=op.getStringOption("ion-sink")){if(strcmp(str,"on")==0)jit::js_JitOptions.disableSink=false;elseif(strcmp(str,"off")==0)jit::js_JitOptions.disableSink=true;elsereturnOptionFailure("ion-sink",str);}if(constchar*str=op.getStringOption("ion-loop-unrolling")){if(strcmp(str,"on")==0)jit::js_JitOptions.disableLoopUnrolling=false;elseif(strcmp(str,"off")==0)jit::js_JitOptions.disableLoopUnrolling=true;elsereturnOptionFailure("ion-loop-unrolling",str);}if(op.getBoolOption("ion-check-range-analysis"))jit::js_JitOptions.checkRangeAnalysis=true;if(constchar*str=op.getStringOption("ion-inlining")){if(strcmp(str,"on")==0)jit::js_JitOptions.disableInlining=false;elseif(strcmp(str,"off")==0)jit::js_JitOptions.disableInlining=true;elsereturnOptionFailure("ion-inlining",str);}if(constchar*str=op.getStringOption("ion-osr")){if(strcmp(str,"on")==0)jit::js_JitOptions.osr=true;elseif(strcmp(str,"off")==0)jit::js_JitOptions.osr=false;elsereturnOptionFailure("ion-osr",str);}if(constchar*str=op.getStringOption("ion-limit-script-size")){if(strcmp(str,"on")==0)jit::js_JitOptions.limitScriptSize=true;elseif(strcmp(str,"off")==0)jit::js_JitOptions.limitScriptSize=false;elsereturnOptionFailure("ion-limit-script-size",str);}int32_twarmUpThreshold=op.getIntOption("ion-warmup-threshold");if(warmUpThreshold>=0