BytecodeGenerator.h 31.3 KB
Newer Older
1
/*
2
 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3
 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4
 * Copyright (C) 2012 Igalia, S.L.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

31 32
#ifndef BytecodeGenerator_h
#define BytecodeGenerator_h
33 34

#include "CodeBlock.h"
35
#include "HashTraits.h"
36
#include "Instruction.h"
37
#include "Label.h"
38
#include "LabelScope.h"
ggaren@apple.com's avatar
ggaren@apple.com committed
39
#include "Interpreter.h"
40
#include "RegisterID.h"
41
#include "SymbolTable.h"
42
#include "Debugger.h"
43
#include "Nodes.h"
44
#include <wtf/PassRefPtr.h>
45
#include <wtf/SegmentedVector.h>
46 47
#include <wtf/Vector.h>

48
namespace JSC {
49 50

    class Identifier;
51
    class Label;
52
    class ScopeChainNode;
53

54 55 56 57 58 59
    class CallArguments {
    public:
        CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode);

        RegisterID* thisRegister() { return m_argv[0].get(); }
        RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); }
60 61
        unsigned registerOffset() { return m_argv.last()->index() + CallFrame::offsetFor(argumentCountIncludingThis()); }
        unsigned argumentCountIncludingThis() { return m_argv.size(); }
62
        RegisterID* profileHookRegister() { return m_profileHookRegister.get(); }
63 64 65
        ArgumentsNode* argumentsNode() { return m_argumentsNode; }

    private:
66 67
        void newArgument(BytecodeGenerator&);

68
        RefPtr<RegisterID> m_profileHookRegister;
69
        ArgumentsNode* m_argumentsNode;
70
        Vector<RefPtr<RegisterID>, 8> m_argv;
71 72
    };

73
    struct FinallyContext {
74
        Label* finallyAddr;
75 76
        RegisterID* retAddrDst;
    };
77

78 79 80 81
    struct ControlFlowContext {
        bool isFinallyBlock;
        FinallyContext finallyContext;
    };
82

83 84 85 86 87 88 89
    struct ForInContext {
        RefPtr<RegisterID> expectedSubscriptRegister;
        RefPtr<RegisterID> iterRegister;
        RefPtr<RegisterID> indexRegister;
        RefPtr<RegisterID> propertyRegister;
    };

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    class ResolveResult {
    public:
        enum Flags {
            // The property is locally bound, in a register.
            RegisterFlag = 0x1,
            // We need to traverse the scope chain at runtime, checking for
            // non-strict eval and/or `with' nodes.
            DynamicFlag = 0x2,
            // The property was resolved to a definite location, and the
            // identifier is not needed any more.
            StaticFlag = 0x4,
            // Once we have the base object, the property will be located at a
            // known index.
            IndexedFlag = 0x8,
            // Skip some number of objects in the scope chain, given by "depth".
            ScopedFlag = 0x10,
            // The resolved binding is immutable.
            ReadOnlyFlag = 0x20,
            // The base object is the global object.
            GlobalFlag = 0x40
        };
        enum Type {
            // The property is local, and stored in a register.
            Register = RegisterFlag | StaticFlag,
            // A read-only local, created by "const".
            ReadOnlyRegister = RegisterFlag | ReadOnlyFlag | StaticFlag,
            // The property is statically scoped free variable. Its coordinates
            // are in "index" and "depth".
            Lexical = IndexedFlag | ScopedFlag | StaticFlag,
            // A read-only Lexical, created by "const".
            ReadOnlyLexical = IndexedFlag | ScopedFlag | ReadOnlyFlag | StaticFlag,
            // The property was not bound lexically, so at runtime we should
            // look directly in the global object.
            Global = GlobalFlag,
            // Like Global, but we could actually resolve the property to a
            // DontDelete property in the global object, for instance, any
            // binding created with "var" at the top level. At runtime we'll
            // just index into the global object.
            IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag,
            // Like IndexedGlobal, but the property is also read-only, like NaN,
            // Infinity, or undefined.
            ReadOnlyIndexedGlobal = IndexedFlag | ReadOnlyFlag | GlobalFlag | StaticFlag,
            // The property could not be resolved statically, due to the
            // presence of `with' blocks. At runtime we'll have to walk the
            // scope chain. ScopedFlag is set to indicate that "depth" will
            // hold some number of nodes to skip in the scope chain, before
            // beginning the search.
            Dynamic = DynamicFlag | ScopedFlag,
            // The property was located as a statically scoped free variable,
            // but while traversing the scope chain, there was an intermediate
            // activation that used non-strict `eval'. At runtime we'll have to
            // check for the absence of this property in those intervening
            // scopes.
            DynamicLexical = DynamicFlag | IndexedFlag | ScopedFlag,
            // Like ReadOnlyLexical, but with intervening non-strict `eval'.
            DynamicReadOnlyLexical = DynamicFlag | IndexedFlag | ScopedFlag | ReadOnlyFlag,
            // Like Global, but with intervening non-strict `eval'. As with 
            // Dynamic, ScopeFlag is set to indicate that "depth" does indeed
            // store a number of frames to skip before doing the dynamic checks.
            DynamicGlobal = DynamicFlag | GlobalFlag | ScopedFlag,
            // Like IndexedGlobal, but with intervening non-strict `eval'.
            DynamicIndexedGlobal = DynamicFlag | IndexedFlag | GlobalFlag | ScopedFlag,
            // Like ReadOnlyIndexedGlobal, but with intervening non-strict
            // `eval'.
            DynamicReadOnlyIndexedGlobal = DynamicFlag | IndexedFlag | ReadOnlyFlag | GlobalFlag | ScopedFlag,
        };

        static ResolveResult registerResolve(RegisterID *local, unsigned flags)
        {
            return ResolveResult(Register | flags, local, missingSymbolMarker(), 0, 0);
        }
        static ResolveResult dynamicResolve(size_t depth)
        {
            return ResolveResult(Dynamic, 0, missingSymbolMarker(), depth, 0);
        }
        static ResolveResult lexicalResolve(int index, size_t depth, unsigned flags)
        {
            unsigned type = (flags & DynamicFlag) ? DynamicLexical : Lexical;
            return ResolveResult(type | flags, 0, index, depth, 0);
        }
        static ResolveResult indexedGlobalResolve(int index, JSObject *globalObject, unsigned flags)
        {
            return ResolveResult(IndexedGlobal | flags, 0, index, 0, globalObject);
        }
        static ResolveResult dynamicIndexedGlobalResolve(int index, size_t depth, JSObject *globalObject, unsigned flags)
        {
            return ResolveResult(DynamicIndexedGlobal | flags, 0, index, depth, globalObject);
        }
        static ResolveResult globalResolve(JSObject *globalObject)
        {
            return ResolveResult(Global, 0, missingSymbolMarker(), 0, globalObject);
        }
        static ResolveResult dynamicGlobalResolve(size_t dynamicDepth, JSObject *globalObject)
        {
            return ResolveResult(DynamicGlobal, 0, missingSymbolMarker(), dynamicDepth, globalObject);
        }

        unsigned type() const { return m_type; }
        // Returns the register corresponding to a local variable, or 0 if no
        // such register exists. Registers returned by ResolveResult::local() do
        // not require explicit reference counting.
        RegisterID* local() const { return m_local; }
        int index() const { ASSERT (isIndexed() || isRegister()); return m_index; }
        size_t depth() const { ASSERT(isScoped()); return m_depth; }
        JSObject* globalObject() const { ASSERT(isGlobal()); ASSERT(m_globalObject); return m_globalObject; }

        bool isRegister() const { return m_type & RegisterFlag; }
        bool isDynamic() const { return m_type & DynamicFlag; }
        bool isStatic() const { return m_type & StaticFlag; }
        bool isIndexed() const { return m_type & IndexedFlag; }
        bool isScoped() const { return m_type & ScopedFlag; }
        bool isReadOnly() const { return (m_type & ReadOnlyFlag) && !isDynamic(); }
        bool isGlobal() const { return m_type & GlobalFlag; }

    private:
        ResolveResult(unsigned type, RegisterID* local, int index, size_t depth, JSObject* globalObject)
            : m_type(type)
            , m_index(index)
            , m_local(local)
            , m_depth(depth)
            , m_globalObject(globalObject)
        {
#ifndef NDEBUG
            checkValidity();
#endif
        }

#ifndef NDEBUG
        void checkValidity();
#endif

        unsigned m_type;
        int m_index; // Index in scope, if IndexedFlag is set
        RegisterID* m_local; // Local register, if RegisterFlag is set
        size_t m_depth; // Depth in scope chain, if ScopedFlag is set
        JSObject* m_globalObject; // If GlobalFlag is set.
    };

228 229
    class BytecodeGenerator {
        WTF_MAKE_FAST_ALLOCATED;
230 231 232
    public:
        typedef DeclarationStacks::VarStack VarStack;
        typedef DeclarationStacks::FunctionStack FunctionStack;
233

kevino@webkit.org's avatar
kevino@webkit.org committed
234
        JS_EXPORT_PRIVATE static void setDumpsGeneratedCode(bool dumpsGeneratedCode);
235
        static bool dumpsGeneratedCode();
236

237 238 239
        BytecodeGenerator(ProgramNode*, ScopeChainNode*, SymbolTable*, ProgramCodeBlock*, CompilationKind);
        BytecodeGenerator(FunctionBodyNode*, ScopeChainNode*, SymbolTable*, CodeBlock*, CompilationKind);
        BytecodeGenerator(EvalNode*, ScopeChainNode*, SymbolTable*, EvalCodeBlock*, CompilationKind);
240

241 242
        ~BytecodeGenerator();
        
ap@webkit.org's avatar
ap@webkit.org committed
243 244
        JSGlobalData* globalData() const { return m_globalData; }
        const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; }
245

246 247
        bool isConstructor() { return m_codeBlock->m_isConstructor; }

248
        JSObject* generate();
249

250
        bool isArgumentNumber(const Identifier&, int);
251 252 253

        void setIsNumericCompareFunction(bool isNumericCompareFunction);

254 255
        bool willResolveToArguments(const Identifier&);
        RegisterID* uncheckedRegisterForArguments();
256

257 258 259
        // Resolve an identifier, given the current compile-time scope chain.
        ResolveResult resolve(const Identifier&);
        // Behaves as resolve does, but ignores dynamic scope as
260
        // dynamic scope should not interfere with const initialisation
261
        ResolveResult resolveConstDecl(const Identifier&);
262 263

        // Returns the register storing "this"
264
        RegisterID* thisRegister() { return &m_thisRegister; }
265 266 267 268 269 270 271

        // Returns the next available temporary register. Registers returned by
        // newTemporary require a modified form of reference counting: any
        // register with a refcount of 0 is considered "available", meaning that
        // the next instruction may overwrite it.
        RegisterID* newTemporary();

mjs@apple.com's avatar
mjs@apple.com committed
272 273
        RegisterID* highestUsedRegister();

274 275 276 277 278 279 280 281
        // The same as newTemporary(), but this function returns "suggestion" if
        // "suggestion" is a temporary. This function is helpful in situations
        // where you've put "suggestion" in a RefPtr, but you'd like to allow
        // the next instruction to overwrite it anyway.
        RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); }

        // Functions for handling of dst register

282 283
        RegisterID* ignoredResult() { return &m_ignoredResultRegister; }

284
        // Returns a place to write intermediate values of an operation
285
        // which reuses dst if it is safe to do so.
286 287 288 289
        RegisterID* tempDestination(RegisterID* dst)
        {
            return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary();
        }
290 291

        // Returns the place to write the final output of an operation.
292 293
        RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0)
        {
294
            if (originalDst && originalDst != ignoredResult())
295
                return originalDst;
296
            ASSERT(tempDst != ignoredResult());
297 298
            if (tempDst && tempDst->isTemporary())
                return tempDst;
299
            return newTemporary();
300
        }
301

302 303 304 305 306 307 308 309 310 311 312
        // Returns the place to write the final output of an operation.
        RegisterID* finalDestinationOrIgnored(RegisterID* originalDst, RegisterID* tempDst = 0)
        {
            if (originalDst)
                return originalDst;
            ASSERT(tempDst != ignoredResult());
            if (tempDst && tempDst->isTemporary())
                return tempDst;
            return newTemporary();
        }

313 314
        RegisterID* destinationForAssignResult(RegisterID* dst)
        {
315
            if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain())
316 317 318 319
                return dst->isTemporary() ? dst : newTemporary();
            return 0;
        }

320 321 322 323 324
        // Moves src to dst if dst is not null and is different from src, otherwise just returns src.
        RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src)
        {
            return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src;
        }
325

326
        PassRefPtr<LabelScope> newLabelScope(LabelScope::Type, const Identifier* = 0);
327
        PassRefPtr<Label> newLabel();
328

329
        // The emitNode functions are just syntactic sugar for calling
330 331 332 333
        // Node::emitCode. These functions accept a 0 for the register,
        // meaning that the node should allocate a register, or ignoredResult(),
        // meaning that the node need not put the result in a register.
        // Other emit functions do not accept 0 or ignoredResult().
334 335
        RegisterID* emitNode(RegisterID* dst, Node* n)
        {
336
            // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
337
            ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount());
338
            addLineInfo(n->lineNo());
339 340 341
            return m_stack.recursionCheck()
                ? n->emitBytecode(*this, dst)
                : emitThrowExpressionTooDeepException();
342 343 344 345 346 347 348
        }

        RegisterID* emitNode(Node* n)
        {
            return emitNode(0, n);
        }

349 350
        void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue)
        {
351
            addLineInfo(n->lineNo());
352 353 354
            if (m_stack.recursionCheck())
                n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue);
            else
355 356 357
                emitThrowExpressionTooDeepException();
        }

358
        void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset)
359 360 361 362
        {
            if (!m_shouldEmitRichSourceInfo)
                return;

363
            divot -= m_codeBlock->sourceOffset();
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
            if (divot > ExpressionRangeInfo::MaxDivot) {
                // Overflow has occurred, we can only give line number info for errors for this region
                divot = 0;
                startOffset = 0;
                endOffset = 0;
            } else if (startOffset > ExpressionRangeInfo::MaxOffset) {
                // If the start offset is out of bounds we clear both offsets
                // so we only get the divot marker.  Error message will have to be reduced
                // to line and column number.
                startOffset = 0;
                endOffset = 0;
            } else if (endOffset > ExpressionRangeInfo::MaxOffset) {
                // The end offset is only used for additional context, and is much more likely
                // to overflow (eg. function call arguments) so we are willing to drop it without
                // dropping the rest of the range.
                endOffset = 0;
            }
            
            ExpressionRangeInfo info;
            info.instructionOffset = instructions().size();
            info.divotPoint = divot;
            info.startOffset = startOffset;
            info.endOffset = endOffset;
387
            m_codeBlock->addExpressionInfo(info);
388
        }
389

390
        ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure)
391
        {
392
            return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure;
393 394
        }

395
        ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure)
396
        {
397
            if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) {
398 399 400 401
                PassRefPtr<RegisterID> dst = newTemporary();
                emitNode(dst.get(), n);
                return dst;
            }
402

403
            return emitNode(n);
404 405 406 407
        }

        RegisterID* emitLoad(RegisterID* dst, bool);
        RegisterID* emitLoad(RegisterID* dst, double);
408
        RegisterID* emitLoad(RegisterID* dst, const Identifier&);
ggaren@apple.com's avatar
ggaren@apple.com committed
409
        RegisterID* emitLoad(RegisterID* dst, JSValue);
410

411
        RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
412 413 414
        RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes);
        RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2);
        RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src);
415

weinig@apple.com's avatar
weinig@apple.com committed
416
        RegisterID* emitNewObject(RegisterID* dst);
417
        RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
418

419
        RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body);
420 421
        RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body);
        RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index, bool shouldNullCheck);
422
        RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
423
        RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
424 425 426

        RegisterID* emitMove(RegisterID* dst, RegisterID* src);

427
        RegisterID* emitToJSNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_jsnumber, dst, src); }
428 429 430 431
        RegisterID* emitPreInc(RegisterID* srcDst);
        RegisterID* emitPreDec(RegisterID* srcDst);
        RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst);
        RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst);
432

433
        void emitCheckHasInstance(RegisterID* base);
434
        RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype);
435
        RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
436
        RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
437

438 439
        RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&);
        RegisterID* emitPutStaticVar(const ResolveResult&, RegisterID* value);
440

441 442 443 444 445
        RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property);
        RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property);
        RegisterID* emitResolveBaseForPut(RegisterID* dst, const ResolveResult&, const Identifier& property);
        RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
        RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const ResolveResult&, const Identifier& property);
446

447 448
        void emitMethodCheck();

449
        RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
450
        RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base);
451
        RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
452
        RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value);
453 454
        RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
        RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
455
        RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
456 457 458
        RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
        RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
        RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
barraclough@apple.com's avatar
barraclough@apple.com committed
459
        void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter);
460

461 462
        RegisterID* emitCall(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
        RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
463
        RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, RegisterID* profileHookRegister, unsigned divot, unsigned startOffset, unsigned endOffset);
464
        RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* args);
465

466
        RegisterID* emitReturn(RegisterID* src);
467
        RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
468

469
        RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
470 471
        RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count);
        void emitToPrimitive(RegisterID* dst, RegisterID* src);
472

473
        PassRefPtr<Label> emitLabel(Label*);
474
        void emitLoopHint();
475 476 477
        PassRefPtr<Label> emitJump(Label* target);
        PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target);
        PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target);
478
        PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target);
479
        PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target);
480
        PassRefPtr<Label> emitJumpScopes(Label* target, int targetScopeDepth);
481

482
        PassRefPtr<Label> emitJumpSubroutine(RegisterID* retAddrDst, Label*);
483
        void emitSubroutineReturn(RegisterID* retAddrSrc);
484

485 486
        RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget);
        RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target);
487

488
        RegisterID* emitCatch(RegisterID*, Label* start, Label* end);
489 490 491 492 493 494
        void emitThrow(RegisterID* exc)
        { 
            m_usesExceptions = true;
            emitUnaryNoDstOp(op_throw, exc);
        }

495 496
        void emitThrowReferenceError(const UString& message);

497
        void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value);
498

499 500
        RegisterID* emitPushScope(RegisterID* scope);
        void emitPopScope();
501

502 503 504
        void emitDebugHook(DebugHookID, int firstLine, int lastLine);

        int scopeDepth() { return m_dynamicScopeDepth + m_finallyDepth; }
505
        bool hasFinaliser() { return m_finallyDepth != 0; }
506

507
        void pushFinallyContext(Label* target, RegisterID* returnAddrDst);
508
        void popFinallyContext();
509

510 511 512 513 514 515 516 517 518 519 520
        void pushOptimisedForIn(RegisterID* expectedBase, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister)
        {
            ForInContext context = { expectedBase, iter, index, propertyRegister };
            m_forInContextStack.append(context);
        }

        void popOptimisedForIn()
        {
            m_forInContextStack.removeLast();
        }

521 522
        LabelScope* breakTarget(const Identifier&);
        LabelScope* continueTarget(const Identifier&);
523

oliver@apple.com's avatar
oliver@apple.com committed
524
        void beginSwitch(RegisterID*, SwitchInfo::SwitchType);
525
        void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range);
oliver@apple.com's avatar
oliver@apple.com committed
526

527
        CodeType codeType() const { return m_codeType; }
528

529
        bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
530 531
        
        bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
532 533
        
        ScopeChainNode* scopeChain() const { return m_scopeChain.get(); }
534

535
    private:
536 537
        friend class Label;
        
538
        void emitOpcode(OpcodeID);
539
        ValueProfile* emitProfiledOpcode(OpcodeID);
540
        void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
541
        void retrieveLastUnaryOp(int& dstIndex, int& srcIndex);
542 543
        ALWAYS_INLINE void rewindBinaryOp();
        ALWAYS_INLINE void rewindUnaryOp();
544

545
        PassRefPtr<Label> emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope);
darin@apple.com's avatar
darin@apple.com committed
546

ggaren@apple.com's avatar
ggaren@apple.com committed
547
        typedef HashMap<double, JSValue> NumberMap;
548
        typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
549
        
550
        RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
551

552
        RegisterID* newRegister();
553

554
        // Adds a var slot and maps it to the name ident in symbolTable().
555 556 557
        RegisterID* addVar(const Identifier& ident, bool isConstant)
        {
            RegisterID* local;
ggaren@apple.com's avatar
ggaren@apple.com committed
558
            addVar(ident, isConstant, local);
559 560
            return local;
        }
561 562

        // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
ggaren@apple.com's avatar
ggaren@apple.com committed
563
        bool addVar(const Identifier&, bool isConstant, RegisterID*&);
564 565 566 567 568 569 570
        
        // Adds an anonymous var slot. To give this slot a name, add it to symbolTable().
        RegisterID* addVar()
        {
            ++m_codeBlock->m_numVars;
            return newRegister();
        }
ggaren@apple.com's avatar
ggaren@apple.com committed
571

572 573
        // Returns the index of the added var.
        int addGlobalVar(const Identifier&, bool isConstant);
574

575
        void addParameter(const Identifier&, int parameterIndex);
576
        
barraclough@apple.com's avatar
barraclough@apple.com committed
577
        void preserveLastVar();
578
        bool shouldAvoidResolveGlobal();
579 580 581 582 583 584

        RegisterID& registerFor(int index)
        {
            if (index >= 0)
                return m_calleeRegisters[index];

585 586
            ASSERT(m_parameters.size());
            return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize];
587
        }
588 589

        unsigned addConstant(const Identifier&);
barraclough@apple.com's avatar
barraclough@apple.com committed
590
        RegisterID* addConstantValue(JSValue);
591
        unsigned addRegExp(RegExp*);
592

593
        unsigned addConstantBuffer(unsigned length);
594
        
595
        FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body)
596
        {
597
            return FunctionExecutable::create(exec, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
598 599
        }

600
        FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
601
        {
602
            return FunctionExecutable::create(*globalData, body->ident(), body->inferredName(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
603 604
        }

605 606
        JSString* addStringConstant(const Identifier&);

607 608 609 610 611 612 613 614
        void addLineInfo(unsigned lineNo)
        {
#if !ENABLE(OPCODE_SAMPLING)
            if (m_shouldEmitRichSourceInfo)
#endif
                m_codeBlock->addLineInfo(instructions().size(), lineNo);
        }

615 616
        RegisterID* emitInitLazyRegister(RegisterID*);

617
        Vector<Instruction>& instructions() { return m_instructions; }
618
        SymbolTable& symbolTable() { return *m_symbolTable; }
619

620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
        bool shouldOptimizeLocals()
        {
            if (m_dynamicScopeDepth)
                return false;

            if (m_codeType != FunctionCode)
                return false;

            return true;
        }

        bool canOptimizeNonLocals()
        {
            if (m_dynamicScopeDepth)
                return false;

            if (m_codeType == EvalCode)
                return false;

            if (m_codeType == FunctionCode && m_codeBlock->usesEval())
                return false;

            return true;
        }
644

darin@apple.com's avatar
darin@apple.com committed
645 646
        RegisterID* emitThrowExpressionTooDeepException();

647
        void createArgumentsIfNecessary();
648
        void createActivationIfNecessary();
649
        RegisterID* createLazyRegisterIfNecessary(RegisterID*);
650 651
        
        Vector<Instruction> m_instructions;
652

653
        bool m_shouldEmitDebugHooks;
ggaren@apple.com's avatar
ggaren@apple.com committed
654
        bool m_shouldEmitProfileHooks;
655
        bool m_shouldEmitRichSourceInfo;
656

657
        Strong<ScopeChainNode> m_scopeChain;
658
        SymbolTable* m_symbolTable;
659

660 661
        ScopeNode* m_scopeNode;
        CodeBlock* m_codeBlock;
662

663 664
        // Some of these objects keep pointers to one another. They are arranged
        // to ensure a sane destruction order that avoids references to freed memory.
665
        HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions;
666
        RegisterID m_ignoredResultRegister;
667
        RegisterID m_thisRegister;
668
        RegisterID* m_activationRegister;
669 670 671 672 673
        SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
        SegmentedVector<RegisterID, 32> m_calleeRegisters;
        SegmentedVector<RegisterID, 32> m_parameters;
        SegmentedVector<Label, 32> m_labels;
        SegmentedVector<LabelScope, 8> m_labelScopes;
barraclough@apple.com's avatar
barraclough@apple.com committed
674
        RefPtr<RegisterID> m_lastVar;
675 676
        int m_finallyDepth;
        int m_dynamicScopeDepth;
677
        int m_baseScopeDepth;
678
        CodeType m_codeType;
679

680
        Vector<ControlFlowContext> m_scopeContextStack;
oliver@apple.com's avatar
oliver@apple.com committed
681
        Vector<SwitchInfo> m_switchContextStack;
682
        Vector<ForInContext> m_forInContextStack;
683

barraclough@apple.com's avatar
barraclough@apple.com committed
684 685
        int m_firstConstantIndex;
        int m_nextConstantOffset;
686
        unsigned m_globalConstantIndex;
687

ggaren@apple.com's avatar
ggaren@apple.com committed
688 689
        int m_globalVarStorageOffset;

690
        bool m_hasCreatedActivation;
691 692 693 694 695 696
        int m_firstLazyFunction;
        int m_lastLazyFunction;
        HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int> > m_lazyFunctions;
        typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap;
        FunctionOffsetMap m_functionOffsets;
        
697 698 699
        // Constant pool
        IdentifierMap m_identifierMap;
        JSValueMap m_jsValueMap;
700 701
        NumberMap m_numberMap;
        IdentifierStringMap m_stringMap;
702

ap@webkit.org's avatar
ap@webkit.org committed
703
        JSGlobalData* m_globalData;
704

705
        OpcodeID m_lastOpcodeID;
706 707 708
#ifndef NDEBUG
        size_t m_lastOpcodePosition;
#endif
709

710
        StackBounds m_stack;
711

712
        bool m_usesExceptions;
713
        bool m_expressionTooDeep;
714 715 716 717
    };

}

718
#endif // BytecodeGenerator_h