1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef frontend_ForInEmitter_h 8 #define frontend_ForInEmitter_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Maybe.h" 12 13 #include <stdint.h> 14 15 #include "frontend/BytecodeControlStructures.h" 16 #include "frontend/TDZCheckCache.h" 17 18 namespace js { 19 namespace frontend { 20 21 struct BytecodeEmitter; 22 class EmitterScope; 23 24 // Class for emitting bytecode for for-in loop. 25 // 26 // Usage: (check for the return value is omitted for simplicity) 27 // 28 // `for (init in iterated) body` 29 // // headLexicalEmitterScope: lexical scope for init 30 // ForInEmitter forIn(this, headLexicalEmitterScope); 31 // forIn.emitIterated(); 32 // emit(iterated); 33 // forIn.emitInitialize(); 34 // emit(init); 35 // forIn.emitBody(); 36 // emit(body); 37 // forIn.emitEnd(Some(offset_of_for)); 38 // 39 class MOZ_STACK_CLASS ForInEmitter { 40 BytecodeEmitter* bce_; 41 42 #ifdef DEBUG 43 // The stack depth before emitting initialize code inside loop. 44 int32_t loopDepth_ = 0; 45 #endif 46 47 mozilla::Maybe<LoopControl> loopInfo_; 48 49 // The lexical scope to be freshened for each iteration. See the comment 50 // in `emitBody` for more details. Can be nullptr if there's no lexical 51 // scope. 52 const EmitterScope* headLexicalEmitterScope_; 53 54 // Cache for the iterated value. 55 // (The cache for the iteration body is inside `loopInfo_`) 56 // 57 // The iterated value needs its own TDZCheckCache, separated from both the 58 // enclosing block and the iteration body, in order to make the sanity check 59 // in Ion work properly. 60 // In term of the execution order, the TDZCheckCache for the iterated value 61 // dominates the one for the iteration body, that means the checks in the 62 // iteration body is dead, and we can optimize them away. But the sanity 63 // check in Ion doesn't know it's dead. 64 // (see bug 1368360 for more context) 65 mozilla::Maybe<TDZCheckCache> tdzCacheForIteratedValue_; 66 67 #ifdef DEBUG 68 // The state of this emitter. 69 // 70 // +-------+ emitIterated +----------+ emitInitialize +------------+ 71 // | Start |------------->| Iterated |--------------->| Initialize |-+ 72 // +-------+ +----------+ +------------+ | 73 // | 74 // +----------------------------------+ 75 // | 76 // | emitBody +------+ emitEnd +-----+ 77 // +----------| Body |--------->| End | 78 // +------+ +-----+ 79 enum class State { 80 // The initial state. 81 Start, 82 83 // After calling emitIterated. 84 Iterated, 85 86 // After calling emitInitialize. 87 Initialize, 88 89 // After calling emitBody. 90 Body, 91 92 // After calling emitEnd. 93 End 94 }; 95 State state_ = State::Start; 96 #endif 97 98 public: 99 ForInEmitter(BytecodeEmitter* bce, 100 const EmitterScope* headLexicalEmitterScope); 101 102 // Parameters are the offset in the source code for each character below: 103 // 104 // for ( var x in obj ) { ... } 105 // ^ 106 // | 107 // forPos 108 // 109 // Can be Nothing() if not available. 110 MOZ_MUST_USE bool emitIterated(); 111 MOZ_MUST_USE bool emitInitialize(); 112 MOZ_MUST_USE bool emitBody(); 113 MOZ_MUST_USE bool emitEnd(const mozilla::Maybe<uint32_t>& forPos); 114 }; 115 116 } /* namespace frontend */ 117 } /* namespace js */ 118 119 #endif /* frontend_ForInEmitter_h */ 120