1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/CompileInfo.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,340 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_CompileInfo_h 1.11 +#define jit_CompileInfo_h 1.12 + 1.13 +#include "jsfun.h" 1.14 + 1.15 +#include "jit/Registers.h" 1.16 +#include "vm/ScopeObject.h" 1.17 + 1.18 +namespace js { 1.19 +namespace jit { 1.20 + 1.21 +inline unsigned 1.22 +StartArgSlot(JSScript *script) 1.23 +{ 1.24 + // Reserved slots: 1.25 + // Slot 0: Scope chain. 1.26 + // Slot 1: Return value. 1.27 + 1.28 + // When needed: 1.29 + // Slot 2: Argumentsobject. 1.30 + 1.31 + // Note: when updating this, please also update the assert in SnapshotWriter::startFrame 1.32 + return 2 + (script->argumentsHasVarBinding() ? 1 : 0); 1.33 +} 1.34 + 1.35 +inline unsigned 1.36 +CountArgSlots(JSScript *script, JSFunction *fun) 1.37 +{ 1.38 + // Slot x + 0: This value. 1.39 + // Slot x + 1: Argument 1. 1.40 + // ... 1.41 + // Slot x + n: Argument n. 1.42 + 1.43 + // Note: when updating this, please also update the assert in SnapshotWriter::startFrame 1.44 + return StartArgSlot(script) + (fun ? fun->nargs() + 1 : 0); 1.45 +} 1.46 + 1.47 +// Contains information about the compilation source for IR being generated. 1.48 +class CompileInfo 1.49 +{ 1.50 + public: 1.51 + CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing, 1.52 + ExecutionMode executionMode, bool scriptNeedsArgsObj) 1.53 + : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing), 1.54 + executionMode_(executionMode), scriptNeedsArgsObj_(scriptNeedsArgsObj) 1.55 + { 1.56 + JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY); 1.57 + 1.58 + // The function here can flow in from anywhere so look up the canonical 1.59 + // function to ensure that we do not try to embed a nursery pointer in 1.60 + // jit-code. Precisely because it can flow in from anywhere, it's not 1.61 + // guaranteed to be non-lazy. Hence, don't access its script! 1.62 + if (fun_) { 1.63 + fun_ = fun_->nonLazyScript()->functionNonDelazifying(); 1.64 + JS_ASSERT(fun_->isTenured()); 1.65 + } 1.66 + 1.67 + osrStaticScope_ = osrPc ? script->getStaticScope(osrPc) : nullptr; 1.68 + 1.69 + nimplicit_ = StartArgSlot(script) /* scope chain and argument obj */ 1.70 + + (fun ? 1 : 0); /* this */ 1.71 + nargs_ = fun ? fun->nargs() : 0; 1.72 + nfixedvars_ = script->nfixedvars(); 1.73 + nlocals_ = script->nfixed(); 1.74 + nstack_ = script->nslots() - script->nfixed(); 1.75 + nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; 1.76 + } 1.77 + 1.78 + CompileInfo(unsigned nlocals, ExecutionMode executionMode) 1.79 + : script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr), 1.80 + constructing_(false), executionMode_(executionMode), scriptNeedsArgsObj_(false) 1.81 + { 1.82 + nimplicit_ = 0; 1.83 + nargs_ = 0; 1.84 + nfixedvars_ = 0; 1.85 + nlocals_ = nlocals; 1.86 + nstack_ = 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */ 1.87 + nslots_ = nlocals_ + nstack_; 1.88 + } 1.89 + 1.90 + JSScript *script() const { 1.91 + return script_; 1.92 + } 1.93 + JSFunction *funMaybeLazy() const { 1.94 + return fun_; 1.95 + } 1.96 + bool constructing() const { 1.97 + return constructing_; 1.98 + } 1.99 + jsbytecode *osrPc() { 1.100 + return osrPc_; 1.101 + } 1.102 + NestedScopeObject *osrStaticScope() const { 1.103 + return osrStaticScope_; 1.104 + } 1.105 + 1.106 + bool hasOsrAt(jsbytecode *pc) { 1.107 + JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY); 1.108 + return pc == osrPc(); 1.109 + } 1.110 + 1.111 + jsbytecode *startPC() const { 1.112 + return script_->code(); 1.113 + } 1.114 + jsbytecode *limitPC() const { 1.115 + return script_->codeEnd(); 1.116 + } 1.117 + 1.118 + const char *filename() const { 1.119 + return script_->filename(); 1.120 + } 1.121 + 1.122 + unsigned lineno() const { 1.123 + return script_->lineno(); 1.124 + } 1.125 + unsigned lineno(jsbytecode *pc) const { 1.126 + return PCToLineNumber(script_, pc); 1.127 + } 1.128 + 1.129 + // Script accessors based on PC. 1.130 + 1.131 + JSAtom *getAtom(jsbytecode *pc) const { 1.132 + return script_->getAtom(GET_UINT32_INDEX(pc)); 1.133 + } 1.134 + 1.135 + PropertyName *getName(jsbytecode *pc) const { 1.136 + return script_->getName(GET_UINT32_INDEX(pc)); 1.137 + } 1.138 + 1.139 + inline RegExpObject *getRegExp(jsbytecode *pc) const; 1.140 + 1.141 + JSObject *getObject(jsbytecode *pc) const { 1.142 + return script_->getObject(GET_UINT32_INDEX(pc)); 1.143 + } 1.144 + 1.145 + inline JSFunction *getFunction(jsbytecode *pc) const; 1.146 + 1.147 + const Value &getConst(jsbytecode *pc) const { 1.148 + return script_->getConst(GET_UINT32_INDEX(pc)); 1.149 + } 1.150 + 1.151 + jssrcnote *getNote(GSNCache &gsn, jsbytecode *pc) const { 1.152 + return GetSrcNote(gsn, script(), pc); 1.153 + } 1.154 + 1.155 + // Total number of slots: args, locals, and stack. 1.156 + unsigned nslots() const { 1.157 + return nslots_; 1.158 + } 1.159 + 1.160 + // Number of slots needed for Scope chain, return value, 1.161 + // maybe argumentsobject and this value. 1.162 + unsigned nimplicit() const { 1.163 + return nimplicit_; 1.164 + } 1.165 + // Number of arguments (without counting this value). 1.166 + unsigned nargs() const { 1.167 + return nargs_; 1.168 + } 1.169 + // Number of slots needed for "fixed vars". Note that this is only non-zero 1.170 + // for function code. 1.171 + unsigned nfixedvars() const { 1.172 + return nfixedvars_; 1.173 + } 1.174 + // Number of slots needed for all local variables. This includes "fixed 1.175 + // vars" (see above) and also block-scoped locals. 1.176 + unsigned nlocals() const { 1.177 + return nlocals_; 1.178 + } 1.179 + unsigned ninvoke() const { 1.180 + return nslots_ - nstack_; 1.181 + } 1.182 + 1.183 + uint32_t scopeChainSlot() const { 1.184 + JS_ASSERT(script()); 1.185 + return 0; 1.186 + } 1.187 + uint32_t returnValueSlot() const { 1.188 + JS_ASSERT(script()); 1.189 + return 1; 1.190 + } 1.191 + uint32_t argsObjSlot() const { 1.192 + JS_ASSERT(hasArguments()); 1.193 + return 2; 1.194 + } 1.195 + uint32_t thisSlot() const { 1.196 + JS_ASSERT(funMaybeLazy()); 1.197 + JS_ASSERT(nimplicit_ > 0); 1.198 + return nimplicit_ - 1; 1.199 + } 1.200 + uint32_t firstArgSlot() const { 1.201 + return nimplicit_; 1.202 + } 1.203 + uint32_t argSlotUnchecked(uint32_t i) const { 1.204 + // During initialization, some routines need to get at arg 1.205 + // slots regardless of how regular argument access is done. 1.206 + JS_ASSERT(i < nargs_); 1.207 + return nimplicit_ + i; 1.208 + } 1.209 + uint32_t argSlot(uint32_t i) const { 1.210 + // This should only be accessed when compiling functions for 1.211 + // which argument accesses don't need to go through the 1.212 + // argument object. 1.213 + JS_ASSERT(!argsObjAliasesFormals()); 1.214 + return argSlotUnchecked(i); 1.215 + } 1.216 + uint32_t firstLocalSlot() const { 1.217 + return nimplicit_ + nargs_; 1.218 + } 1.219 + uint32_t localSlot(uint32_t i) const { 1.220 + return firstLocalSlot() + i; 1.221 + } 1.222 + uint32_t firstStackSlot() const { 1.223 + return firstLocalSlot() + nlocals(); 1.224 + } 1.225 + uint32_t stackSlot(uint32_t i) const { 1.226 + return firstStackSlot() + i; 1.227 + } 1.228 + 1.229 + uint32_t startArgSlot() const { 1.230 + JS_ASSERT(script()); 1.231 + return StartArgSlot(script()); 1.232 + } 1.233 + uint32_t endArgSlot() const { 1.234 + JS_ASSERT(script()); 1.235 + return CountArgSlots(script(), funMaybeLazy()); 1.236 + } 1.237 + 1.238 + uint32_t totalSlots() const { 1.239 + JS_ASSERT(script() && funMaybeLazy()); 1.240 + return nimplicit() + nargs() + nlocals(); 1.241 + } 1.242 + 1.243 + bool isSlotAliased(uint32_t index, NestedScopeObject *staticScope) const { 1.244 + JS_ASSERT(index >= startArgSlot()); 1.245 + 1.246 + if (funMaybeLazy() && index == thisSlot()) 1.247 + return false; 1.248 + 1.249 + uint32_t arg = index - firstArgSlot(); 1.250 + if (arg < nargs()) 1.251 + return script()->formalIsAliased(arg); 1.252 + 1.253 + uint32_t local = index - firstLocalSlot(); 1.254 + if (local < nlocals()) { 1.255 + // First, check if this local is a var. 1.256 + if (local < nfixedvars()) 1.257 + return script()->varIsAliased(local); 1.258 + 1.259 + // Otherwise, it might be part of a block scope. 1.260 + for (; staticScope; staticScope = staticScope->enclosingNestedScope()) { 1.261 + if (!staticScope->is<StaticBlockObject>()) 1.262 + continue; 1.263 + StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>(); 1.264 + if (blockObj.localOffset() < local) { 1.265 + if (local - blockObj.localOffset() < blockObj.numVariables()) 1.266 + return blockObj.isAliased(local - blockObj.localOffset()); 1.267 + return false; 1.268 + } 1.269 + } 1.270 + 1.271 + // In this static scope, this var is dead. 1.272 + return false; 1.273 + } 1.274 + 1.275 + JS_ASSERT(index >= firstStackSlot()); 1.276 + return false; 1.277 + } 1.278 + 1.279 + bool isSlotAliasedAtEntry(uint32_t index) const { 1.280 + return isSlotAliased(index, nullptr); 1.281 + } 1.282 + bool isSlotAliasedAtOsr(uint32_t index) const { 1.283 + return isSlotAliased(index, osrStaticScope()); 1.284 + } 1.285 + 1.286 + bool hasArguments() const { 1.287 + return script()->argumentsHasVarBinding(); 1.288 + } 1.289 + bool argumentsAliasesFormals() const { 1.290 + return script()->argumentsAliasesFormals(); 1.291 + } 1.292 + bool needsArgsObj() const { 1.293 + return scriptNeedsArgsObj_; 1.294 + } 1.295 + bool argsObjAliasesFormals() const { 1.296 + return scriptNeedsArgsObj_ && !script()->strict(); 1.297 + } 1.298 + 1.299 + ExecutionMode executionMode() const { 1.300 + return executionMode_; 1.301 + } 1.302 + 1.303 + bool executionModeIsAnalysis() const { 1.304 + return executionMode_ == DefinitePropertiesAnalysis || executionMode_ == ArgumentsUsageAnalysis; 1.305 + } 1.306 + 1.307 + bool isParallelExecution() const { 1.308 + return executionMode_ == ParallelExecution; 1.309 + } 1.310 + 1.311 + bool canOptimizeOutSlot(uint32_t i) const { 1.312 + if (script()->strict()) 1.313 + return true; 1.314 + 1.315 + // Function.arguments can be used to access all arguments in 1.316 + // non-strict scripts, so we can't optimize out any arguments. 1.317 + return !(firstArgSlot() <= i && i - firstArgSlot() < nargs()); 1.318 + } 1.319 + 1.320 + private: 1.321 + unsigned nimplicit_; 1.322 + unsigned nargs_; 1.323 + unsigned nfixedvars_; 1.324 + unsigned nlocals_; 1.325 + unsigned nstack_; 1.326 + unsigned nslots_; 1.327 + JSScript *script_; 1.328 + JSFunction *fun_; 1.329 + jsbytecode *osrPc_; 1.330 + NestedScopeObject *osrStaticScope_; 1.331 + bool constructing_; 1.332 + ExecutionMode executionMode_; 1.333 + 1.334 + // Whether a script needs an arguments object is unstable over compilation 1.335 + // since the arguments optimization could be marked as failed on the main 1.336 + // thread, so cache a value here and use it throughout for consistency. 1.337 + bool scriptNeedsArgsObj_; 1.338 +}; 1.339 + 1.340 +} // namespace jit 1.341 +} // namespace js 1.342 + 1.343 +#endif /* jit_CompileInfo_h */