michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_CompileInfo_h michael@0: #define jit_CompileInfo_h michael@0: michael@0: #include "jsfun.h" michael@0: michael@0: #include "jit/Registers.h" michael@0: #include "vm/ScopeObject.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: inline unsigned michael@0: StartArgSlot(JSScript *script) michael@0: { michael@0: // Reserved slots: michael@0: // Slot 0: Scope chain. michael@0: // Slot 1: Return value. michael@0: michael@0: // When needed: michael@0: // Slot 2: Argumentsobject. michael@0: michael@0: // Note: when updating this, please also update the assert in SnapshotWriter::startFrame michael@0: return 2 + (script->argumentsHasVarBinding() ? 1 : 0); michael@0: } michael@0: michael@0: inline unsigned michael@0: CountArgSlots(JSScript *script, JSFunction *fun) michael@0: { michael@0: // Slot x + 0: This value. michael@0: // Slot x + 1: Argument 1. michael@0: // ... michael@0: // Slot x + n: Argument n. michael@0: michael@0: // Note: when updating this, please also update the assert in SnapshotWriter::startFrame michael@0: return StartArgSlot(script) + (fun ? fun->nargs() + 1 : 0); michael@0: } michael@0: michael@0: // Contains information about the compilation source for IR being generated. michael@0: class CompileInfo michael@0: { michael@0: public: michael@0: CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing, michael@0: ExecutionMode executionMode, bool scriptNeedsArgsObj) michael@0: : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing), michael@0: executionMode_(executionMode), scriptNeedsArgsObj_(scriptNeedsArgsObj) michael@0: { michael@0: JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY); michael@0: michael@0: // The function here can flow in from anywhere so look up the canonical michael@0: // function to ensure that we do not try to embed a nursery pointer in michael@0: // jit-code. Precisely because it can flow in from anywhere, it's not michael@0: // guaranteed to be non-lazy. Hence, don't access its script! michael@0: if (fun_) { michael@0: fun_ = fun_->nonLazyScript()->functionNonDelazifying(); michael@0: JS_ASSERT(fun_->isTenured()); michael@0: } michael@0: michael@0: osrStaticScope_ = osrPc ? script->getStaticScope(osrPc) : nullptr; michael@0: michael@0: nimplicit_ = StartArgSlot(script) /* scope chain and argument obj */ michael@0: + (fun ? 1 : 0); /* this */ michael@0: nargs_ = fun ? fun->nargs() : 0; michael@0: nfixedvars_ = script->nfixedvars(); michael@0: nlocals_ = script->nfixed(); michael@0: nstack_ = script->nslots() - script->nfixed(); michael@0: nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; michael@0: } michael@0: michael@0: CompileInfo(unsigned nlocals, ExecutionMode executionMode) michael@0: : script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr), michael@0: constructing_(false), executionMode_(executionMode), scriptNeedsArgsObj_(false) michael@0: { michael@0: nimplicit_ = 0; michael@0: nargs_ = 0; michael@0: nfixedvars_ = 0; michael@0: nlocals_ = nlocals; michael@0: nstack_ = 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */ michael@0: nslots_ = nlocals_ + nstack_; michael@0: } michael@0: michael@0: JSScript *script() const { michael@0: return script_; michael@0: } michael@0: JSFunction *funMaybeLazy() const { michael@0: return fun_; michael@0: } michael@0: bool constructing() const { michael@0: return constructing_; michael@0: } michael@0: jsbytecode *osrPc() { michael@0: return osrPc_; michael@0: } michael@0: NestedScopeObject *osrStaticScope() const { michael@0: return osrStaticScope_; michael@0: } michael@0: michael@0: bool hasOsrAt(jsbytecode *pc) { michael@0: JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY); michael@0: return pc == osrPc(); michael@0: } michael@0: michael@0: jsbytecode *startPC() const { michael@0: return script_->code(); michael@0: } michael@0: jsbytecode *limitPC() const { michael@0: return script_->codeEnd(); michael@0: } michael@0: michael@0: const char *filename() const { michael@0: return script_->filename(); michael@0: } michael@0: michael@0: unsigned lineno() const { michael@0: return script_->lineno(); michael@0: } michael@0: unsigned lineno(jsbytecode *pc) const { michael@0: return PCToLineNumber(script_, pc); michael@0: } michael@0: michael@0: // Script accessors based on PC. michael@0: michael@0: JSAtom *getAtom(jsbytecode *pc) const { michael@0: return script_->getAtom(GET_UINT32_INDEX(pc)); michael@0: } michael@0: michael@0: PropertyName *getName(jsbytecode *pc) const { michael@0: return script_->getName(GET_UINT32_INDEX(pc)); michael@0: } michael@0: michael@0: inline RegExpObject *getRegExp(jsbytecode *pc) const; michael@0: michael@0: JSObject *getObject(jsbytecode *pc) const { michael@0: return script_->getObject(GET_UINT32_INDEX(pc)); michael@0: } michael@0: michael@0: inline JSFunction *getFunction(jsbytecode *pc) const; michael@0: michael@0: const Value &getConst(jsbytecode *pc) const { michael@0: return script_->getConst(GET_UINT32_INDEX(pc)); michael@0: } michael@0: michael@0: jssrcnote *getNote(GSNCache &gsn, jsbytecode *pc) const { michael@0: return GetSrcNote(gsn, script(), pc); michael@0: } michael@0: michael@0: // Total number of slots: args, locals, and stack. michael@0: unsigned nslots() const { michael@0: return nslots_; michael@0: } michael@0: michael@0: // Number of slots needed for Scope chain, return value, michael@0: // maybe argumentsobject and this value. michael@0: unsigned nimplicit() const { michael@0: return nimplicit_; michael@0: } michael@0: // Number of arguments (without counting this value). michael@0: unsigned nargs() const { michael@0: return nargs_; michael@0: } michael@0: // Number of slots needed for "fixed vars". Note that this is only non-zero michael@0: // for function code. michael@0: unsigned nfixedvars() const { michael@0: return nfixedvars_; michael@0: } michael@0: // Number of slots needed for all local variables. This includes "fixed michael@0: // vars" (see above) and also block-scoped locals. michael@0: unsigned nlocals() const { michael@0: return nlocals_; michael@0: } michael@0: unsigned ninvoke() const { michael@0: return nslots_ - nstack_; michael@0: } michael@0: michael@0: uint32_t scopeChainSlot() const { michael@0: JS_ASSERT(script()); michael@0: return 0; michael@0: } michael@0: uint32_t returnValueSlot() const { michael@0: JS_ASSERT(script()); michael@0: return 1; michael@0: } michael@0: uint32_t argsObjSlot() const { michael@0: JS_ASSERT(hasArguments()); michael@0: return 2; michael@0: } michael@0: uint32_t thisSlot() const { michael@0: JS_ASSERT(funMaybeLazy()); michael@0: JS_ASSERT(nimplicit_ > 0); michael@0: return nimplicit_ - 1; michael@0: } michael@0: uint32_t firstArgSlot() const { michael@0: return nimplicit_; michael@0: } michael@0: uint32_t argSlotUnchecked(uint32_t i) const { michael@0: // During initialization, some routines need to get at arg michael@0: // slots regardless of how regular argument access is done. michael@0: JS_ASSERT(i < nargs_); michael@0: return nimplicit_ + i; michael@0: } michael@0: uint32_t argSlot(uint32_t i) const { michael@0: // This should only be accessed when compiling functions for michael@0: // which argument accesses don't need to go through the michael@0: // argument object. michael@0: JS_ASSERT(!argsObjAliasesFormals()); michael@0: return argSlotUnchecked(i); michael@0: } michael@0: uint32_t firstLocalSlot() const { michael@0: return nimplicit_ + nargs_; michael@0: } michael@0: uint32_t localSlot(uint32_t i) const { michael@0: return firstLocalSlot() + i; michael@0: } michael@0: uint32_t firstStackSlot() const { michael@0: return firstLocalSlot() + nlocals(); michael@0: } michael@0: uint32_t stackSlot(uint32_t i) const { michael@0: return firstStackSlot() + i; michael@0: } michael@0: michael@0: uint32_t startArgSlot() const { michael@0: JS_ASSERT(script()); michael@0: return StartArgSlot(script()); michael@0: } michael@0: uint32_t endArgSlot() const { michael@0: JS_ASSERT(script()); michael@0: return CountArgSlots(script(), funMaybeLazy()); michael@0: } michael@0: michael@0: uint32_t totalSlots() const { michael@0: JS_ASSERT(script() && funMaybeLazy()); michael@0: return nimplicit() + nargs() + nlocals(); michael@0: } michael@0: michael@0: bool isSlotAliased(uint32_t index, NestedScopeObject *staticScope) const { michael@0: JS_ASSERT(index >= startArgSlot()); michael@0: michael@0: if (funMaybeLazy() && index == thisSlot()) michael@0: return false; michael@0: michael@0: uint32_t arg = index - firstArgSlot(); michael@0: if (arg < nargs()) michael@0: return script()->formalIsAliased(arg); michael@0: michael@0: uint32_t local = index - firstLocalSlot(); michael@0: if (local < nlocals()) { michael@0: // First, check if this local is a var. michael@0: if (local < nfixedvars()) michael@0: return script()->varIsAliased(local); michael@0: michael@0: // Otherwise, it might be part of a block scope. michael@0: for (; staticScope; staticScope = staticScope->enclosingNestedScope()) { michael@0: if (!staticScope->is()) michael@0: continue; michael@0: StaticBlockObject &blockObj = staticScope->as(); michael@0: if (blockObj.localOffset() < local) { michael@0: if (local - blockObj.localOffset() < blockObj.numVariables()) michael@0: return blockObj.isAliased(local - blockObj.localOffset()); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // In this static scope, this var is dead. michael@0: return false; michael@0: } michael@0: michael@0: JS_ASSERT(index >= firstStackSlot()); michael@0: return false; michael@0: } michael@0: michael@0: bool isSlotAliasedAtEntry(uint32_t index) const { michael@0: return isSlotAliased(index, nullptr); michael@0: } michael@0: bool isSlotAliasedAtOsr(uint32_t index) const { michael@0: return isSlotAliased(index, osrStaticScope()); michael@0: } michael@0: michael@0: bool hasArguments() const { michael@0: return script()->argumentsHasVarBinding(); michael@0: } michael@0: bool argumentsAliasesFormals() const { michael@0: return script()->argumentsAliasesFormals(); michael@0: } michael@0: bool needsArgsObj() const { michael@0: return scriptNeedsArgsObj_; michael@0: } michael@0: bool argsObjAliasesFormals() const { michael@0: return scriptNeedsArgsObj_ && !script()->strict(); michael@0: } michael@0: michael@0: ExecutionMode executionMode() const { michael@0: return executionMode_; michael@0: } michael@0: michael@0: bool executionModeIsAnalysis() const { michael@0: return executionMode_ == DefinitePropertiesAnalysis || executionMode_ == ArgumentsUsageAnalysis; michael@0: } michael@0: michael@0: bool isParallelExecution() const { michael@0: return executionMode_ == ParallelExecution; michael@0: } michael@0: michael@0: bool canOptimizeOutSlot(uint32_t i) const { michael@0: if (script()->strict()) michael@0: return true; michael@0: michael@0: // Function.arguments can be used to access all arguments in michael@0: // non-strict scripts, so we can't optimize out any arguments. michael@0: return !(firstArgSlot() <= i && i - firstArgSlot() < nargs()); michael@0: } michael@0: michael@0: private: michael@0: unsigned nimplicit_; michael@0: unsigned nargs_; michael@0: unsigned nfixedvars_; michael@0: unsigned nlocals_; michael@0: unsigned nstack_; michael@0: unsigned nslots_; michael@0: JSScript *script_; michael@0: JSFunction *fun_; michael@0: jsbytecode *osrPc_; michael@0: NestedScopeObject *osrStaticScope_; michael@0: bool constructing_; michael@0: ExecutionMode executionMode_; michael@0: michael@0: // Whether a script needs an arguments object is unstable over compilation michael@0: // since the arguments optimization could be marked as failed on the main michael@0: // thread, so cache a value here and use it throughout for consistency. michael@0: bool scriptNeedsArgsObj_; michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_CompileInfo_h */