]> git.saurik.com Git - apple/javascriptcore.git/blob - bytecompiler/BytecodeGenerator.h
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / bytecompiler / BytecodeGenerator.h
1 /*
2 * Copyright (C) 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 * Copyright (C) 2012 Igalia, S.L.
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.
15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
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"
35 #include <wtf/HashTraits.h>
36 #include "Instruction.h"
37 #include "Label.h"
38 #include "LabelScope.h"
39 #include "Interpreter.h"
40 #include "ParserError.h"
41 #include "RegisterID.h"
42 #include "SymbolTable.h"
43 #include "Debugger.h"
44 #include "Nodes.h"
45 #include "StaticPropertyAnalyzer.h"
46 #include "UnlinkedCodeBlock.h"
47
48 #include <functional>
49
50 #include <wtf/PassRefPtr.h>
51 #include <wtf/SegmentedVector.h>
52 #include <wtf/Vector.h>
53
54
55 namespace JSC {
56
57 class Identifier;
58 class Label;
59
60 enum ExpectedFunction {
61 NoExpectedFunction,
62 ExpectObjectConstructor,
63 ExpectArrayConstructor
64 };
65
66 class CallArguments {
67 public:
68 CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0);
69
70 RegisterID* thisRegister() { return m_argv[0].get(); }
71 RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); }
72 unsigned stackOffset() { return -m_argv[0]->index() + JSStack::CallFrameHeaderSize; }
73 unsigned argumentCountIncludingThis() { return m_argv.size() - m_padding; }
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;
80 Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_argv;
81 unsigned m_padding;
82 };
83
84 struct FinallyContext {
85 StatementNode* finallyBlock;
86 unsigned scopeContextStackSize;
87 unsigned switchContextStackSize;
88 unsigned forInContextStackSize;
89 unsigned tryContextStackSize;
90 unsigned labelScopesSize;
91 int finallyDepth;
92 int dynamicScopeDepth;
93 };
94
95 struct ControlFlowContext {
96 bool isFinallyBlock;
97 FinallyContext finallyContext;
98 };
99
100 struct ForInContext {
101 RefPtr<RegisterID> expectedSubscriptRegister;
102 RefPtr<RegisterID> iterRegister;
103 RefPtr<RegisterID> indexRegister;
104 RefPtr<RegisterID> propertyRegister;
105 };
106
107 struct TryData {
108 RefPtr<Label> target;
109 unsigned targetScopeDepth;
110 };
111
112 struct TryContext {
113 RefPtr<Label> start;
114 TryData* tryData;
115 };
116
117 enum CaptureMode {
118 NotCaptured,
119 IsCaptured
120 };
121
122 class Local {
123 public:
124 Local()
125 : m_local(0)
126 , m_attributes(0)
127 {
128 }
129
130 Local(RegisterID* local, unsigned attributes, CaptureMode captureMode)
131 : m_local(local)
132 , m_attributes(attributes)
133 , m_isCaptured(captureMode == IsCaptured)
134 {
135 }
136
137 operator bool() { return m_local; }
138
139 RegisterID* get() { return m_local; }
140
141 bool isReadOnly() { return m_attributes & ReadOnly; }
142
143 bool isCaptured() { return m_isCaptured; }
144 CaptureMode captureMode() { return isCaptured() ? IsCaptured : NotCaptured; }
145
146 private:
147 RegisterID* m_local;
148 unsigned m_attributes;
149 bool m_isCaptured;
150 };
151
152 struct TryRange {
153 RefPtr<Label> start;
154 RefPtr<Label> end;
155 TryData* tryData;
156 };
157
158 class BytecodeGenerator {
159 WTF_MAKE_FAST_ALLOCATED;
160 public:
161 typedef DeclarationStacks::VarStack VarStack;
162 typedef DeclarationStacks::FunctionStack FunctionStack;
163
164 BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode);
165 BytecodeGenerator(VM&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode);
166 BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode);
167
168 ~BytecodeGenerator();
169
170 VM* vm() const { return m_vm; }
171 const CommonIdentifiers& propertyNames() const { return *m_vm->propertyNames; }
172
173 bool isConstructor() { return m_codeBlock->isConstructor(); }
174
175 ParserError generate();
176
177 bool isArgumentNumber(const Identifier&, int);
178
179 void setIsNumericCompareFunction(bool isNumericCompareFunction);
180
181 bool willResolveToArguments(const Identifier&);
182 RegisterID* uncheckedRegisterForArguments();
183
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&);
189
190 // Returns the register storing "this"
191 RegisterID* thisRegister() { return &m_thisRegister; }
192
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
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
240 LabelScopePtr newLabelScope(LabelScope::Type, const Identifier* = 0);
241 PassRefPtr<Label> newLabel();
242
243 void emitNode(RegisterID* dst, StatementNode* n)
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());
247 // Should never store directly into a captured variable.
248 ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index()));
249 if (!m_vm->isSafeToRecurse()) {
250 emitThrowExpressionTooDeepException();
251 return;
252 }
253 n->emitBytecode(*this, dst);
254 }
255
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());
265 // Should never store directly into a captured variable.
266 ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index()));
267 if (!m_vm->isSafeToRecurse())
268 return emitThrowExpressionTooDeepException();
269 return n->emitBytecode(*this, dst);
270 }
271
272 RegisterID* emitNode(ExpressionNode* n)
273 {
274 return emitNode(0, n);
275 }
276
277 void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
278 {
279 if (!m_vm->isSafeToRecurse()) {
280 emitThrowExpressionTooDeepException();
281 return;
282 }
283
284 n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode);
285 }
286
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
292 int sourceOffset = m_scopeNode->source().startOffset();
293 unsigned firstLine = m_scopeNode->source().firstLine();
294
295 int divotOffset = divot.offset - sourceOffset;
296 int startOffset = divot.offset - divotStart.offset;
297 int endOffset = divotEnd.offset - divot.offset;
298
299 unsigned line = divot.line;
300 ASSERT(line >= firstLine);
301 line -= firstLine;
302
303 int lineStart = divot.lineStartOffset;
304 if (lineStart > sourceOffset)
305 lineStart -= sourceOffset;
306 else
307 lineStart = 0;
308
309 if (divotOffset < lineStart)
310 return;
311
312 unsigned column = divotOffset - lineStart;
313
314 unsigned instructionOffset = instructions().size();
315 if (!m_isBuiltinFunction)
316 m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column);
317 }
318
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
332 return emitNode(n);
333 }
334
335 RegisterID* emitLoad(RegisterID* dst, bool);
336 RegisterID* emitLoad(RegisterID* dst, double);
337 RegisterID* emitLoad(RegisterID* dst, const Identifier&);
338 RegisterID* emitLoad(RegisterID* dst, JSValue);
339 RegisterID* emitLoadGlobalObject(RegisterID* dst);
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
346 RegisterID* emitCreateThis(RegisterID* dst);
347 RegisterID* emitNewObject(RegisterID* dst);
348 RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
349
350 RegisterID* emitNewFunction(RegisterID* dst, CaptureMode, FunctionBodyNode*);
351 RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body);
352 RegisterID* emitNewFunctionInternal(RegisterID* dst, CaptureMode, unsigned index, bool shouldNullCheck);
353 RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
354 RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
355
356 RegisterID* emitMove(RegisterID* dst, CaptureMode, RegisterID* src);
357 RegisterID* emitMove(RegisterID* dst, RegisterID* src);
358
359 RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); }
360 RegisterID* emitInc(RegisterID* srcDst);
361 RegisterID* emitDec(RegisterID* srcDst);
362
363 void emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target);
364 RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype);
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
368 RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value);
369
370 RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
371 RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base);
372 RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
373 RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value);
374 RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
375 RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
376 RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
377 RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
378 RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
379 RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
380 RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
381 void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter);
382
383 ExpectedFunction expectedFunctionForIdentifier(const Identifier&);
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);
387
388 void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack);
389
390 RegisterID* emitReturn(RegisterID* src);
391 RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
392
393 RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
394 RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count);
395 void emitToPrimitive(RegisterID* dst, RegisterID* src);
396
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
402 PassRefPtr<Label> emitLabel(Label*);
403 void emitLoopHint();
404 PassRefPtr<Label> emitJump(Label* target);
405 PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target);
406 PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target);
407 PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target);
408 PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target);
409 void emitPopScopes(int targetScopeDepth);
410
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);
413
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
421 void emitThrow(RegisterID* exc)
422 {
423 m_usesExceptions = true;
424 emitUnaryNoDstOp(op_throw, exc);
425 }
426
427 void emitThrowReferenceError(const String& message);
428
429 void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, unsigned attributes);
430 void emitPushCatchScope(const Identifier& property, RegisterID* value, unsigned attributes);
431
432 RegisterID* emitPushWithScope(RegisterID* scope);
433 void emitPopScope();
434
435 void emitDebugHook(DebugHookID, unsigned line, unsigned charOffset, unsigned lineStart);
436
437 int scopeDepth() { return m_localScopeDepth + m_finallyDepth; }
438 bool hasFinaliser() { return m_finallyDepth != 0; }
439
440 void pushFinallyContext(StatementNode* finallyBlock);
441 void popFinallyContext();
442
443 void pushOptimisedForIn(RegisterID* expectedSubscript, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister)
444 {
445 ForInContext context = { expectedSubscript, iter, index, propertyRegister };
446 m_forInContextStack.append(context);
447 }
448
449 void popOptimisedForIn()
450 {
451 m_forInContextStack.removeLast();
452 }
453
454 LabelScopePtr breakTarget(const Identifier&);
455 LabelScopePtr continueTarget(const Identifier&);
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
462 bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
463 bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; }
464
465 bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
466
467 bool isBuiltinFunction() const { return m_isBuiltinFunction; }
468
469 private:
470 friend class Label;
471
472 void emitOpcode(OpcodeID);
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
484 void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
485 void retrieveLastUnaryOp(int& dstIndex, int& srcIndex);
486 ALWAYS_INLINE void rewindBinaryOp();
487 ALWAYS_INLINE void rewindUnaryOp();
488
489 void emitComplexPopScopes(ControlFlowContext* topScope, ControlFlowContext* bottomScope);
490
491 typedef HashMap<double, JSValue> NumberMap;
492 typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
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);
498
499 RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
500
501 RegisterID* newRegister();
502
503 // Adds a var slot and maps it to the name ident in symbolTable().
504 enum WatchMode { IsWatchable, NotWatchable };
505 RegisterID* addVar(const Identifier& ident, ConstantMode constantMode, WatchMode watchMode)
506 {
507 RegisterID* local;
508 addVar(ident, constantMode, watchMode, local);
509 return local;
510 }
511
512 // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
513 bool addVar(const Identifier&, ConstantMode, WatchMode, RegisterID*&);
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 }
521
522 // Returns the index of the added var.
523 void addParameter(const Identifier&, int parameterIndex);
524 RegisterID* resolveCallee(FunctionBodyNode*);
525 void addCallee(FunctionBodyNode*, RegisterID*);
526
527 void preserveLastVar();
528
529 RegisterID& registerFor(int index)
530 {
531 if (operandIsLocal(index))
532 return m_calleeRegisters[VirtualRegister(index).toLocal()];
533
534 if (index == JSStack::Callee)
535 return m_calleeRegister;
536
537 ASSERT(m_parameters.size());
538 return m_parameters[VirtualRegister(index).toArgument()];
539 }
540
541 unsigned addConstant(const Identifier&);
542 RegisterID* addConstantValue(JSValue);
543 RegisterID* addConstantEmptyValue();
544 unsigned addRegExp(RegExp*);
545
546 unsigned addConstantBuffer(unsigned length);
547
548 UnlinkedFunctionExecutable* makeFunction(FunctionBodyNode* body)
549 {
550 return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction);
551 }
552
553 RegisterID* emitInitLazyRegister(RegisterID*);
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
558 public:
559 JSString* addStringConstant(const Identifier&);
560
561 Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; }
562
563 SymbolTable& symbolTable() { return *m_symbolTable; }
564
565 bool shouldOptimizeLocals()
566 {
567 if (m_codeType != FunctionCode)
568 return false;
569
570 if (m_localScopeDepth)
571 return false;
572
573 return true;
574 }
575
576 bool canOptimizeNonLocals()
577 {
578 if (m_localScopeDepth)
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 }
589
590 bool shouldTearOffArgumentsEagerly()
591 {
592 return m_codeType == FunctionCode && isStrictMode() && m_scopeNode->modifiesParameter();
593 }
594
595 RegisterID* emitThrowExpressionTooDeepException();
596
597 void createArgumentsIfNecessary();
598 void createActivationIfNecessary();
599 RegisterID* createLazyRegisterIfNecessary(RegisterID*);
600
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
619 Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow> m_instructions;
620
621 bool m_shouldEmitDebugHooks;
622 bool m_shouldEmitProfileHooks;
623
624 SymbolTable* m_symbolTable;
625
626 ScopeNode* m_scopeNode;
627 Strong<UnlinkedCodeBlock> m_codeBlock;
628
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.
631 HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions;
632 RegisterID m_ignoredResultRegister;
633 RegisterID m_thisRegister;
634 RegisterID m_calleeRegister;
635 RegisterID* m_activationRegister;
636 RegisterID* m_emptyValueRegister;
637 RegisterID* m_globalObjectRegister;
638 Vector<Identifier, 16> m_watchableVariables;
639 SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
640 SegmentedVector<RegisterID, 32> m_calleeRegisters;
641 SegmentedVector<RegisterID, 32> m_parameters;
642 SegmentedVector<Label, 32> m_labels;
643 LabelScopeStore m_labelScopes;
644 RefPtr<RegisterID> m_lastVar;
645 int m_finallyDepth;
646 int m_localScopeDepth;
647 CodeType m_codeType;
648
649 Vector<ControlFlowContext, 0, UnsafeVectorOverflow> m_scopeContextStack;
650 Vector<SwitchInfo> m_switchContextStack;
651 Vector<ForInContext> m_forInContextStack;
652 Vector<TryContext> m_tryContextStack;
653 Vector<std::pair<RefPtr<RegisterID>, const DeconstructionPatternNode*>> m_deconstructedParameters;
654
655 Vector<TryRange> m_tryRanges;
656 SegmentedVector<TryData, 8> m_tryData;
657
658 int m_firstConstantIndex;
659 int m_nextConstantOffset;
660 unsigned m_globalConstantIndex;
661
662 int m_globalVarStorageOffset;
663
664 int m_firstLazyFunction;
665 int m_lastLazyFunction;
666 HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int>> m_lazyFunctions;
667 typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap;
668 FunctionOffsetMap m_functionOffsets;
669
670 // Constant pool
671 IdentifierMap m_identifierMap;
672 JSValueMap m_jsValueMap;
673 NumberMap m_numberMap;
674 IdentifierStringMap m_stringMap;
675
676 StaticPropertyAnalyzer m_staticPropertyAnalyzer;
677
678 VM* m_vm;
679
680 OpcodeID m_lastOpcodeID;
681 #ifndef NDEBUG
682 size_t m_lastOpcodePosition;
683 #endif
684
685 bool m_usesExceptions;
686 bool m_expressionTooDeep;
687 bool m_isBuiltinFunction;
688 };
689
690 }
691
692 #endif // BytecodeGenerator_h