]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
81345200 | 2 | * Copyright (C) 2008, 2009, 2012, 2013, 2014 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 A |
45 | #include "StaticPropertyAnalyzer.h" |
46 | #include "UnlinkedCodeBlock.h" | |
81345200 A |
47 | |
48 | #include <functional> | |
49 | ||
9dae56ea | 50 | #include <wtf/PassRefPtr.h> |
ba379fdc | 51 | #include <wtf/SegmentedVector.h> |
9dae56ea A |
52 | #include <wtf/Vector.h> |
53 | ||
81345200 | 54 | |
9dae56ea A |
55 | namespace JSC { |
56 | ||
57 | class Identifier; | |
6fe7ccc8 | 58 | class Label; |
93a37866 A |
59 | |
60 | enum ExpectedFunction { | |
61 | NoExpectedFunction, | |
62 | ExpectObjectConstructor, | |
63 | ExpectArrayConstructor | |
64 | }; | |
14957cd0 A |
65 | |
66 | class CallArguments { | |
67 | public: | |
81345200 | 68 | CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0); |
14957cd0 A |
69 | |
70 | RegisterID* thisRegister() { return m_argv[0].get(); } | |
71 | RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } | |
81345200 A |
72 | unsigned stackOffset() { return -m_argv[0]->index() + JSStack::CallFrameHeaderSize; } |
73 | unsigned argumentCountIncludingThis() { return m_argv.size() - m_padding; } | |
14957cd0 A |
74 | RegisterID* profileHookRegister() { return m_profileHookRegister.get(); } |
75 | ArgumentsNode* argumentsNode() { return m_argumentsNode; } | |
76 | ||
77 | private: | |
78 | RefPtr<RegisterID> m_profileHookRegister; | |
79 | ArgumentsNode* m_argumentsNode; | |
93a37866 | 80 | Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_argv; |
81345200 | 81 | unsigned m_padding; |
14957cd0 | 82 | }; |
9dae56ea A |
83 | |
84 | struct FinallyContext { | |
6fe7ccc8 A |
85 | StatementNode* finallyBlock; |
86 | unsigned scopeContextStackSize; | |
87 | unsigned switchContextStackSize; | |
88 | unsigned forInContextStackSize; | |
93a37866 | 89 | unsigned tryContextStackSize; |
6fe7ccc8 A |
90 | unsigned labelScopesSize; |
91 | int finallyDepth; | |
92 | int dynamicScopeDepth; | |
9dae56ea A |
93 | }; |
94 | ||
95 | struct ControlFlowContext { | |
96 | bool isFinallyBlock; | |
97 | FinallyContext finallyContext; | |
98 | }; | |
99 | ||
f9bf01c6 A |
100 | struct ForInContext { |
101 | RefPtr<RegisterID> expectedSubscriptRegister; | |
102 | RefPtr<RegisterID> iterRegister; | |
103 | RefPtr<RegisterID> indexRegister; | |
104 | RefPtr<RegisterID> propertyRegister; | |
105 | }; | |
106 | ||
93a37866 A |
107 | struct TryData { |
108 | RefPtr<Label> target; | |
109 | unsigned targetScopeDepth; | |
110 | }; | |
111 | ||
112 | struct TryContext { | |
113 | RefPtr<Label> start; | |
114 | TryData* tryData; | |
115 | }; | |
116 | ||
81345200 A |
117 | enum CaptureMode { |
118 | NotCaptured, | |
119 | IsCaptured | |
93a37866 A |
120 | }; |
121 | ||
81345200 | 122 | class Local { |
93a37866 | 123 | public: |
81345200 A |
124 | Local() |
125 | : m_local(0) | |
126 | , m_attributes(0) | |
93a37866 | 127 | { |
93a37866 | 128 | } |
81345200 A |
129 | |
130 | Local(RegisterID* local, unsigned attributes, CaptureMode captureMode) | |
131 | : m_local(local) | |
132 | , m_attributes(attributes) | |
133 | , m_isCaptured(captureMode == IsCaptured) | |
93a37866 | 134 | { |
93a37866 | 135 | } |
93a37866 | 136 | |
81345200 | 137 | operator bool() { return m_local; } |
93a37866 | 138 | |
81345200 | 139 | RegisterID* get() { return m_local; } |
93a37866 | 140 | |
81345200 A |
141 | bool isReadOnly() { return m_attributes & ReadOnly; } |
142 | ||
143 | bool isCaptured() { return m_isCaptured; } | |
144 | CaptureMode captureMode() { return isCaptured() ? IsCaptured : NotCaptured; } | |
93a37866 A |
145 | |
146 | private: | |
81345200 A |
147 | RegisterID* m_local; |
148 | unsigned m_attributes; | |
149 | bool m_isCaptured; | |
93a37866 A |
150 | }; |
151 | ||
81345200 A |
152 | struct TryRange { |
153 | RefPtr<Label> start; | |
154 | RefPtr<Label> end; | |
155 | TryData* tryData; | |
93a37866 A |
156 | }; |
157 | ||
14957cd0 A |
158 | class BytecodeGenerator { |
159 | WTF_MAKE_FAST_ALLOCATED; | |
9dae56ea A |
160 | public: |
161 | typedef DeclarationStacks::VarStack VarStack; | |
162 | typedef DeclarationStacks::FunctionStack FunctionStack; | |
163 | ||
81345200 A |
164 | BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode); |
165 | BytecodeGenerator(VM&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); | |
166 | BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode); | |
9dae56ea | 167 | |
6fe7ccc8 A |
168 | ~BytecodeGenerator(); |
169 | ||
93a37866 A |
170 | VM* vm() const { return m_vm; } |
171 | const CommonIdentifiers& propertyNames() const { return *m_vm->propertyNames; } | |
9dae56ea | 172 | |
93a37866 | 173 | bool isConstructor() { return m_codeBlock->isConstructor(); } |
14957cd0 | 174 | |
93a37866 | 175 | ParserError generate(); |
14957cd0 | 176 | |
6fe7ccc8 | 177 | bool isArgumentNumber(const Identifier&, int); |
14957cd0 A |
178 | |
179 | void setIsNumericCompareFunction(bool isNumericCompareFunction); | |
180 | ||
ba379fdc A |
181 | bool willResolveToArguments(const Identifier&); |
182 | RegisterID* uncheckedRegisterForArguments(); | |
9dae56ea | 183 | |
81345200 A |
184 | bool isCaptured(int operand); |
185 | CaptureMode captureMode(int operand) { return isCaptured(operand) ? IsCaptured : NotCaptured; } | |
186 | ||
187 | Local local(const Identifier&); | |
188 | Local constLocal(const Identifier&); | |
9dae56ea A |
189 | |
190 | // Returns the register storing "this" | |
191 | RegisterID* thisRegister() { return &m_thisRegister; } | |
192 | ||
9dae56ea A |
193 | // Returns the next available temporary register. Registers returned by |
194 | // newTemporary require a modified form of reference counting: any | |
195 | // register with a refcount of 0 is considered "available", meaning that | |
196 | // the next instruction may overwrite it. | |
197 | RegisterID* newTemporary(); | |
198 | ||
9dae56ea A |
199 | // The same as newTemporary(), but this function returns "suggestion" if |
200 | // "suggestion" is a temporary. This function is helpful in situations | |
201 | // where you've put "suggestion" in a RefPtr, but you'd like to allow | |
202 | // the next instruction to overwrite it anyway. | |
203 | RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } | |
204 | ||
205 | // Functions for handling of dst register | |
206 | ||
207 | RegisterID* ignoredResult() { return &m_ignoredResultRegister; } | |
208 | ||
209 | // Returns a place to write intermediate values of an operation | |
210 | // which reuses dst if it is safe to do so. | |
211 | RegisterID* tempDestination(RegisterID* dst) | |
212 | { | |
213 | return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); | |
214 | } | |
215 | ||
216 | // Returns the place to write the final output of an operation. | |
217 | RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) | |
218 | { | |
219 | if (originalDst && originalDst != ignoredResult()) | |
220 | return originalDst; | |
221 | ASSERT(tempDst != ignoredResult()); | |
222 | if (tempDst && tempDst->isTemporary()) | |
223 | return tempDst; | |
224 | return newTemporary(); | |
225 | } | |
226 | ||
227 | RegisterID* destinationForAssignResult(RegisterID* dst) | |
228 | { | |
229 | if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain()) | |
230 | return dst->isTemporary() ? dst : newTemporary(); | |
231 | return 0; | |
232 | } | |
233 | ||
234 | // Moves src to dst if dst is not null and is different from src, otherwise just returns src. | |
235 | RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) | |
236 | { | |
237 | return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; | |
238 | } | |
239 | ||
93a37866 | 240 | LabelScopePtr newLabelScope(LabelScope::Type, const Identifier* = 0); |
9dae56ea A |
241 | PassRefPtr<Label> newLabel(); |
242 | ||
93a37866 | 243 | void emitNode(RegisterID* dst, StatementNode* n) |
9dae56ea A |
244 | { |
245 | // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. | |
246 | ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); | |
81345200 A |
247 | // Should never store directly into a captured variable. |
248 | ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index())); | |
249 | if (!m_vm->isSafeToRecurse()) { | |
93a37866 A |
250 | emitThrowExpressionTooDeepException(); |
251 | return; | |
252 | } | |
253 | n->emitBytecode(*this, dst); | |
9dae56ea A |
254 | } |
255 | ||
93a37866 A |
256 | void emitNode(StatementNode* n) |
257 | { | |
258 | emitNode(0, n); | |
259 | } | |
260 | ||
261 | RegisterID* emitNode(RegisterID* dst, ExpressionNode* n) | |
262 | { | |
263 | // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. | |
264 | ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); | |
81345200 A |
265 | // Should never store directly into a captured variable. |
266 | ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index())); | |
267 | if (!m_vm->isSafeToRecurse()) | |
93a37866 A |
268 | return emitThrowExpressionTooDeepException(); |
269 | return n->emitBytecode(*this, dst); | |
270 | } | |
271 | ||
272 | RegisterID* emitNode(ExpressionNode* n) | |
9dae56ea A |
273 | { |
274 | return emitNode(0, n); | |
275 | } | |
276 | ||
93a37866 | 277 | void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) |
f9bf01c6 | 278 | { |
81345200 | 279 | if (!m_vm->isSafeToRecurse()) { |
f9bf01c6 | 280 | emitThrowExpressionTooDeepException(); |
93a37866 A |
281 | return; |
282 | } | |
283 | ||
284 | n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode); | |
f9bf01c6 A |
285 | } |
286 | ||
81345200 A |
287 | void emitExpressionInfo(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
288 | { | |
289 | ASSERT(divot.offset >= divotStart.offset); | |
290 | ASSERT(divotEnd.offset >= divot.offset); | |
291 | ||
93a37866 A |
292 | int sourceOffset = m_scopeNode->source().startOffset(); |
293 | unsigned firstLine = m_scopeNode->source().firstLine(); | |
14957cd0 | 294 | |
81345200 A |
295 | int divotOffset = divot.offset - sourceOffset; |
296 | int startOffset = divot.offset - divotStart.offset; | |
297 | int endOffset = divotEnd.offset - divot.offset; | |
93a37866 | 298 | |
81345200 A |
299 | unsigned line = divot.line; |
300 | ASSERT(line >= firstLine); | |
301 | line -= firstLine; | |
302 | ||
303 | int lineStart = divot.lineStartOffset; | |
93a37866 A |
304 | if (lineStart > sourceOffset) |
305 | lineStart -= sourceOffset; | |
306 | else | |
307 | lineStart = 0; | |
308 | ||
81345200 A |
309 | if (divotOffset < lineStart) |
310 | return; | |
311 | ||
312 | unsigned column = divotOffset - lineStart; | |
93a37866 A |
313 | |
314 | unsigned instructionOffset = instructions().size(); | |
81345200 A |
315 | if (!m_isBuiltinFunction) |
316 | m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column); | |
9dae56ea A |
317 | } |
318 | ||
9dae56ea A |
319 | ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) |
320 | { | |
321 | return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; | |
322 | } | |
323 | ||
324 | ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) | |
325 | { | |
326 | if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { | |
327 | PassRefPtr<RegisterID> dst = newTemporary(); | |
328 | emitNode(dst.get(), n); | |
329 | return dst; | |
330 | } | |
331 | ||
6fe7ccc8 | 332 | return emitNode(n); |
9dae56ea A |
333 | } |
334 | ||
335 | RegisterID* emitLoad(RegisterID* dst, bool); | |
336 | RegisterID* emitLoad(RegisterID* dst, double); | |
337 | RegisterID* emitLoad(RegisterID* dst, const Identifier&); | |
ba379fdc | 338 | RegisterID* emitLoad(RegisterID* dst, JSValue); |
93a37866 | 339 | RegisterID* emitLoadGlobalObject(RegisterID* dst); |
9dae56ea A |
340 | |
341 | RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); | |
342 | RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); | |
343 | RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2); | |
344 | RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src); | |
345 | ||
93a37866 | 346 | RegisterID* emitCreateThis(RegisterID* dst); |
9dae56ea | 347 | RegisterID* emitNewObject(RegisterID* dst); |
14957cd0 | 348 | RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision |
9dae56ea | 349 | |
81345200 | 350 | RegisterID* emitNewFunction(RegisterID* dst, CaptureMode, FunctionBodyNode*); |
14957cd0 | 351 | RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body); |
81345200 | 352 | RegisterID* emitNewFunctionInternal(RegisterID* dst, CaptureMode, unsigned index, bool shouldNullCheck); |
9dae56ea | 353 | RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); |
14957cd0 | 354 | RegisterID* emitNewRegExp(RegisterID* dst, RegExp*); |
9dae56ea | 355 | |
81345200 | 356 | RegisterID* emitMove(RegisterID* dst, CaptureMode, RegisterID* src); |
9dae56ea A |
357 | RegisterID* emitMove(RegisterID* dst, RegisterID* src); |
358 | ||
93a37866 A |
359 | RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); } |
360 | RegisterID* emitInc(RegisterID* srcDst); | |
361 | RegisterID* emitDec(RegisterID* srcDst); | |
9dae56ea | 362 | |
93a37866 A |
363 | void emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target); |
364 | RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype); | |
9dae56ea A |
365 | RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } |
366 | RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } | |
367 | ||
93a37866 | 368 | RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value); |
9dae56ea | 369 | |
9dae56ea | 370 | RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); |
14957cd0 | 371 | RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base); |
9dae56ea | 372 | RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); |
4e4e5a6f | 373 | RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value); |
9dae56ea A |
374 | RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); |
375 | RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); | |
14957cd0 | 376 | RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property); |
9dae56ea | 377 | RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); |
81345200 | 378 | RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); |
9dae56ea A |
379 | RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); |
380 | RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); | |
6fe7ccc8 | 381 | void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter); |
93a37866 A |
382 | |
383 | ExpectedFunction expectedFunctionForIdentifier(const Identifier&); | |
81345200 A |
384 | RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
385 | RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); | |
386 | 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 | 387 | |
81345200 A |
388 | void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack); |
389 | ||
9dae56ea A |
390 | RegisterID* emitReturn(RegisterID* src); |
391 | RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); } | |
392 | ||
81345200 | 393 | RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
ba379fdc A |
394 | RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count); |
395 | void emitToPrimitive(RegisterID* dst, RegisterID* src); | |
9dae56ea | 396 | |
81345200 A |
397 | ResolveType resolveType(); |
398 | RegisterID* emitResolveScope(RegisterID* dst, const Identifier&); | |
399 | RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier&, ResolveMode); | |
400 | RegisterID* emitPutToScope(RegisterID* scope, const Identifier&, RegisterID* value, ResolveMode); | |
401 | ||
9dae56ea | 402 | PassRefPtr<Label> emitLabel(Label*); |
6fe7ccc8 | 403 | void emitLoopHint(); |
9dae56ea A |
404 | PassRefPtr<Label> emitJump(Label* target); |
405 | PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target); | |
406 | PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target); | |
ba379fdc A |
407 | PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target); |
408 | PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target); | |
93a37866 | 409 | void emitPopScopes(int targetScopeDepth); |
9dae56ea | 410 | |
f9bf01c6 A |
411 | RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget); |
412 | RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target); | |
9dae56ea | 413 | |
93a37866 A |
414 | void emitReadOnlyExceptionIfNeeded(); |
415 | ||
416 | // Start a try block. 'start' must have been emitted. | |
417 | TryData* pushTry(Label* start); | |
418 | // End a try block. 'end' must have been emitted. | |
419 | RegisterID* popTryAndEmitCatch(TryData*, RegisterID* targetRegister, Label* end); | |
420 | ||
14957cd0 A |
421 | void emitThrow(RegisterID* exc) |
422 | { | |
423 | m_usesExceptions = true; | |
424 | emitUnaryNoDstOp(op_throw, exc); | |
425 | } | |
426 | ||
93a37866 | 427 | void emitThrowReferenceError(const String& message); |
14957cd0 | 428 | |
81345200 A |
429 | void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, unsigned attributes); |
430 | void emitPushCatchScope(const Identifier& property, RegisterID* value, unsigned attributes); | |
9dae56ea | 431 | |
93a37866 | 432 | RegisterID* emitPushWithScope(RegisterID* scope); |
9dae56ea A |
433 | void emitPopScope(); |
434 | ||
81345200 | 435 | void emitDebugHook(DebugHookID, unsigned line, unsigned charOffset, unsigned lineStart); |
9dae56ea | 436 | |
81345200 | 437 | int scopeDepth() { return m_localScopeDepth + m_finallyDepth; } |
9dae56ea A |
438 | bool hasFinaliser() { return m_finallyDepth != 0; } |
439 | ||
6fe7ccc8 | 440 | void pushFinallyContext(StatementNode* finallyBlock); |
9dae56ea A |
441 | void popFinallyContext(); |
442 | ||
81345200 | 443 | void pushOptimisedForIn(RegisterID* expectedSubscript, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister) |
f9bf01c6 | 444 | { |
81345200 | 445 | ForInContext context = { expectedSubscript, iter, index, propertyRegister }; |
f9bf01c6 A |
446 | m_forInContextStack.append(context); |
447 | } | |
448 | ||
449 | void popOptimisedForIn() | |
450 | { | |
451 | m_forInContextStack.removeLast(); | |
452 | } | |
453 | ||
81345200 A |
454 | LabelScopePtr breakTarget(const Identifier&); |
455 | LabelScopePtr continueTarget(const Identifier&); | |
9dae56ea A |
456 | |
457 | void beginSwitch(RegisterID*, SwitchInfo::SwitchType); | |
458 | void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range); | |
459 | ||
460 | CodeType codeType() const { return m_codeType; } | |
461 | ||
14957cd0 | 462 | bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; } |
93a37866 | 463 | bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; } |
14957cd0 A |
464 | |
465 | bool isStrictMode() const { return m_codeBlock->isStrictMode(); } | |
81345200 A |
466 | |
467 | bool isBuiltinFunction() const { return m_isBuiltinFunction; } | |
468 | ||
9dae56ea | 469 | private: |
6fe7ccc8 A |
470 | friend class Label; |
471 | ||
9dae56ea | 472 | void emitOpcode(OpcodeID); |
93a37866 A |
473 | UnlinkedArrayAllocationProfile newArrayAllocationProfile(); |
474 | UnlinkedObjectAllocationProfile newObjectAllocationProfile(); | |
475 | UnlinkedArrayProfile newArrayProfile(); | |
476 | UnlinkedValueProfile emitProfiledOpcode(OpcodeID); | |
477 | int kill(RegisterID* dst) | |
478 | { | |
479 | int index = dst->index(); | |
480 | m_staticPropertyAnalyzer.kill(index); | |
481 | return index; | |
482 | } | |
483 | ||
9dae56ea A |
484 | void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); |
485 | void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); | |
4e4e5a6f A |
486 | ALWAYS_INLINE void rewindBinaryOp(); |
487 | ALWAYS_INLINE void rewindUnaryOp(); | |
9dae56ea | 488 | |
93a37866 | 489 | void emitComplexPopScopes(ControlFlowContext* topScope, ControlFlowContext* bottomScope); |
9dae56ea | 490 | |
ba379fdc | 491 | typedef HashMap<double, JSValue> NumberMap; |
14957cd0 | 492 | typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; |
93a37866 A |
493 | |
494 | // Helper for emitCall() and emitConstruct(). This works because the set of | |
495 | // expected functions have identical behavior for both call and construct | |
496 | // (i.e. "Object()" is identical to "new Object()"). | |
497 | ExpectedFunction emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, Label* done); | |
9dae56ea | 498 | |
81345200 | 499 | RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
14957cd0 | 500 | |
9dae56ea A |
501 | RegisterID* newRegister(); |
502 | ||
14957cd0 | 503 | // Adds a var slot and maps it to the name ident in symbolTable(). |
81345200 A |
504 | enum WatchMode { IsWatchable, NotWatchable }; |
505 | RegisterID* addVar(const Identifier& ident, ConstantMode constantMode, WatchMode watchMode) | |
9dae56ea A |
506 | { |
507 | RegisterID* local; | |
81345200 | 508 | addVar(ident, constantMode, watchMode, local); |
9dae56ea A |
509 | return local; |
510 | } | |
14957cd0 A |
511 | |
512 | // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. | |
81345200 | 513 | bool addVar(const Identifier&, ConstantMode, WatchMode, RegisterID*&); |
14957cd0 A |
514 | |
515 | // Adds an anonymous var slot. To give this slot a name, add it to symbolTable(). | |
516 | RegisterID* addVar() | |
517 | { | |
518 | ++m_codeBlock->m_numVars; | |
519 | return newRegister(); | |
520 | } | |
9dae56ea | 521 | |
6fe7ccc8 | 522 | // Returns the index of the added var. |
14957cd0 | 523 | void addParameter(const Identifier&, int parameterIndex); |
93a37866 A |
524 | RegisterID* resolveCallee(FunctionBodyNode*); |
525 | void addCallee(FunctionBodyNode*, RegisterID*); | |
526 | ||
ba379fdc | 527 | void preserveLastVar(); |
9dae56ea A |
528 | |
529 | RegisterID& registerFor(int index) | |
530 | { | |
81345200 A |
531 | if (operandIsLocal(index)) |
532 | return m_calleeRegisters[VirtualRegister(index).toLocal()]; | |
9dae56ea | 533 | |
93a37866 A |
534 | if (index == JSStack::Callee) |
535 | return m_calleeRegister; | |
536 | ||
6fe7ccc8 | 537 | ASSERT(m_parameters.size()); |
81345200 | 538 | return m_parameters[VirtualRegister(index).toArgument()]; |
9dae56ea A |
539 | } |
540 | ||
9dae56ea | 541 | unsigned addConstant(const Identifier&); |
ba379fdc | 542 | RegisterID* addConstantValue(JSValue); |
93a37866 | 543 | RegisterID* addConstantEmptyValue(); |
9dae56ea A |
544 | unsigned addRegExp(RegExp*); |
545 | ||
14957cd0 A |
546 | unsigned addConstantBuffer(unsigned length); |
547 | ||
93a37866 | 548 | UnlinkedFunctionExecutable* makeFunction(FunctionBodyNode* body) |
f9bf01c6 | 549 | { |
81345200 | 550 | return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction); |
f9bf01c6 A |
551 | } |
552 | ||
93a37866 | 553 | RegisterID* emitInitLazyRegister(RegisterID*); |
81345200 A |
554 | |
555 | RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); | |
556 | 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); | |
557 | ||
93a37866 | 558 | public: |
14957cd0 A |
559 | JSString* addStringConstant(const Identifier&); |
560 | ||
93a37866 | 561 | Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; } |
14957cd0 | 562 | |
81345200 | 563 | SymbolTable& symbolTable() { return *m_symbolTable; } |
9dae56ea | 564 | |
6fe7ccc8 A |
565 | bool shouldOptimizeLocals() |
566 | { | |
81345200 | 567 | if (m_codeType != FunctionCode) |
6fe7ccc8 A |
568 | return false; |
569 | ||
81345200 | 570 | if (m_localScopeDepth) |
6fe7ccc8 A |
571 | return false; |
572 | ||
573 | return true; | |
574 | } | |
575 | ||
576 | bool canOptimizeNonLocals() | |
577 | { | |
81345200 | 578 | if (m_localScopeDepth) |
6fe7ccc8 A |
579 | return false; |
580 | ||
581 | if (m_codeType == EvalCode) | |
582 | return false; | |
583 | ||
584 | if (m_codeType == FunctionCode && m_codeBlock->usesEval()) | |
585 | return false; | |
586 | ||
587 | return true; | |
588 | } | |
9dae56ea | 589 | |
81345200 A |
590 | bool shouldTearOffArgumentsEagerly() |
591 | { | |
592 | return m_codeType == FunctionCode && isStrictMode() && m_scopeNode->modifiesParameter(); | |
593 | } | |
594 | ||
9dae56ea A |
595 | RegisterID* emitThrowExpressionTooDeepException(); |
596 | ||
ba379fdc | 597 | void createArgumentsIfNecessary(); |
14957cd0 A |
598 | void createActivationIfNecessary(); |
599 | RegisterID* createLazyRegisterIfNecessary(RegisterID*); | |
6fe7ccc8 | 600 | |
81345200 A |
601 | unsigned watchableVariable(int operand) |
602 | { | |
603 | VirtualRegister reg(operand); | |
604 | if (!reg.isLocal()) | |
605 | return UINT_MAX; | |
606 | if (static_cast<size_t>(reg.toLocal()) >= m_watchableVariables.size()) | |
607 | return UINT_MAX; | |
608 | Identifier& ident = m_watchableVariables[reg.toLocal()]; | |
609 | if (ident.isNull()) | |
610 | return UINT_MAX; | |
611 | return addConstant(ident); | |
612 | } | |
613 | ||
614 | bool hasWatchableVariable(int operand) | |
615 | { | |
616 | return watchableVariable(operand) != UINT_MAX; | |
617 | } | |
618 | ||
93a37866 | 619 | Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow> m_instructions; |
ba379fdc | 620 | |
9dae56ea A |
621 | bool m_shouldEmitDebugHooks; |
622 | bool m_shouldEmitProfileHooks; | |
623 | ||
81345200 | 624 | SymbolTable* m_symbolTable; |
9dae56ea A |
625 | |
626 | ScopeNode* m_scopeNode; | |
93a37866 | 627 | Strong<UnlinkedCodeBlock> m_codeBlock; |
9dae56ea | 628 | |
ba379fdc A |
629 | // Some of these objects keep pointers to one another. They are arranged |
630 | // to ensure a sane destruction order that avoids references to freed memory. | |
14957cd0 | 631 | HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions; |
9dae56ea A |
632 | RegisterID m_ignoredResultRegister; |
633 | RegisterID m_thisRegister; | |
93a37866 | 634 | RegisterID m_calleeRegister; |
14957cd0 | 635 | RegisterID* m_activationRegister; |
93a37866 A |
636 | RegisterID* m_emptyValueRegister; |
637 | RegisterID* m_globalObjectRegister; | |
81345200 | 638 | Vector<Identifier, 16> m_watchableVariables; |
f9bf01c6 A |
639 | SegmentedVector<RegisterID, 32> m_constantPoolRegisters; |
640 | SegmentedVector<RegisterID, 32> m_calleeRegisters; | |
641 | SegmentedVector<RegisterID, 32> m_parameters; | |
f9bf01c6 | 642 | SegmentedVector<Label, 32> m_labels; |
93a37866 | 643 | LabelScopeStore m_labelScopes; |
ba379fdc | 644 | RefPtr<RegisterID> m_lastVar; |
9dae56ea | 645 | int m_finallyDepth; |
81345200 | 646 | int m_localScopeDepth; |
9dae56ea A |
647 | CodeType m_codeType; |
648 | ||
93a37866 | 649 | Vector<ControlFlowContext, 0, UnsafeVectorOverflow> m_scopeContextStack; |
9dae56ea | 650 | Vector<SwitchInfo> m_switchContextStack; |
f9bf01c6 | 651 | Vector<ForInContext> m_forInContextStack; |
93a37866 | 652 | Vector<TryContext> m_tryContextStack; |
81345200 | 653 | Vector<std::pair<RefPtr<RegisterID>, const DeconstructionPatternNode*>> m_deconstructedParameters; |
93a37866 A |
654 | |
655 | Vector<TryRange> m_tryRanges; | |
656 | SegmentedVector<TryData, 8> m_tryData; | |
9dae56ea | 657 | |
ba379fdc A |
658 | int m_firstConstantIndex; |
659 | int m_nextConstantOffset; | |
660 | unsigned m_globalConstantIndex; | |
9dae56ea A |
661 | |
662 | int m_globalVarStorageOffset; | |
663 | ||
14957cd0 A |
664 | int m_firstLazyFunction; |
665 | int m_lastLazyFunction; | |
81345200 | 666 | HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int>> m_lazyFunctions; |
14957cd0 A |
667 | typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap; |
668 | FunctionOffsetMap m_functionOffsets; | |
669 | ||
9dae56ea A |
670 | // Constant pool |
671 | IdentifierMap m_identifierMap; | |
672 | JSValueMap m_jsValueMap; | |
673 | NumberMap m_numberMap; | |
674 | IdentifierStringMap m_stringMap; | |
675 | ||
93a37866 A |
676 | StaticPropertyAnalyzer m_staticPropertyAnalyzer; |
677 | ||
678 | VM* m_vm; | |
9dae56ea A |
679 | |
680 | OpcodeID m_lastOpcodeID; | |
14957cd0 A |
681 | #ifndef NDEBUG |
682 | size_t m_lastOpcodePosition; | |
683 | #endif | |
9dae56ea | 684 | |
14957cd0 A |
685 | bool m_usesExceptions; |
686 | bool m_expressionTooDeep; | |
81345200 | 687 | bool m_isBuiltinFunction; |
b80e6193 | 688 | }; |
93a37866 | 689 | |
9dae56ea A |
690 | } |
691 | ||
692 | #endif // BytecodeGenerator_h |