1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/BaselineJIT.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,430 @@ 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_BaselineJIT_h 1.11 +#define jit_BaselineJIT_h 1.12 + 1.13 +#ifdef JS_ION 1.14 + 1.15 +#include "mozilla/MemoryReporting.h" 1.16 + 1.17 +#include "jscntxt.h" 1.18 +#include "jscompartment.h" 1.19 + 1.20 +#include "ds/LifoAlloc.h" 1.21 +#include "jit/Bailouts.h" 1.22 +#include "jit/IonCode.h" 1.23 +#include "jit/IonMacroAssembler.h" 1.24 + 1.25 +namespace js { 1.26 +namespace jit { 1.27 + 1.28 +class StackValue; 1.29 +class ICEntry; 1.30 +class ICStub; 1.31 + 1.32 +class PCMappingSlotInfo 1.33 +{ 1.34 + uint8_t slotInfo_; 1.35 + 1.36 + public: 1.37 + // SlotInfo encoding: 1.38 + // Bits 0 & 1: number of slots at top of stack which are unsynced. 1.39 + // Bits 2 & 3: SlotLocation of top slot value (only relevant if numUnsynced > 0). 1.40 + // Bits 3 & 4: SlotLocation of next slot value (only relevant if numUnsynced > 1). 1.41 + enum SlotLocation { SlotInR0 = 0, SlotInR1 = 1, SlotIgnore = 3 }; 1.42 + 1.43 + PCMappingSlotInfo() 1.44 + : slotInfo_(0) 1.45 + { } 1.46 + 1.47 + explicit PCMappingSlotInfo(uint8_t slotInfo) 1.48 + : slotInfo_(slotInfo) 1.49 + { } 1.50 + 1.51 + static inline bool ValidSlotLocation(SlotLocation loc) { 1.52 + return (loc == SlotInR0) || (loc == SlotInR1) || (loc == SlotIgnore); 1.53 + } 1.54 + 1.55 + static SlotLocation ToSlotLocation(const StackValue *stackVal); 1.56 + 1.57 + inline static PCMappingSlotInfo MakeSlotInfo() { return PCMappingSlotInfo(0); } 1.58 + 1.59 + inline static PCMappingSlotInfo MakeSlotInfo(SlotLocation topSlotLoc) { 1.60 + JS_ASSERT(ValidSlotLocation(topSlotLoc)); 1.61 + return PCMappingSlotInfo(1 | (topSlotLoc << 2)); 1.62 + } 1.63 + 1.64 + inline static PCMappingSlotInfo MakeSlotInfo(SlotLocation topSlotLoc, SlotLocation nextSlotLoc) { 1.65 + JS_ASSERT(ValidSlotLocation(topSlotLoc)); 1.66 + JS_ASSERT(ValidSlotLocation(nextSlotLoc)); 1.67 + return PCMappingSlotInfo(2 | (topSlotLoc << 2) | (nextSlotLoc) << 4); 1.68 + } 1.69 + 1.70 + inline unsigned numUnsynced() const { 1.71 + return slotInfo_ & 0x3; 1.72 + } 1.73 + inline SlotLocation topSlotLocation() const { 1.74 + return static_cast<SlotLocation>((slotInfo_ >> 2) & 0x3); 1.75 + } 1.76 + inline SlotLocation nextSlotLocation() const { 1.77 + return static_cast<SlotLocation>((slotInfo_ >> 4) & 0x3); 1.78 + } 1.79 + inline uint8_t toByte() const { 1.80 + return slotInfo_; 1.81 + } 1.82 +}; 1.83 + 1.84 +// A CompactBuffer is used to store native code offsets (relative to the 1.85 +// previous pc) and PCMappingSlotInfo bytes. To allow binary search into this 1.86 +// table, we maintain a second table of "index" entries. Every X ops, the 1.87 +// compiler will add an index entry, so that from the index entry to the 1.88 +// actual native code offset, we have to iterate at most X times. 1.89 +struct PCMappingIndexEntry 1.90 +{ 1.91 + // jsbytecode offset. 1.92 + uint32_t pcOffset; 1.93 + 1.94 + // Native code offset. 1.95 + uint32_t nativeOffset; 1.96 + 1.97 + // Offset in the CompactBuffer where data for pcOffset starts. 1.98 + uint32_t bufferOffset; 1.99 +}; 1.100 + 1.101 +struct BaselineScript 1.102 +{ 1.103 + public: 1.104 + static const uint32_t MAX_JSSCRIPT_LENGTH = 0x0fffffffu; 1.105 + 1.106 + // Limit the locals on a given script so that stack check on baseline frames 1.107 + // doesn't overflow a uint32_t value. 1.108 + // (MAX_JSSCRIPT_SLOTS * sizeof(Value)) must fit within a uint32_t. 1.109 + static const uint32_t MAX_JSSCRIPT_SLOTS = 0xffffu; 1.110 + 1.111 + private: 1.112 + // Code pointer containing the actual method. 1.113 + HeapPtr<JitCode> method_; 1.114 + 1.115 + // For heavyweight scripts, template objects to use for the call object and 1.116 + // decl env object (linked via the call object's enclosing scope). 1.117 + HeapPtrObject templateScope_; 1.118 + 1.119 + // Allocated space for fallback stubs. 1.120 + FallbackICStubSpace fallbackStubSpace_; 1.121 + 1.122 + // Native code offset right before the scope chain is initialized. 1.123 + uint32_t prologueOffset_; 1.124 + 1.125 + // Native code offset right before the frame is popped and the method 1.126 + // returned from. 1.127 + uint32_t epilogueOffset_; 1.128 + 1.129 + // The offsets for the toggledJump instructions for SPS update ICs. 1.130 +#ifdef DEBUG 1.131 + mozilla::DebugOnly<bool> spsOn_; 1.132 +#endif 1.133 + uint32_t spsPushToggleOffset_; 1.134 + 1.135 + // Native code offsets right after the debug prologue VM call returns, or 1.136 + // would have returned. This offset is recorded even when debug mode is 1.137 + // off to aid on-stack debug mode recompilation. 1.138 + // 1.139 + // We don't need one for the debug epilogue because that always happens 1.140 + // right before the epilogue, so we just use the epilogue offset. 1.141 + uint32_t postDebugPrologueOffset_; 1.142 + 1.143 + public: 1.144 + enum Flag { 1.145 + // Flag set by JSScript::argumentsOptimizationFailed. Similar to 1.146 + // JSScript::needsArgsObj_, but can be read from JIT code. 1.147 + NEEDS_ARGS_OBJ = 1 << 0, 1.148 + 1.149 + // Flag set when discarding JIT code, to indicate this script is 1.150 + // on the stack and should not be discarded. 1.151 + ACTIVE = 1 << 1, 1.152 + 1.153 + // Flag set when the script contains any writes to its on-stack 1.154 + // (rather than call object stored) arguments. 1.155 + MODIFIES_ARGUMENTS = 1 << 2, 1.156 + 1.157 + // Flag set when compiled for use for debug mode. Handles various 1.158 + // Debugger hooks and compiles toggled calls for traps. 1.159 + DEBUG_MODE = 1 << 3 1.160 + }; 1.161 + 1.162 + private: 1.163 + uint32_t flags_; 1.164 + 1.165 + private: 1.166 + void trace(JSTracer *trc); 1.167 + 1.168 + uint32_t icEntriesOffset_; 1.169 + uint32_t icEntries_; 1.170 + 1.171 + uint32_t pcMappingIndexOffset_; 1.172 + uint32_t pcMappingIndexEntries_; 1.173 + 1.174 + uint32_t pcMappingOffset_; 1.175 + uint32_t pcMappingSize_; 1.176 + 1.177 + // List mapping indexes of bytecode type sets to the offset of the opcode 1.178 + // they correspond to, for use by TypeScript::BytecodeTypes. 1.179 + uint32_t bytecodeTypeMapOffset_; 1.180 + 1.181 + public: 1.182 + // Do not call directly, use BaselineScript::New. This is public for cx->new_. 1.183 + BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset, 1.184 + uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset); 1.185 + 1.186 + static BaselineScript *New(JSContext *cx, uint32_t prologueOffset, 1.187 + uint32_t epilogueOffset, uint32_t postDebugPrologueOffset, 1.188 + uint32_t spsPushToggleOffset, size_t icEntries, 1.189 + size_t pcMappingIndexEntries, size_t pcMappingSize, 1.190 + size_t bytecodeTypeMapEntries); 1.191 + static void Trace(JSTracer *trc, BaselineScript *script); 1.192 + static void Destroy(FreeOp *fop, BaselineScript *script); 1.193 + 1.194 + void purgeOptimizedStubs(Zone *zone); 1.195 + 1.196 + static inline size_t offsetOfMethod() { 1.197 + return offsetof(BaselineScript, method_); 1.198 + } 1.199 + 1.200 + void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t *data, 1.201 + size_t *fallbackStubs) const { 1.202 + *data += mallocSizeOf(this); 1.203 + 1.204 + // |data| already includes the ICStubSpace itself, so use 1.205 + // sizeOfExcludingThis. 1.206 + *fallbackStubs += fallbackStubSpace_.sizeOfExcludingThis(mallocSizeOf); 1.207 + } 1.208 + 1.209 + bool active() const { 1.210 + return flags_ & ACTIVE; 1.211 + } 1.212 + void setActive() { 1.213 + flags_ |= ACTIVE; 1.214 + } 1.215 + void resetActive() { 1.216 + flags_ &= ~ACTIVE; 1.217 + } 1.218 + 1.219 + void setNeedsArgsObj() { 1.220 + flags_ |= NEEDS_ARGS_OBJ; 1.221 + } 1.222 + 1.223 + void setModifiesArguments() { 1.224 + flags_ |= MODIFIES_ARGUMENTS; 1.225 + } 1.226 + bool modifiesArguments() { 1.227 + return flags_ & MODIFIES_ARGUMENTS; 1.228 + } 1.229 + 1.230 + void setDebugMode() { 1.231 + flags_ |= DEBUG_MODE; 1.232 + } 1.233 + bool debugMode() const { 1.234 + return flags_ & DEBUG_MODE; 1.235 + } 1.236 + 1.237 + uint32_t prologueOffset() const { 1.238 + return prologueOffset_; 1.239 + } 1.240 + uint8_t *prologueEntryAddr() const { 1.241 + return method_->raw() + prologueOffset_; 1.242 + } 1.243 + 1.244 + uint32_t epilogueOffset() const { 1.245 + return epilogueOffset_; 1.246 + } 1.247 + uint8_t *epilogueEntryAddr() const { 1.248 + return method_->raw() + epilogueOffset_; 1.249 + } 1.250 + 1.251 + uint32_t postDebugPrologueOffset() const { 1.252 + return postDebugPrologueOffset_; 1.253 + } 1.254 + uint8_t *postDebugPrologueAddr() const { 1.255 + return method_->raw() + postDebugPrologueOffset_; 1.256 + } 1.257 + 1.258 + ICEntry *icEntryList() { 1.259 + return (ICEntry *)(reinterpret_cast<uint8_t *>(this) + icEntriesOffset_); 1.260 + } 1.261 + PCMappingIndexEntry *pcMappingIndexEntryList() { 1.262 + return (PCMappingIndexEntry *)(reinterpret_cast<uint8_t *>(this) + pcMappingIndexOffset_); 1.263 + } 1.264 + uint8_t *pcMappingData() { 1.265 + return reinterpret_cast<uint8_t *>(this) + pcMappingOffset_; 1.266 + } 1.267 + FallbackICStubSpace *fallbackStubSpace() { 1.268 + return &fallbackStubSpace_; 1.269 + } 1.270 + 1.271 + JitCode *method() const { 1.272 + return method_; 1.273 + } 1.274 + void setMethod(JitCode *code) { 1.275 + JS_ASSERT(!method_); 1.276 + method_ = code; 1.277 + } 1.278 + 1.279 + JSObject *templateScope() const { 1.280 + return templateScope_; 1.281 + } 1.282 + void setTemplateScope(JSObject *templateScope) { 1.283 + JS_ASSERT(!templateScope_); 1.284 + templateScope_ = templateScope; 1.285 + } 1.286 + 1.287 + void toggleBarriers(bool enabled) { 1.288 + method()->togglePreBarriers(enabled); 1.289 + } 1.290 + 1.291 + bool containsCodeAddress(uint8_t *addr) const { 1.292 + return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize(); 1.293 + } 1.294 + 1.295 + ICEntry &icEntry(size_t index); 1.296 + ICEntry *maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset); 1.297 + ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset); 1.298 + ICEntry &icEntryFromPCOffset(uint32_t pcOffset); 1.299 + ICEntry &icEntryForDebugModeRecompileFromPCOffset(uint32_t pcOffset); 1.300 + ICEntry &icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntry); 1.301 + ICEntry *maybeICEntryFromReturnAddress(uint8_t *returnAddr); 1.302 + ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr); 1.303 + uint8_t *returnAddressForIC(const ICEntry &ent); 1.304 + 1.305 + size_t numICEntries() const { 1.306 + return icEntries_; 1.307 + } 1.308 + 1.309 + void copyICEntries(JSScript *script, const ICEntry *entries, MacroAssembler &masm); 1.310 + void adoptFallbackStubs(FallbackICStubSpace *stubSpace); 1.311 + 1.312 + PCMappingIndexEntry &pcMappingIndexEntry(size_t index); 1.313 + CompactBufferReader pcMappingReader(size_t indexEntry); 1.314 + 1.315 + size_t numPCMappingIndexEntries() const { 1.316 + return pcMappingIndexEntries_; 1.317 + } 1.318 + 1.319 + void copyPCMappingIndexEntries(const PCMappingIndexEntry *entries); 1.320 + 1.321 + void copyPCMappingEntries(const CompactBufferWriter &entries); 1.322 + uint8_t *nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo = nullptr); 1.323 + jsbytecode *pcForReturnOffset(JSScript *script, uint32_t nativeOffset); 1.324 + jsbytecode *pcForReturnAddress(JSScript *script, uint8_t *nativeAddress); 1.325 + 1.326 + // Toggle debug traps (used for breakpoints and step mode) in the script. 1.327 + // If |pc| is nullptr, toggle traps for all ops in the script. Else, only 1.328 + // toggle traps at |pc|. 1.329 + void toggleDebugTraps(JSScript *script, jsbytecode *pc); 1.330 + 1.331 + void toggleSPS(bool enable); 1.332 + 1.333 + void noteAccessedGetter(uint32_t pcOffset); 1.334 + void noteArrayWriteHole(uint32_t pcOffset); 1.335 + 1.336 + static size_t offsetOfFlags() { 1.337 + return offsetof(BaselineScript, flags_); 1.338 + } 1.339 + 1.340 + static void writeBarrierPre(Zone *zone, BaselineScript *script); 1.341 + 1.342 + uint32_t *bytecodeTypeMap() { 1.343 + JS_ASSERT(bytecodeTypeMapOffset_); 1.344 + return reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(this) + bytecodeTypeMapOffset_); 1.345 + } 1.346 +}; 1.347 + 1.348 +inline bool 1.349 +IsBaselineEnabled(JSContext *cx) 1.350 +{ 1.351 + return cx->runtime()->options().baseline(); 1.352 +} 1.353 + 1.354 +MethodStatus 1.355 +CanEnterBaselineMethod(JSContext *cx, RunState &state); 1.356 + 1.357 +MethodStatus 1.358 +CanEnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, bool newType); 1.359 + 1.360 +IonExecStatus 1.361 +EnterBaselineMethod(JSContext *cx, RunState &state); 1.362 + 1.363 +IonExecStatus 1.364 +EnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc); 1.365 + 1.366 +void 1.367 +FinishDiscardBaselineScript(FreeOp *fop, JSScript *script); 1.368 + 1.369 +void 1.370 +AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size_t *data, 1.371 + size_t *fallbackStubs); 1.372 + 1.373 +void 1.374 +ToggleBaselineSPS(JSRuntime *runtime, bool enable); 1.375 + 1.376 +struct BaselineBailoutInfo 1.377 +{ 1.378 + // Pointer into the current C stack, where overwriting will start. 1.379 + uint8_t *incomingStack; 1.380 + 1.381 + // The top and bottom heapspace addresses of the reconstructed stack 1.382 + // which will be copied to the bottom. 1.383 + uint8_t *copyStackTop; 1.384 + uint8_t *copyStackBottom; 1.385 + 1.386 + // Fields to store the top-of-stack baseline values that are held 1.387 + // in registers. The setR0 and setR1 fields are flags indicating 1.388 + // whether each one is initialized. 1.389 + uint32_t setR0; 1.390 + Value valueR0; 1.391 + uint32_t setR1; 1.392 + Value valueR1; 1.393 + 1.394 + // The value of the frame pointer register on resume. 1.395 + void *resumeFramePtr; 1.396 + 1.397 + // The native code address to resume into. 1.398 + void *resumeAddr; 1.399 + 1.400 + // If resuming into a TypeMonitor IC chain, this field holds the 1.401 + // address of the first stub in that chain. If this field is 1.402 + // set, then the actual jitcode resumed into is the jitcode for 1.403 + // the first stub, not the resumeAddr above. The resumeAddr 1.404 + // above, in this case, is pushed onto the stack so that the 1.405 + // TypeMonitor chain can tail-return into the main jitcode when done. 1.406 + ICStub *monitorStub; 1.407 + 1.408 + // Number of baseline frames to push on the stack. 1.409 + uint32_t numFrames; 1.410 + 1.411 + // The bailout kind. 1.412 + BailoutKind bailoutKind; 1.413 +}; 1.414 + 1.415 +uint32_t 1.416 +BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter, 1.417 + bool invalidate, BaselineBailoutInfo **bailoutInfo, 1.418 + const ExceptionBailoutInfo *exceptionInfo = nullptr); 1.419 + 1.420 +// Mark baseline scripts on the stack as active, so that they are not discarded 1.421 +// during GC. 1.422 +void 1.423 +MarkActiveBaselineScripts(Zone *zone); 1.424 + 1.425 +MethodStatus 1.426 +BaselineCompile(JSContext *cx, JSScript *script); 1.427 + 1.428 +} // namespace jit 1.429 +} // namespace js 1.430 + 1.431 +#endif // JS_ION 1.432 + 1.433 +#endif /* jit_BaselineJIT_h */