]> git.saurik.com Git - apple/javascriptcore.git/blame - bytecompiler/BytecodeGenerator.h
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / bytecompiler / BytecodeGenerator.h
CommitLineData
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
55namespace 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