]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved. |
9dae56ea | 3 | * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> |
93a37866 | 4 | * Copyright (C) 2012 Igalia, S.L. |
9dae56ea A |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
81345200 | 15 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
9dae56ea A |
16 | * its contributors may be used to endorse or promote products derived |
17 | * from this software without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
22 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | |
30 | ||
31 | #ifndef BytecodeGenerator_h | |
32 | #define BytecodeGenerator_h | |
33 | ||
34 | #include "CodeBlock.h" | |
6fe7ccc8 | 35 | #include <wtf/HashTraits.h> |
9dae56ea A |
36 | #include "Instruction.h" |
37 | #include "Label.h" | |
38 | #include "LabelScope.h" | |
39 | #include "Interpreter.h" | |
93a37866 | 40 | #include "ParserError.h" |
9dae56ea | 41 | #include "RegisterID.h" |
9dae56ea A |
42 | #include "SymbolTable.h" |
43 | #include "Debugger.h" | |
44 | #include "Nodes.h" | |
93a37866 | 45 | #include "StaticPropertyAnalyzer.h" |
ed1e77d3 | 46 | #include "TemplateRegistryKey.h" |
93a37866 | 47 | #include "UnlinkedCodeBlock.h" |
81345200 A |
48 | |
49 | #include <functional> | |
50 | ||
9dae56ea | 51 | #include <wtf/PassRefPtr.h> |
ba379fdc | 52 | #include <wtf/SegmentedVector.h> |
9dae56ea A |
53 | #include <wtf/Vector.h> |
54 | ||
81345200 | 55 | |
9dae56ea A |
56 | namespace JSC { |
57 | ||
58 | class Identifier; | |
ed1e77d3 | 59 | class JSTemplateRegistryKey; |
93a37866 A |
60 | |
61 | enum ExpectedFunction { | |
62 | NoExpectedFunction, | |
63 | ExpectObjectConstructor, | |
64 | ExpectArrayConstructor | |
65 | }; | |
14957cd0 A |
66 | |
67 | class CallArguments { | |
68 | public: | |
81345200 | 69 | CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0); |
14957cd0 A |
70 | |
71 | RegisterID* thisRegister() { return m_argv[0].get(); } | |
72 | RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } | |
81345200 A |
73 | unsigned stackOffset() { return -m_argv[0]->index() + JSStack::CallFrameHeaderSize; } |
74 | unsigned argumentCountIncludingThis() { return m_argv.size() - m_padding; } | |
14957cd0 A |
75 | RegisterID* profileHookRegister() { return m_profileHookRegister.get(); } |
76 | ArgumentsNode* argumentsNode() { return m_argumentsNode; } | |
77 | ||
78 | private: | |
79 | RefPtr<RegisterID> m_profileHookRegister; | |
80 | ArgumentsNode* m_argumentsNode; | |
93a37866 | 81 | Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_argv; |
81345200 | 82 | unsigned m_padding; |
14957cd0 | 83 | }; |
9dae56ea A |
84 | |
85 | struct FinallyContext { | |
6fe7ccc8 | 86 | StatementNode* finallyBlock; |
ed1e77d3 A |
87 | RegisterID* iterator; |
88 | ThrowableExpressionData* enumerationNode; | |
6fe7ccc8 A |
89 | unsigned scopeContextStackSize; |
90 | unsigned switchContextStackSize; | |
91 | unsigned forInContextStackSize; | |
93a37866 | 92 | unsigned tryContextStackSize; |
6fe7ccc8 A |
93 | unsigned labelScopesSize; |
94 | int finallyDepth; | |
95 | int dynamicScopeDepth; | |
9dae56ea A |
96 | }; |
97 | ||
98 | struct ControlFlowContext { | |
99 | bool isFinallyBlock; | |
100 | FinallyContext finallyContext; | |
101 | }; | |
102 | ||
ed1e77d3 A |
103 | class ForInContext { |
104 | public: | |
105 | ForInContext(RegisterID* localRegister) | |
106 | : m_localRegister(localRegister) | |
107 | , m_isValid(true) | |
108 | { | |
109 | } | |
110 | ||
111 | virtual ~ForInContext() | |
112 | { | |
113 | } | |
114 | ||
115 | bool isValid() const { return m_isValid; } | |
116 | void invalidate() { m_isValid = false; } | |
117 | ||
118 | enum ForInContextType { | |
119 | StructureForInContextType, | |
120 | IndexedForInContextType | |
121 | }; | |
122 | virtual ForInContextType type() const = 0; | |
123 | ||
124 | RegisterID* local() const { return m_localRegister.get(); } | |
125 | ||
126 | private: | |
127 | RefPtr<RegisterID> m_localRegister; | |
128 | bool m_isValid; | |
129 | }; | |
130 | ||
131 | class StructureForInContext : public ForInContext { | |
132 | public: | |
133 | StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister) | |
134 | : ForInContext(localRegister) | |
135 | , m_indexRegister(indexRegister) | |
136 | , m_propertyRegister(propertyRegister) | |
137 | , m_enumeratorRegister(enumeratorRegister) | |
138 | { | |
139 | } | |
140 | ||
141 | virtual ForInContextType type() const | |
142 | { | |
143 | return StructureForInContextType; | |
144 | } | |
145 | ||
146 | RegisterID* index() const { return m_indexRegister.get(); } | |
147 | RegisterID* property() const { return m_propertyRegister.get(); } | |
148 | RegisterID* enumerator() const { return m_enumeratorRegister.get(); } | |
149 | ||
150 | private: | |
151 | RefPtr<RegisterID> m_indexRegister; | |
152 | RefPtr<RegisterID> m_propertyRegister; | |
153 | RefPtr<RegisterID> m_enumeratorRegister; | |
154 | }; | |
155 | ||
156 | class IndexedForInContext : public ForInContext { | |
157 | public: | |
158 | IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister) | |
159 | : ForInContext(localRegister) | |
160 | , m_indexRegister(indexRegister) | |
161 | { | |
162 | } | |
163 | ||
164 | virtual ForInContextType type() const | |
165 | { | |
166 | return IndexedForInContextType; | |
167 | } | |
168 | ||
169 | RegisterID* index() const { return m_indexRegister.get(); } | |
170 | ||
171 | private: | |
172 | RefPtr<RegisterID> m_indexRegister; | |
f9bf01c6 A |
173 | }; |
174 | ||
93a37866 A |
175 | struct TryData { |
176 | RefPtr<Label> target; | |
177 | unsigned targetScopeDepth; | |
ed1e77d3 | 178 | HandlerType handlerType; |
93a37866 A |
179 | }; |
180 | ||
181 | struct TryContext { | |
182 | RefPtr<Label> start; | |
183 | TryData* tryData; | |
184 | }; | |
185 | ||
ed1e77d3 | 186 | class Variable { |
93a37866 | 187 | public: |
ed1e77d3 A |
188 | enum VariableKind { NormalVariable, SpecialVariable }; |
189 | ||
190 | Variable() | |
191 | : m_offset() | |
192 | , m_local(nullptr) | |
193 | , m_attributes(0) | |
194 | , m_kind(NormalVariable) | |
195 | { | |
196 | } | |
197 | ||
198 | Variable(const Identifier& ident) | |
199 | : m_ident(ident) | |
200 | , m_local(nullptr) | |
81345200 | 201 | , m_attributes(0) |
ed1e77d3 | 202 | , m_kind(NormalVariable) // This is somewhat meaningless here for this kind of Variable. |
93a37866 | 203 | { |
93a37866 | 204 | } |
81345200 | 205 | |
ed1e77d3 A |
206 | Variable(const Identifier& ident, VarOffset offset, RegisterID* local, unsigned attributes, VariableKind kind) |
207 | : m_ident(ident) | |
208 | , m_offset(offset) | |
209 | , m_local(local) | |
81345200 | 210 | , m_attributes(attributes) |
ed1e77d3 | 211 | , m_kind(kind) |
93a37866 | 212 | { |
93a37866 | 213 | } |
93a37866 | 214 | |
ed1e77d3 A |
215 | // If it's unset, then it is a non-locally-scoped variable. If it is set, then it could be |
216 | // a stack variable, a scoped variable in the local scope, or a variable captured in the | |
217 | // direct arguments object. | |
218 | bool isResolved() const { return !!m_offset; } | |
219 | ||
220 | const Identifier& ident() const { return m_ident; } | |
81345200 | 221 | |
ed1e77d3 A |
222 | VarOffset offset() const { return m_offset; } |
223 | bool isLocal() const { return m_offset.isStack(); } | |
224 | RegisterID* local() const { return m_local; } | |
225 | ||
226 | bool isReadOnly() const { return m_attributes & ReadOnly; } | |
227 | bool isSpecial() const { return m_kind != NormalVariable; } | |
93a37866 A |
228 | |
229 | private: | |
ed1e77d3 A |
230 | Identifier m_ident; |
231 | VarOffset m_offset; | |
81345200 A |
232 | RegisterID* m_local; |
233 | unsigned m_attributes; | |
ed1e77d3 | 234 | VariableKind m_kind; |
93a37866 A |
235 | }; |
236 | ||
81345200 A |
237 | struct TryRange { |
238 | RefPtr<Label> start; | |
239 | RefPtr<Label> end; | |
240 | TryData* tryData; | |
93a37866 A |
241 | }; |
242 | ||
ed1e77d3 A |
243 | enum ProfileTypeBytecodeFlag { |
244 | ProfileTypeBytecodePutToScope, | |
245 | ProfileTypeBytecodeGetFromScope, | |
246 | ProfileTypeBytecodePutToLocalScope, | |
247 | ProfileTypeBytecodeGetFromLocalScope, | |
248 | ProfileTypeBytecodeHasGlobalID, | |
249 | ProfileTypeBytecodeDoesNotHaveGlobalID, | |
250 | ProfileTypeBytecodeFunctionArgument, | |
251 | ProfileTypeBytecodeFunctionReturnStatement | |
252 | }; | |
253 | ||
14957cd0 A |
254 | class BytecodeGenerator { |
255 | WTF_MAKE_FAST_ALLOCATED; | |
ed1e77d3 | 256 | WTF_MAKE_NONCOPYABLE(BytecodeGenerator); |
9dae56ea A |
257 | public: |
258 | typedef DeclarationStacks::VarStack VarStack; | |
259 | typedef DeclarationStacks::FunctionStack FunctionStack; | |
260 | ||
81345200 | 261 | BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode); |
ed1e77d3 | 262 | BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); |
81345200 | 263 | BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode); |
9dae56ea | 264 | |
6fe7ccc8 A |
265 | ~BytecodeGenerator(); |
266 | ||
93a37866 | 267 | VM* vm() const { return m_vm; } |
ed1e77d3 | 268 | ParserArena& parserArena() const { return m_scopeNode->parserArena(); } |
93a37866 | 269 | const CommonIdentifiers& propertyNames() const { return *m_vm->propertyNames; } |
9dae56ea | 270 | |
ed1e77d3 A |
271 | bool isConstructor() const { return m_codeBlock->isConstructor(); } |
272 | #if ENABLE(ES6_CLASS_SYNTAX) | |
273 | ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); } | |
274 | #else | |
275 | ConstructorKind constructorKind() const { return ConstructorKind::None; } | |
276 | #endif | |
14957cd0 | 277 | |
93a37866 | 278 | ParserError generate(); |
14957cd0 | 279 | |
6fe7ccc8 | 280 | bool isArgumentNumber(const Identifier&, int); |
14957cd0 | 281 | |
ed1e77d3 A |
282 | Variable variable(const Identifier&); |
283 | ||
284 | // Ignores the possibility of intervening scopes. | |
285 | Variable variablePerSymbolTable(const Identifier&); | |
286 | ||
287 | enum ExistingVariableMode { VerifyExisting, IgnoreExisting }; | |
288 | void createVariable(const Identifier&, VarKind, ConstantMode, ExistingVariableMode = VerifyExisting); // Creates the variable, or asserts that the already-created variable is sufficiently compatible. | |
81345200 | 289 | |
9dae56ea A |
290 | // Returns the register storing "this" |
291 | RegisterID* thisRegister() { return &m_thisRegister; } | |
ed1e77d3 A |
292 | RegisterID* argumentsRegister() { return m_argumentsRegister; } |
293 | RegisterID* newTarget() { return m_newTargetRegister; } | |
294 | ||
295 | RegisterID* scopeRegister() { return m_scopeRegister; } | |
9dae56ea | 296 | |
9dae56ea A |
297 | // Returns the next available temporary register. Registers returned by |
298 | // newTemporary require a modified form of reference counting: any | |
299 | // register with a refcount of 0 is considered "available", meaning that | |
300 | // the next instruction may overwrite it. | |
301 | RegisterID* newTemporary(); | |
302 | ||
9dae56ea A |
303 | // The same as newTemporary(), but this function returns "suggestion" if |
304 | // "suggestion" is a temporary. This function is helpful in situations | |
305 | // where you've put "suggestion" in a RefPtr, but you'd like to allow | |
306 | // the next instruction to overwrite it anyway. | |
307 | RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } | |
308 | ||
309 | // Functions for handling of dst register | |
310 | ||
311 | RegisterID* ignoredResult() { return &m_ignoredResultRegister; } | |
312 | ||
313 | // Returns a place to write intermediate values of an operation | |
314 | // which reuses dst if it is safe to do so. | |
315 | RegisterID* tempDestination(RegisterID* dst) | |
316 | { | |
317 | return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); | |
318 | } | |
319 | ||
320 | // Returns the place to write the final output of an operation. | |
321 | RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) | |
322 | { | |
323 | if (originalDst && originalDst != ignoredResult()) | |
324 | return originalDst; | |
325 | ASSERT(tempDst != ignoredResult()); | |
326 | if (tempDst && tempDst->isTemporary()) | |
327 | return tempDst; | |
328 | return newTemporary(); | |
329 | } | |
330 | ||
331 | RegisterID* destinationForAssignResult(RegisterID* dst) | |
332 | { | |
333 | if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain()) | |
334 | return dst->isTemporary() ? dst : newTemporary(); | |
335 | return 0; | |
336 | } | |
337 | ||
338 | // Moves src to dst if dst is not null and is different from src, otherwise just returns src. | |
339 | RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) | |
340 | { | |
341 | return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; | |
342 | } | |
343 | ||
93a37866 | 344 | LabelScopePtr newLabelScope(LabelScope::Type, const Identifier* = 0); |
9dae56ea A |
345 | PassRefPtr<Label> newLabel(); |
346 | ||
93a37866 | 347 | void emitNode(RegisterID* dst, StatementNode* n) |
9dae56ea A |
348 | { |
349 | // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. | |
350 | ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); | |
81345200 | 351 | if (!m_vm->isSafeToRecurse()) { |
93a37866 A |
352 | emitThrowExpressionTooDeepException(); |
353 | return; | |
354 | } | |
355 | n->emitBytecode(*this, dst); | |
9dae56ea A |
356 | } |
357 | ||
93a37866 A |
358 | void emitNode(StatementNode* n) |
359 | { | |
360 | emitNode(0, n); | |
361 | } | |
362 | ||
363 | RegisterID* emitNode(RegisterID* dst, ExpressionNode* n) | |
364 | { | |
365 | // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. | |
366 | ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); | |
81345200 | 367 | if (!m_vm->isSafeToRecurse()) |
93a37866 A |
368 | return emitThrowExpressionTooDeepException(); |
369 | return n->emitBytecode(*this, dst); | |
370 | } | |
371 | ||
372 | RegisterID* emitNode(ExpressionNode* n) | |
9dae56ea A |
373 | { |
374 | return emitNode(0, n); | |
375 | } | |
376 | ||
93a37866 | 377 | void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 378 | { |
81345200 | 379 | if (!m_vm->isSafeToRecurse()) { |
f9bf01c6 | 380 | emitThrowExpressionTooDeepException(); |
93a37866 A |
381 | return; |
382 | } | |
383 | ||
384 | n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode); | |
f9bf01c6 A |
385 | } |
386 | ||
81345200 A |
387 | void emitExpressionInfo(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
388 | { | |
389 | ASSERT(divot.offset >= divotStart.offset); | |
390 | ASSERT(divotEnd.offset >= divot.offset); | |
391 | ||
93a37866 A |
392 | int sourceOffset = m_scopeNode->source().startOffset(); |
393 | unsigned firstLine = m_scopeNode->source().firstLine(); | |
14957cd0 | 394 | |
81345200 A |
395 | int divotOffset = divot.offset - sourceOffset; |
396 | int startOffset = divot.offset - divotStart.offset; | |
397 | int endOffset = divotEnd.offset - divot.offset; | |
93a37866 | 398 | |
81345200 A |
399 | unsigned line = divot.line; |
400 | ASSERT(line >= firstLine); | |
401 | line -= firstLine; | |
402 | ||
403 | int lineStart = divot.lineStartOffset; | |
93a37866 A |
404 | if (lineStart > sourceOffset) |
405 | lineStart -= sourceOffset; | |
406 | else | |
407 | lineStart = 0; | |
408 | ||
81345200 A |
409 | if (divotOffset < lineStart) |
410 | return; | |
411 | ||
412 | unsigned column = divotOffset - lineStart; | |
93a37866 A |
413 | |
414 | unsigned instructionOffset = instructions().size(); | |
81345200 A |
415 | if (!m_isBuiltinFunction) |
416 | m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column); | |
9dae56ea A |
417 | } |
418 | ||
ed1e77d3 | 419 | |
9dae56ea A |
420 | ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) |
421 | { | |
422 | return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; | |
423 | } | |
424 | ||
425 | ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) | |
426 | { | |
427 | if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { | |
428 | PassRefPtr<RegisterID> dst = newTemporary(); | |
429 | emitNode(dst.get(), n); | |
430 | return dst; | |
431 | } | |
432 | ||
6fe7ccc8 | 433 | return emitNode(n); |
9dae56ea A |
434 | } |
435 | ||
ed1e77d3 A |
436 | void emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot); |
437 | void emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag, const Identifier*); | |
438 | ||
439 | void emitProfileControlFlow(int); | |
440 | ||
9dae56ea | 441 | RegisterID* emitLoad(RegisterID* dst, bool); |
9dae56ea | 442 | RegisterID* emitLoad(RegisterID* dst, const Identifier&); |
ed1e77d3 | 443 | RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); |
93a37866 | 444 | RegisterID* emitLoadGlobalObject(RegisterID* dst); |
9dae56ea A |
445 | |
446 | RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); | |
447 | RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); | |
448 | RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2); | |
449 | RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src); | |
450 | ||
93a37866 | 451 | RegisterID* emitCreateThis(RegisterID* dst); |
ed1e77d3 | 452 | void emitTDZCheck(RegisterID* target); |
9dae56ea | 453 | RegisterID* emitNewObject(RegisterID* dst); |
14957cd0 | 454 | RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision |
9dae56ea | 455 | |
ed1e77d3 A |
456 | RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode*); |
457 | RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index); | |
9dae56ea | 458 | RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); |
ed1e77d3 | 459 | RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name); |
14957cd0 | 460 | RegisterID* emitNewRegExp(RegisterID* dst, RegExp*); |
9dae56ea | 461 | |
ed1e77d3 A |
462 | RegisterID* emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant); |
463 | RegisterID* emitMoveEmptyValue(RegisterID* dst); | |
9dae56ea A |
464 | RegisterID* emitMove(RegisterID* dst, RegisterID* src); |
465 | ||
93a37866 | 466 | RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); } |
ed1e77d3 | 467 | RegisterID* emitToString(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_string, dst, src); } |
93a37866 A |
468 | RegisterID* emitInc(RegisterID* srcDst); |
469 | RegisterID* emitDec(RegisterID* srcDst); | |
9dae56ea | 470 | |
93a37866 A |
471 | void emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target); |
472 | RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype); | |
9dae56ea A |
473 | RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } |
474 | RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } | |
475 | ||
93a37866 | 476 | RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value); |
9dae56ea | 477 | |
9dae56ea A |
478 | RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); |
479 | RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); | |
ed1e77d3 | 480 | RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType); |
9dae56ea A |
481 | RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); |
482 | RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); | |
14957cd0 | 483 | RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property); |
9dae56ea | 484 | RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); |
81345200 | 485 | RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); |
9dae56ea A |
486 | RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); |
487 | RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); | |
ed1e77d3 A |
488 | |
489 | void emitPutGetterById(RegisterID* base, const Identifier& property, RegisterID* getter); | |
490 | void emitPutSetterById(RegisterID* base, const Identifier& property, RegisterID* setter); | |
6fe7ccc8 | 491 | void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter); |
93a37866 A |
492 | |
493 | ExpectedFunction expectedFunctionForIdentifier(const Identifier&); | |
81345200 A |
494 | RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
495 | RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); | |
496 | RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); | |
9dae56ea | 497 | |
ed1e77d3 A |
498 | enum PropertyDescriptorOption { |
499 | PropertyConfigurable = 1, | |
500 | PropertyWritable = 1 << 1, | |
501 | PropertyEnumerable = 1 << 2, | |
502 | }; | |
503 | void emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister, | |
504 | RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition&); | |
505 | ||
81345200 | 506 | void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack); |
ed1e77d3 A |
507 | |
508 | #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) | |
509 | RegisterID* emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode*); | |
510 | #endif | |
511 | ||
9dae56ea A |
512 | RegisterID* emitReturn(RegisterID* src); |
513 | RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); } | |
514 | ||
81345200 | 515 | RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
ba379fdc A |
516 | RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count); |
517 | void emitToPrimitive(RegisterID* dst, RegisterID* src); | |
9dae56ea | 518 | |
81345200 | 519 | ResolveType resolveType(); |
ed1e77d3 A |
520 | RegisterID* emitResolveConstantLocal(RegisterID* dst, const Variable&); |
521 | RegisterID* emitResolveScope(RegisterID* dst, const Variable&); | |
522 | RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Variable&, ResolveMode); | |
523 | RegisterID* emitPutToScope(RegisterID* scope, const Variable&, RegisterID* value, ResolveMode); | |
524 | RegisterID* initializeVariable(const Variable&, RegisterID* value); | |
81345200 | 525 | |
9dae56ea | 526 | PassRefPtr<Label> emitLabel(Label*); |
6fe7ccc8 | 527 | void emitLoopHint(); |
9dae56ea A |
528 | PassRefPtr<Label> emitJump(Label* target); |
529 | PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target); | |
530 | PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target); | |
ba379fdc A |
531 | PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target); |
532 | PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target); | |
ed1e77d3 | 533 | void emitPopScopes(RegisterID* srcDst, int targetScopeDepth); |
9dae56ea | 534 | |
ed1e77d3 A |
535 | RegisterID* emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName); |
536 | RegisterID* emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator); | |
537 | RegisterID* emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName); | |
538 | RegisterID* emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base); | |
539 | RegisterID* emitGetEnumerableLength(RegisterID* dst, RegisterID* base); | |
540 | RegisterID* emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length); | |
541 | RegisterID* emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator); | |
542 | RegisterID* emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index); | |
543 | RegisterID* emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index); | |
544 | RegisterID* emitToIndexString(RegisterID* dst, RegisterID* index); | |
545 | ||
546 | RegisterID* emitIsObject(RegisterID* dst, RegisterID* src); | |
547 | RegisterID* emitIsUndefined(RegisterID* dst, RegisterID* src); | |
548 | ||
549 | RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node); | |
550 | void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node); | |
9dae56ea | 551 | |
93a37866 A |
552 | void emitReadOnlyExceptionIfNeeded(); |
553 | ||
554 | // Start a try block. 'start' must have been emitted. | |
555 | TryData* pushTry(Label* start); | |
556 | // End a try block. 'end' must have been emitted. | |
ed1e77d3 | 557 | void popTryAndEmitCatch(TryData*, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType); |
93a37866 | 558 | |
14957cd0 A |
559 | void emitThrow(RegisterID* exc) |
560 | { | |
561 | m_usesExceptions = true; | |
562 | emitUnaryNoDstOp(op_throw, exc); | |
563 | } | |
564 | ||
93a37866 | 565 | void emitThrowReferenceError(const String& message); |
ed1e77d3 | 566 | void emitThrowTypeError(const String& message); |
14957cd0 | 567 | |
ed1e77d3 A |
568 | void emitPushFunctionNameScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes); |
569 | void emitPushCatchScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes); | |
9dae56ea | 570 | |
ed1e77d3 A |
571 | void emitGetScope(); |
572 | RegisterID* emitPushWithScope(RegisterID* dst, RegisterID* scope); | |
573 | void emitPopScope(RegisterID* srcDst); | |
9dae56ea | 574 | |
81345200 | 575 | void emitDebugHook(DebugHookID, unsigned line, unsigned charOffset, unsigned lineStart); |
9dae56ea | 576 | |
81345200 | 577 | int scopeDepth() { return m_localScopeDepth + m_finallyDepth; } |
9dae56ea A |
578 | bool hasFinaliser() { return m_finallyDepth != 0; } |
579 | ||
6fe7ccc8 | 580 | void pushFinallyContext(StatementNode* finallyBlock); |
9dae56ea | 581 | void popFinallyContext(); |
ed1e77d3 A |
582 | void pushIteratorCloseContext(RegisterID* iterator, ThrowableExpressionData* enumerationNode); |
583 | void popIteratorCloseContext(); | |
9dae56ea | 584 | |
ed1e77d3 A |
585 | void pushIndexedForInScope(RegisterID* local, RegisterID* index); |
586 | void popIndexedForInScope(RegisterID* local); | |
587 | void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator); | |
588 | void popStructureForInScope(RegisterID* local); | |
589 | void invalidateForInContextForLocal(RegisterID* local); | |
f9bf01c6 | 590 | |
81345200 A |
591 | LabelScopePtr breakTarget(const Identifier&); |
592 | LabelScopePtr continueTarget(const Identifier&); | |
9dae56ea A |
593 | |
594 | void beginSwitch(RegisterID*, SwitchInfo::SwitchType); | |
595 | void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range); | |
596 | ||
597 | CodeType codeType() const { return m_codeType; } | |
598 | ||
14957cd0 | 599 | bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; } |
93a37866 | 600 | bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; } |
14957cd0 A |
601 | |
602 | bool isStrictMode() const { return m_codeBlock->isStrictMode(); } | |
81345200 A |
603 | |
604 | bool isBuiltinFunction() const { return m_isBuiltinFunction; } | |
ed1e77d3 A |
605 | |
606 | OpcodeID lastOpcodeID() const { return m_lastOpcodeID; } | |
607 | ||
9dae56ea | 608 | private: |
ed1e77d3 A |
609 | Variable variableForLocalEntry(const Identifier&, const SymbolTableEntry&); |
610 | ||
9dae56ea | 611 | void emitOpcode(OpcodeID); |
93a37866 A |
612 | UnlinkedArrayAllocationProfile newArrayAllocationProfile(); |
613 | UnlinkedObjectAllocationProfile newObjectAllocationProfile(); | |
614 | UnlinkedArrayProfile newArrayProfile(); | |
615 | UnlinkedValueProfile emitProfiledOpcode(OpcodeID); | |
616 | int kill(RegisterID* dst) | |
617 | { | |
618 | int index = dst->index(); | |
619 | m_staticPropertyAnalyzer.kill(index); | |
620 | return index; | |
621 | } | |
622 | ||
9dae56ea A |
623 | void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); |
624 | void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); | |
4e4e5a6f A |
625 | ALWAYS_INLINE void rewindBinaryOp(); |
626 | ALWAYS_INLINE void rewindUnaryOp(); | |
9dae56ea | 627 | |
ed1e77d3 A |
628 | void allocateAndEmitScope(); |
629 | void emitComplexPopScopes(RegisterID*, ControlFlowContext* topScope, ControlFlowContext* bottomScope); | |
9dae56ea | 630 | |
ba379fdc | 631 | typedef HashMap<double, JSValue> NumberMap; |
ed1e77d3 A |
632 | typedef HashMap<UniquedStringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; |
633 | typedef HashMap<TemplateRegistryKey, JSTemplateRegistryKey*> TemplateRegistryKeyMap; | |
93a37866 A |
634 | |
635 | // Helper for emitCall() and emitConstruct(). This works because the set of | |
636 | // expected functions have identical behavior for both call and construct | |
637 | // (i.e. "Object()" is identical to "new Object()"). | |
638 | ExpectedFunction emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, Label* done); | |
9dae56ea | 639 | |
81345200 | 640 | RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
14957cd0 | 641 | |
9dae56ea A |
642 | RegisterID* newRegister(); |
643 | ||
ed1e77d3 | 644 | // Adds an anonymous local var slot. To give this slot a name, add it to symbolTable(). |
14957cd0 A |
645 | RegisterID* addVar() |
646 | { | |
647 | ++m_codeBlock->m_numVars; | |
ed1e77d3 A |
648 | RegisterID* result = newRegister(); |
649 | ASSERT(VirtualRegister(result->index()).toLocal() == m_codeBlock->m_numVars - 1); | |
650 | result->ref(); // We should never free this slot. | |
651 | return result; | |
14957cd0 | 652 | } |
9dae56ea | 653 | |
ed1e77d3 A |
654 | // Initializes the stack form the parameter; does nothing for the symbol table. |
655 | RegisterID* initializeNextParameter(); | |
656 | UniquedStringImpl* visibleNameForParameter(DestructuringPatternNode*); | |
657 | ||
658 | RegisterID& registerFor(VirtualRegister reg) | |
9dae56ea | 659 | { |
ed1e77d3 A |
660 | if (reg.isLocal()) |
661 | return m_calleeRegisters[reg.toLocal()]; | |
9dae56ea | 662 | |
ed1e77d3 | 663 | if (reg.offset() == JSStack::Callee) |
93a37866 A |
664 | return m_calleeRegister; |
665 | ||
6fe7ccc8 | 666 | ASSERT(m_parameters.size()); |
ed1e77d3 | 667 | return m_parameters[reg.toArgument()]; |
9dae56ea A |
668 | } |
669 | ||
ed1e77d3 | 670 | bool hasConstant(const Identifier&) const; |
9dae56ea | 671 | unsigned addConstant(const Identifier&); |
ed1e77d3 | 672 | RegisterID* addConstantValue(JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); |
93a37866 | 673 | RegisterID* addConstantEmptyValue(); |
9dae56ea A |
674 | unsigned addRegExp(RegExp*); |
675 | ||
14957cd0 A |
676 | unsigned addConstantBuffer(unsigned length); |
677 | ||
93a37866 | 678 | UnlinkedFunctionExecutable* makeFunction(FunctionBodyNode* body) |
f9bf01c6 | 679 | { |
81345200 | 680 | return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction); |
f9bf01c6 A |
681 | } |
682 | ||
ed1e77d3 | 683 | RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
81345200 | 684 | RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
ed1e77d3 | 685 | |
93a37866 | 686 | public: |
14957cd0 | 687 | JSString* addStringConstant(const Identifier&); |
ed1e77d3 | 688 | JSTemplateRegistryKey* addTemplateRegistryKeyConstant(const TemplateRegistryKey&); |
14957cd0 | 689 | |
93a37866 | 690 | Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; } |
14957cd0 | 691 | |
81345200 | 692 | SymbolTable& symbolTable() { return *m_symbolTable; } |
9dae56ea | 693 | |
6fe7ccc8 A |
694 | bool shouldOptimizeLocals() |
695 | { | |
81345200 | 696 | if (m_codeType != FunctionCode) |
6fe7ccc8 A |
697 | return false; |
698 | ||
81345200 | 699 | if (m_localScopeDepth) |
6fe7ccc8 A |
700 | return false; |
701 | ||
702 | return true; | |
703 | } | |
704 | ||
705 | bool canOptimizeNonLocals() | |
706 | { | |
81345200 | 707 | if (m_localScopeDepth) |
6fe7ccc8 A |
708 | return false; |
709 | ||
710 | if (m_codeType == EvalCode) | |
711 | return false; | |
712 | ||
713 | if (m_codeType == FunctionCode && m_codeBlock->usesEval()) | |
714 | return false; | |
715 | ||
716 | return true; | |
717 | } | |
9dae56ea A |
718 | |
719 | RegisterID* emitThrowExpressionTooDeepException(); | |
720 | ||
ed1e77d3 | 721 | private: |
93a37866 | 722 | Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow> m_instructions; |
ba379fdc | 723 | |
9dae56ea A |
724 | bool m_shouldEmitDebugHooks; |
725 | bool m_shouldEmitProfileHooks; | |
726 | ||
ed1e77d3 | 727 | SymbolTable* m_symbolTable { nullptr }; |
9dae56ea | 728 | |
ed1e77d3 | 729 | ScopeNode* const m_scopeNode; |
93a37866 | 730 | Strong<UnlinkedCodeBlock> m_codeBlock; |
9dae56ea | 731 | |
ba379fdc A |
732 | // Some of these objects keep pointers to one another. They are arranged |
733 | // to ensure a sane destruction order that avoids references to freed memory. | |
ed1e77d3 | 734 | HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> m_functions; |
9dae56ea A |
735 | RegisterID m_ignoredResultRegister; |
736 | RegisterID m_thisRegister; | |
93a37866 | 737 | RegisterID m_calleeRegister; |
ed1e77d3 A |
738 | RegisterID* m_scopeRegister { nullptr }; |
739 | RegisterID* m_argumentsRegister { nullptr }; | |
740 | RegisterID* m_lexicalEnvironmentRegister { nullptr }; | |
741 | RegisterID* m_emptyValueRegister { nullptr }; | |
742 | RegisterID* m_globalObjectRegister { nullptr }; | |
743 | RegisterID* m_newTargetRegister { nullptr }; | |
744 | RegisterID* m_linkTimeConstantRegisters[LinkTimeConstantCount]; | |
745 | ||
f9bf01c6 A |
746 | SegmentedVector<RegisterID, 32> m_constantPoolRegisters; |
747 | SegmentedVector<RegisterID, 32> m_calleeRegisters; | |
748 | SegmentedVector<RegisterID, 32> m_parameters; | |
f9bf01c6 | 749 | SegmentedVector<Label, 32> m_labels; |
93a37866 | 750 | LabelScopeStore m_labelScopes; |
ed1e77d3 A |
751 | int m_finallyDepth { 0 }; |
752 | int m_localScopeDepth { 0 }; | |
753 | const CodeType m_codeType; | |
9dae56ea | 754 | |
93a37866 | 755 | Vector<ControlFlowContext, 0, UnsafeVectorOverflow> m_scopeContextStack; |
9dae56ea | 756 | Vector<SwitchInfo> m_switchContextStack; |
ed1e77d3 | 757 | Vector<std::unique_ptr<ForInContext>> m_forInContextStack; |
93a37866 | 758 | Vector<TryContext> m_tryContextStack; |
ed1e77d3 A |
759 | Vector<std::pair<RefPtr<RegisterID>, const DestructuringPatternNode*>> m_destructuringParameters; |
760 | enum FunctionVariableType : uint8_t { NormalFunctionVariable, GlobalFunctionVariable }; | |
761 | Vector<std::pair<FunctionBodyNode*, FunctionVariableType>> m_functionsToInitialize; | |
762 | bool m_needToInitializeArguments { false }; | |
93a37866 A |
763 | |
764 | Vector<TryRange> m_tryRanges; | |
765 | SegmentedVector<TryData, 8> m_tryData; | |
9dae56ea | 766 | |
ed1e77d3 | 767 | int m_nextConstantOffset { 0 }; |
9dae56ea | 768 | |
14957cd0 A |
769 | typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap; |
770 | FunctionOffsetMap m_functionOffsets; | |
771 | ||
9dae56ea A |
772 | // Constant pool |
773 | IdentifierMap m_identifierMap; | |
ed1e77d3 A |
774 | |
775 | typedef HashMap<EncodedJSValueWithRepresentation, unsigned, EncodedJSValueWithRepresentationHash, EncodedJSValueWithRepresentationHashTraits> JSValueMap; | |
9dae56ea | 776 | JSValueMap m_jsValueMap; |
9dae56ea | 777 | IdentifierStringMap m_stringMap; |
ed1e77d3 | 778 | TemplateRegistryKeyMap m_templateRegistryKeyMap; |
9dae56ea | 779 | |
ed1e77d3 | 780 | StaticPropertyAnalyzer m_staticPropertyAnalyzer { &m_instructions }; |
93a37866 A |
781 | |
782 | VM* m_vm; | |
9dae56ea | 783 | |
ed1e77d3 | 784 | OpcodeID m_lastOpcodeID = op_end; |
14957cd0 | 785 | #ifndef NDEBUG |
ed1e77d3 | 786 | size_t m_lastOpcodePosition { 0 }; |
14957cd0 | 787 | #endif |
9dae56ea | 788 | |
ed1e77d3 A |
789 | bool m_usesExceptions { false }; |
790 | bool m_expressionTooDeep { false }; | |
791 | bool m_isBuiltinFunction { false }; | |
b80e6193 | 792 | }; |
93a37866 | 793 | |
9dae56ea A |
794 | } |
795 | ||
796 | #endif // BytecodeGenerator_h |