BytecodeSection.cpp (6489B)
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 #include "frontend/BytecodeSection.h" 8 9 #include "mozilla/Assertions.h" // MOZ_ASSERT 10 11 #include "frontend/AbstractScopePtr.h" // ScopeIndex 12 #include "frontend/CompilationStencil.h" // CompilationStencil 13 #include "frontend/FrontendContext.h" // FrontendContext 14 #include "frontend/SharedContext.h" // FunctionBox 15 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin 16 #include "vm/BytecodeUtil.h" // INDEX_LIMIT, StackUses, StackDefs 17 #include "vm/GlobalObject.h" 18 #include "vm/JSContext.h" // JSContext 19 #include "vm/RegExpObject.h" // RegexpObject 20 #include "vm/Scope.h" // GlobalScope 21 22 using namespace js; 23 using namespace js::frontend; 24 25 bool GCThingList::append(FunctionBox* funbox, GCThingIndex* index) { 26 // Append the function to the vector and return the index in *index. 27 *index = GCThingIndex(vector.length()); 28 29 if (!vector.emplaceBack(funbox->index())) { 30 return false; 31 } 32 return true; 33 } 34 35 AbstractScopePtr GCThingList::getScope(size_t index) const { 36 const TaggedScriptThingIndex& elem = vector[index]; 37 if (elem.isEmptyGlobalScope()) { 38 // The empty enclosing scope should be stored by 39 // CompilationInput::initForSelfHostingGlobal. 40 return AbstractScopePtr::compilationEnclosingScope(compilationState); 41 } 42 return AbstractScopePtr(compilationState, elem.toScope()); 43 } 44 45 mozilla::Maybe<ScopeIndex> GCThingList::getScopeIndex(size_t index) const { 46 const TaggedScriptThingIndex& elem = vector[index]; 47 if (elem.isEmptyGlobalScope()) { 48 return mozilla::Nothing(); 49 } 50 return mozilla::Some(vector[index].toScope()); 51 } 52 53 TaggedParserAtomIndex GCThingList::getAtom(size_t index) const { 54 const TaggedScriptThingIndex& elem = vector[index]; 55 return elem.toAtom(); 56 } 57 58 bool js::frontend::EmitScriptThingsVector( 59 JSContext* cx, const CompilationAtomCache& atomCache, 60 const CompilationStencil& stencil, CompilationGCOutput& gcOutput, 61 mozilla::Span<const TaggedScriptThingIndex> things, 62 mozilla::Span<JS::GCCellPtr> output) { 63 MOZ_ASSERT(things.size() <= INDEX_LIMIT); 64 MOZ_ASSERT(things.size() == output.size()); 65 66 for (uint32_t i = 0; i < things.size(); i++) { 67 const auto& thing = things[i]; 68 switch (thing.tag()) { 69 case TaggedScriptThingIndex::Kind::ParserAtomIndex: 70 case TaggedScriptThingIndex::Kind::WellKnown: { 71 JSString* str = atomCache.getExistingStringAt(cx, thing.toAtom()); 72 MOZ_ASSERT(str); 73 output[i] = JS::GCCellPtr(str); 74 break; 75 } 76 case TaggedScriptThingIndex::Kind::Null: 77 output[i] = JS::GCCellPtr(nullptr); 78 break; 79 case TaggedScriptThingIndex::Kind::BigInt: { 80 const BigIntStencil& data = stencil.bigIntData[thing.toBigInt()]; 81 BigInt* bi = data.createBigInt(cx); 82 if (!bi) { 83 return false; 84 } 85 output[i] = JS::GCCellPtr(bi); 86 break; 87 } 88 case TaggedScriptThingIndex::Kind::ObjLiteral: { 89 const ObjLiteralStencil& data = 90 stencil.objLiteralData[thing.toObjLiteral()]; 91 JS::GCCellPtr ptr = data.create(cx, atomCache); 92 if (!ptr) { 93 return false; 94 } 95 output[i] = ptr; 96 break; 97 } 98 case TaggedScriptThingIndex::Kind::RegExp: { 99 RegExpStencil& data = stencil.regExpData[thing.toRegExp()]; 100 RegExpObject* regexp = data.createRegExp(cx, atomCache); 101 if (!regexp) { 102 return false; 103 } 104 output[i] = JS::GCCellPtr(regexp); 105 break; 106 } 107 case TaggedScriptThingIndex::Kind::Scope: 108 output[i] = JS::GCCellPtr(gcOutput.getScope(thing.toScope())); 109 break; 110 case TaggedScriptThingIndex::Kind::Function: 111 output[i] = JS::GCCellPtr(gcOutput.getFunction(thing.toFunction())); 112 break; 113 case TaggedScriptThingIndex::Kind::EmptyGlobalScope: { 114 Scope* scope = &cx->global()->emptyGlobalScope(); 115 output[i] = JS::GCCellPtr(scope); 116 break; 117 } 118 } 119 } 120 121 return true; 122 } 123 124 bool CGTryNoteList::append(TryNoteKind kind, uint32_t stackDepth, 125 BytecodeOffset start, BytecodeOffset end) { 126 MOZ_ASSERT(start <= end); 127 128 // Offsets are given relative to sections, but we only expect main-section 129 // to have TryNotes. In finish() we will fixup base offset. 130 131 TryNote note(uint32_t(kind), stackDepth, start.toUint32(), 132 (end - start).toUint32()); 133 134 return list.append(note); 135 } 136 137 bool CGScopeNoteList::append(GCThingIndex scopeIndex, BytecodeOffset offset, 138 uint32_t parent) { 139 ScopeNote note; 140 note.index = scopeIndex; 141 note.start = offset.toUint32(); 142 note.length = 0; 143 note.parent = parent; 144 145 return list.append(note); 146 } 147 148 void CGScopeNoteList::recordEnd(uint32_t index, BytecodeOffset offset) { 149 recordEndImpl(index, offset.toUint32()); 150 } 151 152 void CGScopeNoteList::recordEndFunctionBodyVar(uint32_t index) { 153 recordEndImpl(index, UINT32_MAX); 154 } 155 156 void CGScopeNoteList::recordEndImpl(uint32_t index, uint32_t offset) { 157 MOZ_ASSERT(index < length()); 158 MOZ_ASSERT(list[index].length == 0); 159 MOZ_ASSERT(offset >= list[index].start); 160 list[index].length = offset - list[index].start; 161 } 162 163 BytecodeSection::BytecodeSection(FrontendContext* fc, uint32_t lineNum, 164 JS::LimitedColumnNumberOneOrigin column) 165 : code_(fc), 166 notes_(fc), 167 lastNoteOffset_(0), 168 tryNoteList_(fc), 169 scopeNoteList_(fc), 170 resumeOffsetList_(fc), 171 currentLine_(lineNum), 172 lastColumn_(column) {} 173 174 void BytecodeSection::updateDepth(JSOp op, BytecodeOffset target) { 175 jsbytecode* pc = code(target); 176 177 int nuses = StackUses(op, pc); 178 int ndefs = StackDefs(op); 179 180 stackDepth_ -= nuses; 181 MOZ_ASSERT(stackDepth_ >= 0); 182 stackDepth_ += ndefs; 183 184 if (uint32_t(stackDepth_) > maxStackDepth_) { 185 maxStackDepth_ = stackDepth_; 186 } 187 } 188 189 PerScriptData::PerScriptData(FrontendContext* fc, 190 frontend::CompilationState& compilationState) 191 : gcThingList_(fc, compilationState), 192 atomIndices_(fc->nameCollectionPool()) {} 193 194 bool PerScriptData::init(FrontendContext* fc) { 195 return atomIndices_.acquire(fc); 196 }