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/. */
7 #include "frontend/BytecodeSection.h"
9 #include "mozilla/Assertions.h" // MOZ_ASSERT
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
23 using namespace js::frontend
;
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());
29 if (!vector
.emplaceBack(funbox
->index())) {
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
);
42 return AbstractScopePtr(compilationState
, elem
.toScope());
45 mozilla::Maybe
<ScopeIndex
> GCThingList::getScopeIndex(size_t index
) const {
46 const TaggedScriptThingIndex
& elem
= vector
[index
];
47 if (elem
.isEmptyGlobalScope()) {
48 return mozilla::Nothing();
50 return mozilla::Some(vector
[index
].toScope());
53 TaggedParserAtomIndex
GCThingList::getAtom(size_t index
) const {
54 const TaggedScriptThingIndex
& elem
= vector
[index
];
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());
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());
73 output
[i
] = JS::GCCellPtr(str
);
76 case TaggedScriptThingIndex::Kind::Null
:
77 output
[i
] = JS::GCCellPtr(nullptr);
79 case TaggedScriptThingIndex::Kind::BigInt
: {
80 const BigIntStencil
& data
= stencil
.bigIntData
[thing
.toBigInt()];
81 BigInt
* bi
= data
.createBigInt(cx
);
85 output
[i
] = JS::GCCellPtr(bi
);
88 case TaggedScriptThingIndex::Kind::ObjLiteral
: {
89 const ObjLiteralStencil
& data
=
90 stencil
.objLiteralData
[thing
.toObjLiteral()];
91 JS::GCCellPtr ptr
= data
.create(cx
, atomCache
);
98 case TaggedScriptThingIndex::Kind::RegExp
: {
99 RegExpStencil
& data
= stencil
.regExpData
[thing
.toRegExp()];
100 RegExpObject
* regexp
= data
.createRegExp(cx
, atomCache
);
104 output
[i
] = JS::GCCellPtr(regexp
);
107 case TaggedScriptThingIndex::Kind::Scope
:
108 output
[i
] = JS::GCCellPtr(gcOutput
.getScope(thing
.toScope()));
110 case TaggedScriptThingIndex::Kind::Function
:
111 output
[i
] = JS::GCCellPtr(gcOutput
.getFunction(thing
.toFunction()));
113 case TaggedScriptThingIndex::Kind::EmptyGlobalScope
: {
114 Scope
* scope
= &cx
->global()->emptyGlobalScope();
115 output
[i
] = JS::GCCellPtr(scope
);
124 bool CGTryNoteList::append(TryNoteKind kind
, uint32_t stackDepth
,
125 BytecodeOffset start
, BytecodeOffset end
) {
126 MOZ_ASSERT(start
<= end
);
128 // Offsets are given relative to sections, but we only expect main-section
129 // to have TryNotes. In finish() we will fixup base offset.
131 TryNote
note(uint32_t(kind
), stackDepth
, start
.toUint32(),
132 (end
- start
).toUint32());
134 return list
.append(note
);
137 bool CGScopeNoteList::append(GCThingIndex scopeIndex
, BytecodeOffset offset
,
140 note
.index
= scopeIndex
;
141 note
.start
= offset
.toUint32();
143 note
.parent
= parent
;
145 return list
.append(note
);
148 void CGScopeNoteList::recordEnd(uint32_t index
, BytecodeOffset offset
) {
149 recordEndImpl(index
, offset
.toUint32());
152 void CGScopeNoteList::recordEndFunctionBodyVar(uint32_t index
) {
153 recordEndImpl(index
, UINT32_MAX
);
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
;
163 BytecodeSection::BytecodeSection(FrontendContext
* fc
, uint32_t lineNum
,
164 JS::LimitedColumnNumberOneOrigin column
)
170 resumeOffsetList_(fc
),
171 currentLine_(lineNum
),
172 lastColumn_(column
) {}
174 void BytecodeSection::updateDepth(JSOp op
, BytecodeOffset target
) {
175 jsbytecode
* pc
= code(target
);
177 int nuses
= StackUses(op
, pc
);
178 int ndefs
= StackDefs(op
);
180 stackDepth_
-= nuses
;
181 MOZ_ASSERT(stackDepth_
>= 0);
182 stackDepth_
+= ndefs
;
184 if (uint32_t(stackDepth_
) > maxStackDepth_
) {
185 maxStackDepth_
= stackDepth_
;
189 PerScriptData::PerScriptData(FrontendContext
* fc
,
190 frontend::CompilationState
& compilationState
)
191 : gcThingList_(fc
, compilationState
),
192 atomIndices_(fc
->nameCollectionPool()) {}
194 bool PerScriptData::init(FrontendContext
* fc
) {
195 return atomIndices_
.acquire(fc
);