static void DumpFunctionCountMap(const char *title, JSRuntime::FunctionCountMap &map, FILE *fp) { fprintf(fp, "\n%s count map:\n", title); for (JSRuntime::FunctionCountMap::Range r = map.all(); !r.empty(); r.popFront()) { JSFunction *fun = r.front().key; int32 count = r.front().value; fprintf(fp, "%10d %s:%u\n", count, fun->script()->filename, fun->script()->lineno); } }
static StackFrame * PushInlinedFrame(JSContext *cx, StackFrame *callerFrame) { // Grab the callee object out of the caller's frame, which has already been restored. // N.B. we currently assume that the caller frame is at a JSOP_CALL pc for the caller frames, // which will not be the case when we inline getters (in which case it would be a // JSOP_GETPROP). That will have to be handled differently. FrameRegs ®s = cx->regs(); JS_ASSERT(JSOp(*regs.pc) == JSOP_CALL || JSOp(*regs.pc) == JSOP_NEW); int callerArgc = GET_ARGC(regs.pc); const Value &calleeVal = regs.sp[-callerArgc - 2]; JSFunction *fun = calleeVal.toObject().toFunction(); JSScript *script = fun->script(); CallArgs inlineArgs = CallArgsFromSp(callerArgc, regs.sp); // Bump the stack pointer to make it look like the inline args have been pushed, but they will // really get filled in by RestoreOneFrame. regs.sp = inlineArgs.end(); InitialFrameFlags flags = INITIAL_NONE; if (JSOp(*regs.pc) == JSOP_NEW) flags = INITIAL_CONSTRUCT; if (!cx->stack.pushInlineFrame(cx, regs, inlineArgs, *fun, script, flags, DONT_REPORT_ERROR)) return NULL; StackFrame *fp = cx->stack.fp(); JS_ASSERT(fp == regs.fp()); JS_ASSERT(fp->prev() == callerFrame); fp->formals()[-2].setObject(*fun); return fp; }
/* * This function must only be called after the early prologue, since it depends * on fp->exec.fun. */ void * JS_FASTCALL stubs::FixupArity(VMFrame &f, uint32_t nactual) { JSContext *cx = f.cx; StackFrame *oldfp = f.fp(); JS_ASSERT(nactual != oldfp->numFormalArgs()); /* * Grossssss! *move* the stack frame. If this ends up being perf-critical, * we can figure out how to spot-optimize it. Be careful to touch only the * members that have been initialized by the caller and early prologue. */ InitialFrameFlags initial = oldfp->initialFlags(); JSFunction *fun = oldfp->fun(); JSScript *script = fun->script(); void *ncode = oldfp->nativeReturnAddress(); /* Pop the inline frame. */ f.regs.popPartialFrame((Value *)oldfp); /* Reserve enough space for a callee frame. */ CallArgs args = CallArgsFromSp(nactual, f.regs.sp); StackFrame *fp = cx->stack.getFixupFrame(cx, DONT_REPORT_ERROR, args, fun, script, ncode, initial, &f.stackLimit); if (!fp) { f.regs.updateForNcode(f.jit(), ncode); js_ReportOverRecursed(cx); THROWV(NULL); } /* The caller takes care of assigning fp to regs. */ return fp; }
void * JS_FASTCALL stubs::CompileFunction(VMFrame &f, uint32 nactual) { /* * We have a partially constructed frame. That's not really good enough to * compile though because we could throw, so get a full, adjusted frame. */ JSContext *cx = f.cx; JSStackFrame *fp = f.fp(); /* * Since we can only use members set by initCallFrameCallerHalf, * we must carefully extract the callee from the nactual. */ JSObject &callee = fp->formalArgsEnd()[-(int(nactual) + 2)].toObject(); JSFunction *fun = callee.getFunctionPrivate(); JSScript *script = fun->script(); /* * FixupArity/RemovePartialFrame expect to be called after the early * prologue. */ fp->initCallFrameEarlyPrologue(fun, nactual); if (nactual != fp->numFormalArgs()) { fp = (JSStackFrame *)FixupArity(f, nactual); if (!fp) return NULL; } /* Finish frame initialization. */ fp->initCallFrameLatePrologue(); /* These would have been initialized by the prologue. */ f.regs.fp = fp; f.regs.sp = fp->base(); f.regs.pc = script->code; if (fun->isHeavyweight() && !js::CreateFunCallObject(cx, fp)) THROWV(NULL); CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT); if (status == Compile_Okay) return script->getJIT(fp->isConstructing())->invokeEntry; /* Function did not compile... interpret it. */ JSBool ok = Interpret(cx, fp); InlineReturn(f); if (!ok) THROWV(NULL); return NULL; }
static inline bool UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc) { JSContext *cx = f.cx; Value *vp = f.regs.sp - (argc + 2); JSObject &callee = vp->toObject(); JSFunction *newfun = callee.getFunctionPrivate(); JSScript *newscript = newfun->script(); /* Get pointer to new frame/slots, prepare arguments. */ StackSpace &stack = cx->stack(); JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc, newfun, newscript, &flags, f.entryfp, &f.stackLimit); if (JS_UNLIKELY(!newfp)) return false; /* Initialize frame, locals. */ newfp->initCallFrame(cx, callee, newfun, argc, flags); SetValueRangeToUndefined(newfp->slots(), newscript->nfixed); /* Officially push the frame. */ stack.pushInlineFrame(cx, newscript, newfp, &f.regs); JS_ASSERT(newfp == f.regs.fp); /* Scope with a call object parented by callee's parent. */ if (newfun->isHeavyweight() && !js::CreateFunCallObject(cx, newfp)) return false; /* Try to compile if not already compiled. */ if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) { CompileStatus status = CanMethodJIT(cx, newscript, newfp, CompileRequest_Interpreter); if (status == Compile_Error) { /* A runtime exception was thrown, get out. */ InlineReturn(f); return false; } if (status == Compile_Abort) *unjittable = true; } /* If newscript was successfully compiled, run it. */ if (JITScript *jit = newscript->getJIT(newfp->isConstructing())) { *pret = jit->invokeEntry; return true; } /* Otherwise, run newscript in the interpreter. */ bool ok = !!Interpret(cx, cx->fp()); InlineReturn(f); *pret = NULL; return ok; }
bool MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script_) { Rooted<JSScript*> script(cx, script_); Vector<JSScript *, 16> worklist(cx); if (!worklist.append(script.reference())) return false; while (worklist.length()) { JSScript *outer = worklist.back(); worklist.popBack(); /* * If outer has an extensible scope, its slots may be resized which * will invalidate nesting->varArray/argArray. */ if (outer->funHasExtensibleScope) continue; if (outer->hasObjects()) { ObjectArray *arr = outer->objects(); /* * If this is an eval script, don't treat the saved caller function * stored in the first object slot as an inner function. */ size_t start = outer->savedCallerFun ? 1 : 0; for (size_t i = start; i < arr->length; i++) { JSObject *obj = arr->vector[i]; if (!obj->isFunction()) continue; JSFunction *fun = obj->toFunction(); JS_ASSERT(fun->isInterpreted()); JSScript *inner = fun->script(); if (outer->function() && outer->function()->isHeavyweight()) { outer->isOuterFunction = true; inner->isInnerFunction = true; } if (!inner->hasObjects()) continue; if (!worklist.append(inner)) return false; } } } return true; }
JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) { XDRScriptState fstate(xdr); if (xdr->mode == JSXDR_ENCODE) { JSFunction* fun = (*objp)->getFunctionPrivate(); if (!fun) return false; fstate.filename = fun->script()->filename; } return js_XDRFunctionObject(xdr, objp); }
static JSScript* GetBailedJSScript(JSContext *cx) { // Just after the frame conversion, we can safely interpret the ionTop as JS // frame because it targets the bailed JS frame converted to an exit frame. IonJSFrameLayout *frame = reinterpret_cast<IonJSFrameLayout*>(cx->runtime->ionTop); switch (GetCalleeTokenTag(frame->calleeToken())) { case CalleeToken_Function: { JSFunction *fun = CalleeTokenToFunction(frame->calleeToken()); return fun->script(); } case CalleeToken_Script: return CalleeTokenToScript(frame->calleeToken()); default: JS_NOT_REACHED("unexpected callee token kind"); return NULL; } }
/* * This function must only be called after the early prologue, since it depends * on fp->exec.fun. */ void * JS_FASTCALL stubs::FixupArity(VMFrame &f, uint32 nactual) { JSContext *cx = f.cx; JSStackFrame *oldfp = f.fp(); JS_ASSERT(nactual != oldfp->numFormalArgs()); /* * Grossssss! *move* the stack frame. If this ends up being perf-critical, * we can figure out how to spot-optimize it. Be careful to touch only the * members that have been initialized by initCallFrameCallerHalf and the * early prologue. */ uint32 flags = oldfp->isConstructingFlag(); JSFunction *fun = oldfp->fun(); void *ncode = oldfp->nativeReturnAddress(); /* Pop the inline frame. */ f.fp() = oldfp->prev(); f.regs.sp = (Value*) oldfp; /* Reserve enough space for a callee frame. */ JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual, fun, fun->script(), &flags, f.entryfp, &f.stackLimit); if (!newfp) { /* * The PC is not coherent with the current frame, so fix it up for * exception handling. */ f.regs.pc = f.jit()->nativeToPC(ncode); THROWV(NULL); } /* Reset the part of the stack frame set by the caller. */ newfp->initCallFrameCallerHalf(cx, flags, ncode); /* Reset the part of the stack frame set by the prologue up to now. */ newfp->initCallFrameEarlyPrologue(fun, nactual); /* The caller takes care of assigning fp to regs. */ return newfp; }
bool MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script) { Root<JSScript*> root(cx, &script); Vector<JSScript *, 16> worklist(cx); if (!worklist.append(script)) return false; while (worklist.length()) { JSScript *outer = worklist.back(); worklist.popBack(); if (outer->hasObjects()) { ObjectArray *arr = outer->objects(); /* * If this is an eval script, don't treat the saved caller function * stored in the first object slot as an inner function. */ size_t start = outer->savedCallerFun ? 1 : 0; for (size_t i = start; i < arr->length; i++) { JSObject *obj = arr->vector[i]; if (!obj->isFunction()) continue; JSFunction *fun = obj->toFunction(); JS_ASSERT(fun->isInterpreted()); JSScript *inner = fun->script(); if (outer->function() && outer->function()->isHeavyweight()) { outer->isOuterFunction = true; inner->isInnerFunction = true; } if (!inner->hasObjects()) continue; if (!worklist.append(inner)) return false; } } } return true; }
static inline bool UncachedInlineCall(VMFrame &f, MaybeConstruct construct, void **pret, bool *unjittable, uint32 argc) { JSContext *cx = f.cx; CallArgs args = CallArgsFromSp(argc, f.regs.sp); JSObject &callee = args.callee(); JSFunction *newfun = callee.getFunctionPrivate(); JSScript *newscript = newfun->script(); /* Get pointer to new frame/slots, prepare arguments. */ if (!cx->stack.pushInlineFrame(cx, f.regs, args, callee, newfun, newscript, construct, &f.stackLimit)) return false; /* Scope with a call object parented by callee's parent. */ if (newfun->isHeavyweight() && !js::CreateFunCallObject(cx, f.fp())) return false; /* Try to compile if not already compiled. */ if (newscript->getJITStatus(f.fp()->isConstructing()) == JITScript_None) { CompileStatus status = CanMethodJIT(cx, newscript, f.fp(), CompileRequest_Interpreter); if (status == Compile_Error) { /* A runtime exception was thrown, get out. */ InlineReturn(f); return false; } if (status == Compile_Abort) *unjittable = true; } /* If newscript was successfully compiled, run it. */ if (JITScript *jit = newscript->getJIT(f.fp()->isConstructing())) { *pret = jit->invokeEntry; return true; } /* Otherwise, run newscript in the interpreter. */ bool ok = !!Interpret(cx, cx->fp()); InlineReturn(f); *pret = NULL; return ok; }
JSBool CallObject::setArgOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) { CallObject &callobj = obj->asCall(); JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id)); unsigned i = (uint16_t) JSID_TO_INT(id); if (StackFrame *fp = callobj.maybeStackFrame()) fp->formalArg(i) = *vp; else callobj.setArg(i, *vp); JSFunction *fun = callobj.getCalleeFunction(); JSScript *script = fun->script(); if (!script->ensureHasTypes(cx)) return false; TypeScript::SetArgument(cx, script, i, *vp); return true; }
/* * This function must only be called after the early prologue, since it depends * on fp->exec.fun. */ void * JS_FASTCALL stubs::FixupArity(VMFrame &f, uint32 nactual) { JSContext *cx = f.cx; StackFrame *oldfp = f.fp(); JS_ASSERT(nactual != oldfp->numFormalArgs()); /* * Grossssss! *move* the stack frame. If this ends up being perf-critical, * we can figure out how to spot-optimize it. Be careful to touch only the * members that have been initialized by initJitFrameCallerHalf and the * early prologue. */ MaybeConstruct construct = oldfp->isConstructing(); JSFunction *fun = oldfp->fun(); JSScript *script = fun->script(); void *ncode = oldfp->nativeReturnAddress(); /* Pop the inline frame. */ f.regs.popPartialFrame((Value *)oldfp); /* Reserve enough space for a callee frame. */ CallArgs args = CallArgsFromSp(nactual, f.regs.sp); StackFrame *fp = cx->stack.getFixupFrame(cx, DONT_REPORT_ERROR, args, fun, script, ncode, construct, &f.stackLimit); if (!fp) { /* * The PC is not coherent with the current frame, so fix it up for * exception handling. */ f.regs.pc = f.jit()->nativeToPC(ncode); js_ReportOverRecursed(cx); THROWV(NULL); } /* The caller takes care of assigning fp to regs. */ return fp; }
bool ContextStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial, InvokeFrameGuard *ifg) { JS_ASSERT(onTop()); JS_ASSERT(space().firstUnused() == args.end()); JSObject &callee = args.callee(); JSFunction *fun = callee.toFunction(); JSScript *script = fun->script(); StackFrame::Flags flags = ToFrameFlags(initial); StackFrame *fp = getCallFrame(cx, REPORT_ERROR, args, fun, script, &flags); if (!fp) return false; fp->initCallFrame(cx, *fun, script, args.length(), flags); ifg->regs_.prepareToRun(*fp, script); ifg->prevRegs_ = seg_->pushRegs(ifg->regs_); JS_ASSERT(space().firstUnused() == ifg->regs_.sp); ifg->setPushed(*this); return true; }
/* * This helper function brings the ContextStack to the top of the thread stack * (so that it can be extended to push a frame and/or arguments) by potentially * pushing a StackSegment. The 'pushedSeg' outparam indicates whether such a * segment was pushed (and hence whether the caller needs to call popSegment). * * Additionally, to minimize calls to ensureSpace, ensureOnTop ensures that * there is space for nvars slots on top of the stack. */ Value * ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars, MaybeExtend extend, bool *pushedSeg, JSCompartment *dest) { Value *firstUnused = space().firstUnused(); #ifdef JS_METHODJIT /* * The only calls made by inlined methodjit frames can be to other JIT * frames associated with the same VMFrame. If we try to Invoke(), * Execute() or so forth, any topmost inline frame will need to be * expanded (along with other inline frames in the compartment). * To avoid pathological behavior here, make sure to mark any topmost * function as uninlineable, which will expand inline frames if there are * any and prevent the function from being inlined in the future. */ if (FrameRegs *regs = cx->maybeRegs()) { JSFunction *fun = NULL; if (InlinedSite *site = regs->inlined()) { mjit::JITChunk *chunk = regs->fp()->jit()->chunk(regs->pc); fun = chunk->inlineFrames()[site->inlineIndex].fun; } else { StackFrame *fp = regs->fp(); if (fp->isFunctionFrame()) { JSFunction *f = fp->fun(); if (f->isInterpreted()) fun = f; } } if (fun) { fun->script()->uninlineable = true; types::MarkTypeObjectFlags(cx, fun, types::OBJECT_FLAG_UNINLINEABLE); } } JS_ASSERT_IF(cx->hasfp(), !cx->regs().inlined()); #endif if (onTop() && extend) { if (!space().ensureSpace(cx, report, firstUnused, nvars, dest)) return NULL; return firstUnused; } if (!space().ensureSpace(cx, report, firstUnused, VALUES_PER_STACK_SEGMENT + nvars, dest)) return NULL; FrameRegs *regs; CallArgsList *calls; if (seg_ && extend) { regs = seg_->maybeRegs(); calls = seg_->maybeCalls(); } else { regs = NULL; calls = NULL; } seg_ = new(firstUnused) StackSegment(seg_, space().seg_, regs, calls); space().seg_ = seg_; *pushedSeg = true; return seg_->slotsBegin(); }
static JSBool fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, Value *vp) { JSObject *obj = obj_; while (!obj->isFunction()) { obj = obj->getProto(); if (!obj) return true; } JSFunction *fun = obj->toFunction(); /* * Mark the function's script as uninlineable, to expand any of its * frames on the stack before we go looking for them. This allows the * below walk to only check each explicit frame rather than needing to * check any calls that were inlined. */ if (fun->isInterpreted()) { fun->script()->uninlineable = true; MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE); } /* Set to early to null in case of error */ vp->setNull(); /* Find fun's top-most activation record. */ StackIter iter(cx); for (; !iter.done(); ++iter) { if (!iter.isFunctionFrame() || iter.isEvalFrame()) continue; if (iter.callee() == fun) break; } if (iter.done()) return true; StackFrame *fp = iter.fp(); if (JSID_IS_ATOM(id, cx->runtime->atomState.argumentsAtom)) { if (fun->hasRest()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_FUNCTION_ARGUMENTS_AND_REST); return false; } /* Warn if strict about f.arguments or equivalent unqualified uses. */ if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage, NULL, JSMSG_DEPRECATED_USAGE, js_arguments_str)) { return false; } ArgumentsObject *argsobj = ArgumentsObject::createUnexpected(cx, fp); if (!argsobj) return false; *vp = ObjectValue(*argsobj); return true; } #ifdef JS_METHODJIT if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom) && fp && fp->prev()) { /* * If the frame was called from within an inlined frame, mark the * innermost function as uninlineable to expand its frame and allow us * to recover its callee object. */ JSInlinedSite *inlined; jsbytecode *prevpc = fp->prev()->pcQuadratic(cx->stack, fp, &inlined); if (inlined) { mjit::JITChunk *chunk = fp->prev()->jit()->chunk(prevpc); JSFunction *fun = chunk->inlineFrames()[inlined->inlineIndex].fun; fun->script()->uninlineable = true; MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE); } } #endif if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) { StackIter prev(iter); do { ++prev; } while (!prev.done() && prev.isImplicitNativeCall()); if (prev.done() || !prev.isFunctionFrame()) { JS_ASSERT(vp->isNull()); return true; } *vp = prev.calleev(); /* Censor the caller if it is from another compartment. */ JSObject &caller = vp->toObject(); if (caller.compartment() != cx->compartment) { vp->setNull(); } else if (caller.isFunction()) { JSFunction *callerFun = caller.toFunction(); if (callerFun->isInterpreted() && callerFun->inStrictMode()) { JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, JSMSG_CALLER_IS_STRICT); return false; } } return true; } JS_NOT_REACHED("fun_getProperty"); return false; }
bool js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript) { /* NB: Keep this in sync with CloneInterpretedFunction. */ JSFunction *fun; JSAtom *atom; uint32_t firstword; /* flag telling whether fun->atom is non-null, plus for fun->u.i.skipmin, fun->u.i.wrapper, and 14 bits reserved for future use */ uint32_t flagsword; /* word for argument count and fun->flags */ JSContext *cx = xdr->cx(); JSScript *script; if (mode == XDR_ENCODE) { fun = (*objp)->toFunction(); if (!fun->isInterpreted()) { JSAutoByteString funNameBytes; if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, name); } return false; } firstword = !!fun->atom; flagsword = (fun->nargs << 16) | fun->flags; atom = fun->atom; script = fun->script(); } else { RootedObject parent(cx, NULL); fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL); if (!fun) return false; if (!fun->clearParent(cx)) return false; if (!fun->clearType(cx)) return false; atom = NULL; script = NULL; } if (!xdr->codeUint32(&firstword)) return false; if ((firstword & 1U) && !XDRAtom(xdr, &atom)) return false; if (!xdr->codeUint32(&flagsword)) return false; if (!XDRScript(xdr, &script, parentScript)) return false; if (mode == XDR_DECODE) { fun->nargs = flagsword >> 16; JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED); fun->flags = uint16_t(flagsword); fun->atom.init(atom); fun->initScript(script); if (!script->typeSetFunction(cx, fun)) return false; JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs()); js_CallNewScriptHook(cx, fun->script(), fun); *objp = fun; }
bool DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script) { JSObject *globalObj = globalScope.globalObj; /* Define and update global properties. */ for (size_t i = 0; i < globalScope.defs.length(); i++) { GlobalScope::GlobalDef &def = globalScope.defs[i]; /* Names that could be resolved ahead of time can be skipped. */ if (!def.atom) continue; jsid id = ATOM_TO_JSID(def.atom); Value rval; if (def.funbox) { JSFunction *fun = def.funbox->function(); /* * No need to check for redeclarations or anything, global * optimizations only take place if the property is not defined. */ rval.setObject(*fun); types::AddTypePropertyId(cx, globalObj, id, rval); } else { rval.setUndefined(); } /* * Don't update the type information when defining the property for the * global object, per the consistency rules for type properties. If the * property is only undefined before it is ever written, we can check * the global directly during compilation and avoid having to emit type * checks every time it is accessed in the script. */ const Shape *shape = DefineNativeProperty(cx, globalObj, id, rval, JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE | JSPROP_PERMANENT, 0, 0, DNP_SKIP_TYPE); if (!shape) return false; def.knownSlot = shape->slot(); } Vector<JSScript *, 16> worklist(cx); if (!worklist.append(script)) return false; /* * Recursively walk through all scripts we just compiled. For each script, * go through all global uses. Each global use indexes into globalScope->defs. * Use this information to repoint each use to the correct slot in the global * object. */ while (worklist.length()) { JSScript *outer = worklist.back(); worklist.popBack(); if (JSScript::isValidOffset(outer->objectsOffset)) { JSObjectArray *arr = outer->objects(); /* * If this is an eval script, don't treat the saved caller function * stored in the first object slot as an inner function. */ size_t start = outer->savedCallerFun ? 1 : 0; for (size_t i = start; i < arr->length; i++) { JSObject *obj = arr->vector[i]; if (!obj->isFunction()) continue; JSFunction *fun = obj->toFunction(); JS_ASSERT(fun->isInterpreted()); JSScript *inner = fun->script(); if (outer->function() && outer->function()->isHeavyweight()) { outer->isOuterFunction = true; inner->isInnerFunction = true; } if (!JSScript::isValidOffset(inner->globalsOffset) && !JSScript::isValidOffset(inner->objectsOffset)) { continue; } if (!worklist.append(inner)) return false; } } if (!JSScript::isValidOffset(outer->globalsOffset)) continue; GlobalSlotArray *globalUses = outer->globals(); uint32_t nGlobalUses = globalUses->length; for (uint32_t i = 0; i < nGlobalUses; i++) { uint32_t index = globalUses->vector[i].slot; JS_ASSERT(index < globalScope.defs.length()); globalUses->vector[i].slot = globalScope.defs[index].knownSlot; } } return true; }
JSObject * GlobalObject::initFunctionAndObjectClasses(JSContext *cx) { JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); JS_ASSERT(isNative()); /* * Calling a function from a cleared global triggers this (yeah, I know). * Uncomment this once bug 470510 is fixed (if that bug doesn't remove * isCleared entirely). */ // JS_ASSERT(!isCleared()); /* If cx has no global object, make this the global object. */ if (!cx->globalObject) JS_SetGlobalObject(cx, this); /* * Create |Object.prototype| first, mirroring CreateBlankProto but for the * prototype of the created object. */ JSObject *objectProto = NewObjectWithGivenProto(cx, &ObjectClass, NULL, this); if (!objectProto || !objectProto->setSingletonType(cx)) return NULL; /* * The default 'new' type of Object.prototype is required by type inference * to have unknown properties, to simplify handling of e.g. heterogenous * objects in JSON and script literals. */ if (!objectProto->setNewTypeUnknown(cx)) return NULL; /* Create |Function.prototype| next so we can create other functions. */ JSFunction *functionProto; { JSObject *proto = NewObjectWithGivenProto(cx, &FunctionClass, objectProto, this); if (!proto) return NULL; /* * Bizarrely, |Function.prototype| must be an interpreted function, so * give it the guts to be one. */ functionProto = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, this, NULL); if (!functionProto) return NULL; JS_ASSERT(proto == functionProto); functionProto->flags |= JSFUN_PROTOTYPE; JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT); if (!script) return NULL; script->noScriptRval = true; script->code[0] = JSOP_STOP; script->code[1] = SRC_NULL; functionProto->initScript(script); functionProto->getType(cx)->interpretedFunction = functionProto; script->setFunction(functionProto); if (!proto->setSingletonType(cx)) return NULL; /* * The default 'new' type of Function.prototype is required by type * inference to have unknown properties, to simplify handling of e.g. * CloneFunctionObject. */ if (!proto->setNewTypeUnknown(cx)) return NULL; } /* Create the Object function now that we have a [[Prototype]] for it. */ jsid objectId = ATOM_TO_JSID(CLASS_ATOM(cx, Object)); JSFunction *objectCtor; { JSObject *ctor = NewObjectWithGivenProto(cx, &FunctionClass, functionProto, this); if (!ctor) return NULL; objectCtor = js_NewFunction(cx, ctor, js_Object, 1, JSFUN_CONSTRUCTOR, this, JSID_TO_ATOM(objectId)); if (!objectCtor) return NULL; JS_ASSERT(ctor == objectCtor); objectCtor->setConstructorClass(&ObjectClass); } /* * Install |Object| and |Object.prototype| for the benefit of subsequent * code that looks for them. */ setObjectClassDetails(objectCtor, objectProto); /* Create |Function| so it and |Function.prototype| can be installed. */ jsid functionId = ATOM_TO_JSID(CLASS_ATOM(cx, Function)); JSFunction *functionCtor; { JSObject *ctor = NewObjectWithGivenProto(cx, &FunctionClass, functionProto, this); if (!ctor) return NULL; functionCtor = js_NewFunction(cx, ctor, Function, 1, JSFUN_CONSTRUCTOR, this, JSID_TO_ATOM(functionId)); if (!functionCtor) return NULL; JS_ASSERT(ctor == functionCtor); functionCtor->setConstructorClass(&FunctionClass); } /* * Install |Function| and |Function.prototype| so that we can freely create * functions and objects without special effort. */ setFunctionClassDetails(functionCtor, functionProto); /* * The hard part's done: now go back and add all the properties these * primordial values have. */ if (!LinkConstructorAndPrototype(cx, objectCtor, objectProto) || !DefinePropertiesAndBrand(cx, objectProto, object_props, object_methods) || !DefinePropertiesAndBrand(cx, objectCtor, NULL, object_static_methods) || !LinkConstructorAndPrototype(cx, functionCtor, functionProto) || !DefinePropertiesAndBrand(cx, functionProto, NULL, function_methods) || !DefinePropertiesAndBrand(cx, functionCtor, NULL, NULL)) { return NULL; } /* Add the global Function and Object properties now. */ if (!addDataProperty(cx, objectId, JSProto_Object + JSProto_LIMIT * 2, 0)) return NULL; if (!addDataProperty(cx, functionId, JSProto_Function + JSProto_LIMIT * 2, 0)) return NULL; /* Heavy lifting done, but lingering tasks remain. */ /* ES5 15.1.2.1. */ jsid id = ATOM_TO_JSID(cx->runtime->atomState.evalAtom); JSObject *evalobj = js_DefineFunction(cx, this, id, eval, 1, JSFUN_STUB_GSOPS); if (!evalobj) return NULL; setOriginalEval(evalobj); /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */ JSFunction *throwTypeError = js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, this, NULL); if (!throwTypeError) return NULL; AutoIdVector ids(cx); if (!throwTypeError->preventExtensions(cx, &ids)) return NULL; setThrowTypeError(throwTypeError); /* * The global object should have |Object.prototype| as its [[Prototype]]. * Eventually we'd like to have standard classes be there from the start, * and thus we would know we were always setting what had previously been a * null [[Prototype]], but right now some code assumes it can set the * [[Prototype]] before standard classes have been initialized. For now, * only set the [[Prototype]] if it hasn't already been set. */ if (shouldSplicePrototype(cx) && !splicePrototype(cx, objectProto)) return NULL; /* * Notify any debuggers about the creation of the script for * |Function.prototype| -- after all initialization, for simplicity. */ js_CallNewScriptHook(cx, functionProto->script(), functionProto); return functionProto; }
static inline bool UncachedInlineCall(VMFrame &f, InitialFrameFlags initial, void **pret, bool *unjittable, uint32_t argc) { JSContext *cx = f.cx; CallArgs args = CallArgsFromSp(argc, f.regs.sp); JSFunction *newfun = args.callee().toFunction(); JSScript *newscript = newfun->script(); bool construct = InitialFrameFlagsAreConstructing(initial); bool newType = construct && cx->typeInferenceEnabled() && types::UseNewType(cx, f.script(), f.pc()); if (!types::TypeMonitorCall(cx, args, construct)) return false; /* Try to compile if not already compiled. */ CompileStatus status = CanMethodJIT(cx, newscript, newscript->code, construct, CompileRequest_Interpreter); if (status == Compile_Error) { /* A runtime exception was thrown, get out. */ return false; } if (status == Compile_Abort) *unjittable = true; /* * Make sure we are not calling from an inline frame if we need to make a * call object for the callee, as doing so could trigger GC and cause * jitcode discarding / frame expansion. */ if (f.regs.inlined() && newfun->isHeavyweight()) { ExpandInlineFrames(cx->compartment); JS_ASSERT(!f.regs.inlined()); } /* * Preserve f.regs.fp while pushing the new frame, for the invariant that * f.regs reflects the state when we entered the stub call. This handoff is * tricky: we need to make sure that f.regs is not updated to the new * frame, and we also need to ensure that cx->regs still points to f.regs * when space is reserved, in case doing so throws an exception. */ FrameRegs regs = f.regs; /* Get pointer to new frame/slots, prepare arguments. */ if (!cx->stack.pushInlineFrame(cx, regs, args, *newfun, newscript, initial, &f.stackLimit)) return false; /* Finish the handoff to the new frame regs. */ PreserveRegsGuard regsGuard(cx, regs); /* Scope with a call object parented by callee's parent. */ if (!regs.fp()->functionPrologue(cx)) return false; /* * If newscript was successfully compiled, run it. Skip for calls which * will be constructing a new type object for 'this'. */ if (!newType) { if (JITScript *jit = newscript->getJIT(regs.fp()->isConstructing(), cx->compartment->needsBarrier())) { if (jit->invokeEntry) { *pret = jit->invokeEntry; /* Restore the old fp around and let the JIT code repush the new fp. */ regs.popFrame((Value *) regs.fp()); return true; } } } /* * Otherwise, run newscript in the interpreter. Expand any inlined frame we * are calling from, as the new frame is not associated with the VMFrame * and will not have its prevpc info updated if frame expansion is * triggered while interpreting. */ if (f.regs.inlined()) { ExpandInlineFrames(cx->compartment); JS_ASSERT(!f.regs.inlined()); regs.fp()->resetInlinePrev(f.fp(), f.regs.pc); } JS_CHECK_RECURSION(cx, return false); bool ok = Interpret(cx, cx->fp()); f.cx->stack.popInlineFrame(regs); if (ok) types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval()); *pret = NULL; return ok; }
void js_PutCallObject(StackFrame *fp) { CallObject &callobj = fp->callObj().asCall(); JS_ASSERT(callobj.maybeStackFrame() == fp); JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame()); JS_ASSERT(fp->isEvalFrame() == callobj.isForEval()); /* Get the arguments object to snapshot fp's actual argument values. */ if (fp->hasArgsObj()) { if (callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS)) callobj.setArguments(ObjectValue(fp->argsObj())); js_PutArgsObject(fp); } JSScript *script = fp->script(); Bindings &bindings = script->bindings; if (callobj.isForEval()) { JS_ASSERT(script->strictModeCode); JS_ASSERT(bindings.countArgs() == 0); /* This could be optimized as below, but keep it simple for now. */ callobj.copyValues(0, NULL, bindings.countVars(), fp->slots()); } else { JSFunction *fun = fp->fun(); JS_ASSERT(script == callobj.getCalleeFunction()->script()); JS_ASSERT(script == fun->script()); unsigned n = bindings.countArgsAndVars(); if (n > 0) { uint32_t nvars = bindings.countVars(); uint32_t nargs = bindings.countArgs(); JS_ASSERT(fun->nargs == nargs); JS_ASSERT(nvars + nargs == n); JSScript *script = fun->script(); if (script->usesEval #ifdef JS_METHODJIT || script->debugMode #endif ) { callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots()); } else { /* * For each arg & var that is closed over, copy it from the stack * into the call object. We use initArg/VarUnchecked because, * when you call a getter on a call object, js_NativeGetInline * caches the return value in the slot, so we can't assert that * it's undefined. */ uint32_t nclosed = script->nClosedArgs; for (uint32_t i = 0; i < nclosed; i++) { uint32_t e = script->getClosedArg(i); #ifdef JS_GC_ZEAL callobj.setArg(e, fp->formalArg(e)); #else callobj.initArgUnchecked(e, fp->formalArg(e)); #endif } nclosed = script->nClosedVars; for (uint32_t i = 0; i < nclosed; i++) { uint32_t e = script->getClosedVar(i); #ifdef JS_GC_ZEAL callobj.setVar(e, fp->slots()[e]); #else callobj.initVarUnchecked(e, fp->slots()[e]); #endif } } /* * Update the args and vars for the active call if this is an outer * function in a script nesting. */ types::TypeScriptNesting *nesting = script->nesting(); if (nesting && script->isOuterFunction) { nesting->argArray = callobj.argArray(); nesting->varArray = callobj.varArray(); } } /* Clear private pointers to fp, which is about to go away. */ if (js_IsNamedLambda(fun)) { JSObject &env = callobj.enclosingScope(); JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp); env.setPrivate(NULL); } } callobj.setStackFrame(NULL); }