1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsanalyze.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,216 @@ 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 +/* Definitions for javascript analysis. */ 1.11 + 1.12 +#ifndef jsanalyze_h 1.13 +#define jsanalyze_h 1.14 + 1.15 +#include "jscompartment.h" 1.16 + 1.17 +namespace js { 1.18 +namespace analyze { 1.19 + 1.20 +class Bytecode; 1.21 +struct LifetimeVariable; 1.22 +class SlotValue; 1.23 +class SSAValue; 1.24 +struct SSAValueInfo; 1.25 +class SSAUseChain; 1.26 + 1.27 +// Common representation of slots between ScriptAnalysis, TypeScript, and in the 1.28 +// case of TotalSlots, Ion. 1.29 +static inline uint32_t ThisSlot() { 1.30 + return 0; 1.31 +} 1.32 +static inline uint32_t ArgSlot(uint32_t arg) { 1.33 + return 1 + arg; 1.34 +} 1.35 +static inline uint32_t LocalSlot(JSScript *script, uint32_t local) { 1.36 + return 1 + local + 1.37 + (script->functionNonDelazifying() ? script->functionNonDelazifying()->nargs() : 0); 1.38 +} 1.39 +static inline uint32_t TotalSlots(JSScript *script) { 1.40 + return LocalSlot(script, 0) + script->nfixed(); 1.41 +} 1.42 + 1.43 +// Analysis information about a script. FIXME: At this point, the entire 1.44 +// purpose of this class is to compute JSScript::needsArgsObj, and to support 1.45 +// isReachable() in order for jsinfer.cpp:FindPreviousInnerInitializer to get 1.46 +// the previous opcode. For that purpose, it is completely overkill. 1.47 +class ScriptAnalysis 1.48 +{ 1.49 + friend class Bytecode; 1.50 + 1.51 + JSScript *script_; 1.52 + 1.53 + Bytecode **codeArray; 1.54 + 1.55 + uint32_t numSlots; 1.56 + 1.57 + bool *escapedSlots; 1.58 + 1.59 +#ifdef DEBUG 1.60 + /* Whether the compartment was in debug mode when we performed the analysis. */ 1.61 + bool originalDebugMode_: 1; 1.62 +#endif 1.63 + 1.64 + /* --------- Bytecode analysis --------- */ 1.65 + 1.66 + bool canTrackVars:1; 1.67 + bool argumentsContentsObserved_:1; 1.68 + 1.69 + /* --------- Lifetime analysis --------- */ 1.70 + 1.71 + LifetimeVariable *lifetimes; 1.72 + 1.73 + public: 1.74 + ScriptAnalysis(JSScript *script) { 1.75 + mozilla::PodZero(this); 1.76 + this->script_ = script; 1.77 +#ifdef DEBUG 1.78 + this->originalDebugMode_ = script_->compartment()->debugMode(); 1.79 +#endif 1.80 + } 1.81 + 1.82 + MOZ_WARN_UNUSED_RESULT 1.83 + bool analyzeBytecode(JSContext *cx); 1.84 + 1.85 + bool isReachable(const jsbytecode *pc) { return maybeCode(pc); } 1.86 + 1.87 + private: 1.88 + MOZ_WARN_UNUSED_RESULT 1.89 + bool analyzeSSA(JSContext *cx); 1.90 + MOZ_WARN_UNUSED_RESULT 1.91 + bool analyzeLifetimes(JSContext *cx); 1.92 + 1.93 + /* Accessors for bytecode information. */ 1.94 + Bytecode& getCode(uint32_t offset) { 1.95 + JS_ASSERT(offset < script_->length()); 1.96 + JS_ASSERT(codeArray[offset]); 1.97 + return *codeArray[offset]; 1.98 + } 1.99 + Bytecode& getCode(const jsbytecode *pc) { return getCode(script_->pcToOffset(pc)); } 1.100 + 1.101 + Bytecode* maybeCode(uint32_t offset) { 1.102 + JS_ASSERT(offset < script_->length()); 1.103 + return codeArray[offset]; 1.104 + } 1.105 + Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(script_->pcToOffset(pc)); } 1.106 + 1.107 + inline bool jumpTarget(uint32_t offset); 1.108 + inline bool jumpTarget(const jsbytecode *pc); 1.109 + 1.110 + inline const SSAValue &poppedValue(uint32_t offset, uint32_t which); 1.111 + inline const SSAValue &poppedValue(const jsbytecode *pc, uint32_t which); 1.112 + 1.113 + inline const SlotValue *newValues(uint32_t offset); 1.114 + inline const SlotValue *newValues(const jsbytecode *pc); 1.115 + 1.116 + inline bool trackUseChain(const SSAValue &v); 1.117 + 1.118 + /* 1.119 + * Get the use chain for an SSA value. 1.120 + */ 1.121 + inline SSAUseChain *& useChain(const SSAValue &v); 1.122 + 1.123 + 1.124 + /* For a JSOP_CALL* op, get the pc of the corresponding JSOP_CALL/NEW/etc. */ 1.125 + inline jsbytecode *getCallPC(jsbytecode *pc); 1.126 + 1.127 + /* Accessors for local variable information. */ 1.128 + 1.129 + /* 1.130 + * Escaping slots include all slots that can be accessed in ways other than 1.131 + * through the corresponding LOCAL/ARG opcode. This includes all closed 1.132 + * slots in the script, all slots in scripts which use eval or are in debug 1.133 + * mode, and slots which are aliased by NAME or similar opcodes in the 1.134 + * containing script (which does not imply the variable is closed). 1.135 + */ 1.136 + inline bool slotEscapes(uint32_t slot); 1.137 + 1.138 + /* 1.139 + * Whether we distinguish different writes of this variable while doing 1.140 + * SSA analysis. Escaping locals can be written in other scripts, and the 1.141 + * presence of NAME opcodes which could alias local variables or arguments 1.142 + * keeps us from tracking variable values at each point. 1.143 + */ 1.144 + inline bool trackSlot(uint32_t slot); 1.145 + 1.146 + inline const LifetimeVariable & liveness(uint32_t slot); 1.147 + 1.148 + void printSSA(JSContext *cx); 1.149 + void printTypes(JSContext *cx); 1.150 + 1.151 + /* Bytecode helpers */ 1.152 + MOZ_WARN_UNUSED_RESULT 1.153 + inline bool addJump(JSContext *cx, unsigned offset, 1.154 + unsigned *currentOffset, unsigned *forwardJump, unsigned *forwardLoop, 1.155 + unsigned stackDepth); 1.156 + 1.157 + /* Lifetime helpers */ 1.158 + MOZ_WARN_UNUSED_RESULT 1.159 + inline bool addVariable(JSContext *cx, LifetimeVariable &var, unsigned offset, 1.160 + LifetimeVariable **&saved, unsigned &savedCount); 1.161 + MOZ_WARN_UNUSED_RESULT 1.162 + inline bool killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset, 1.163 + LifetimeVariable **&saved, unsigned &savedCount); 1.164 + MOZ_WARN_UNUSED_RESULT 1.165 + inline bool extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end); 1.166 + 1.167 + inline void ensureVariable(LifetimeVariable &var, unsigned until); 1.168 + 1.169 + /* SSA helpers */ 1.170 + MOZ_WARN_UNUSED_RESULT 1.171 + bool makePhi(JSContext *cx, uint32_t slot, uint32_t offset, SSAValue *pv); 1.172 + MOZ_WARN_UNUSED_RESULT 1.173 + bool insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v); 1.174 + MOZ_WARN_UNUSED_RESULT 1.175 + bool mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv); 1.176 + MOZ_WARN_UNUSED_RESULT 1.177 + bool checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slot, 1.178 + Vector<SlotValue> *pending); 1.179 + MOZ_WARN_UNUSED_RESULT 1.180 + bool checkBranchTarget(JSContext *cx, uint32_t targetOffset, Vector<uint32_t> &branchTargets, 1.181 + SSAValueInfo *values, uint32_t stackDepth); 1.182 + MOZ_WARN_UNUSED_RESULT 1.183 + bool checkExceptionTarget(JSContext *cx, uint32_t catchOffset, 1.184 + Vector<uint32_t> &exceptionTargets); 1.185 + MOZ_WARN_UNUSED_RESULT 1.186 + bool mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot, 1.187 + const Vector<uint32_t> &branchTargets, uint32_t currentOffset); 1.188 + MOZ_WARN_UNUSED_RESULT 1.189 + bool mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint32_t slot, 1.190 + const Vector<uint32_t> &exceptionTargets); 1.191 + MOZ_WARN_UNUSED_RESULT 1.192 + bool mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values, 1.193 + const Vector<uint32_t> &exceptionTargets); 1.194 + MOZ_WARN_UNUSED_RESULT 1.195 + bool freezeNewValues(JSContext *cx, uint32_t offset); 1.196 + 1.197 + typedef Vector<SSAValue, 16> SeenVector; 1.198 + bool needsArgsObj(JSContext *cx, SeenVector &seen, const SSAValue &v); 1.199 + bool needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use); 1.200 + bool needsArgsObj(JSContext *cx); 1.201 + 1.202 + public: 1.203 +#ifdef DEBUG 1.204 + void assertMatchingDebugMode(); 1.205 + void assertMatchingStackDepthAtOffset(uint32_t offset, uint32_t stackDepth); 1.206 +#else 1.207 + void assertMatchingDebugMode() { } 1.208 + void assertMatchingStackDepthAtOffset(uint32_t offset, uint32_t stackDepth) { } 1.209 +#endif 1.210 +}; 1.211 + 1.212 +#ifdef DEBUG 1.213 +void PrintBytecode(JSContext *cx, HandleScript script, jsbytecode *pc); 1.214 +#endif 1.215 + 1.216 +} /* namespace analyze */ 1.217 +} /* namespace js */ 1.218 + 1.219 +#endif /* jsanalyze_h */