DFGByteCodeParser.cpp 161 KB
Newer Older
1
/*
2
 * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
3 4 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
 * 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. 
 */

#include "config.h"
#include "DFGByteCodeParser.h"

#if ENABLE(DFG_JIT)

31
#include "ArrayConstructor.h"
32 33
#include "CallLinkStatus.h"
#include "CodeBlock.h"
34
#include "CodeBlockWithJITType.h"
35
#include "DFGArrayMode.h"
36
#include "DFGCapabilities.h"
37
#include "GetByIdStatus.h"
38
#include "Operations.h"
39
#include "PreciseJumpTargets.h"
40
#include "PutByIdStatus.h"
41
#include "ResolveGlobalStatus.h"
42
#include "StringConstructor.h"
43
#include <wtf/CommaPrinter.h>
44
#include <wtf/HashMap.h>
45
#include <wtf/MathExtras.h>
46 47 48

namespace JSC { namespace DFG {

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 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
class ConstantBufferKey {
public:
    ConstantBufferKey()
        : m_codeBlock(0)
        , m_index(0)
    {
    }
    
    ConstantBufferKey(WTF::HashTableDeletedValueType)
        : m_codeBlock(0)
        , m_index(1)
    {
    }
    
    ConstantBufferKey(CodeBlock* codeBlock, unsigned index)
        : m_codeBlock(codeBlock)
        , m_index(index)
    {
    }
    
    bool operator==(const ConstantBufferKey& other) const
    {
        return m_codeBlock == other.m_codeBlock
            && m_index == other.m_index;
    }
    
    unsigned hash() const
    {
        return WTF::PtrHash<CodeBlock*>::hash(m_codeBlock) ^ m_index;
    }
    
    bool isHashTableDeletedValue() const
    {
        return !m_codeBlock && m_index;
    }
    
    CodeBlock* codeBlock() const { return m_codeBlock; }
    unsigned index() const { return m_index; }
    
private:
    CodeBlock* m_codeBlock;
    unsigned m_index;
};

struct ConstantBufferKeyHash {
    static unsigned hash(const ConstantBufferKey& key) { return key.hash(); }
    static bool equal(const ConstantBufferKey& a, const ConstantBufferKey& b)
    {
        return a == b;
    }
    
    static const bool safeToCompareToEmptyOrDeleted = true;
};

} } // namespace JSC::DFG

namespace WTF {

template<typename T> struct DefaultHash;
template<> struct DefaultHash<JSC::DFG::ConstantBufferKey> {
    typedef JSC::DFG::ConstantBufferKeyHash Hash;
};

template<typename T> struct HashTraits;
template<> struct HashTraits<JSC::DFG::ConstantBufferKey> : SimpleClassHashTraits<JSC::DFG::ConstantBufferKey> { };

} // namespace WTF

namespace JSC { namespace DFG {

119 120 121 122 123
// === ByteCodeParser ===
//
// This class is used to compile the dataflow graph from a CodeBlock.
class ByteCodeParser {
public:
124 125
    ByteCodeParser(Graph& graph)
        : m_globalData(&graph.m_globalData)
126 127
        , m_codeBlock(graph.m_codeBlock)
        , m_profiledBlock(graph.m_profiledBlock)
128
        , m_graph(graph)
fpizlo@apple.com's avatar
fpizlo@apple.com committed
129
        , m_currentBlock(0)
130
        , m_currentIndex(0)
131
        , m_currentProfilingIndex(0)
132
        , m_constantUndefined(UINT_MAX)
133
        , m_constantNull(UINT_MAX)
134
        , m_constantNaN(UINT_MAX)
135
        , m_constant1(UINT_MAX)
136 137 138 139
        , m_constants(m_codeBlock->numberOfConstantRegisters())
        , m_numArguments(m_codeBlock->numParameters())
        , m_numLocals(m_codeBlock->m_numCalleeRegisters)
        , m_preservedVars(m_codeBlock->m_numVars)
140 141
        , m_parameterSlots(0)
        , m_numPassedVarArgs(0)
142
        , m_globalResolveNumber(0)
143 144
        , m_inlineStackTop(0)
        , m_haveBuiltOperandMaps(false)
145
        , m_emptyJSValueIndex(UINT_MAX)
146
        , m_currentInstruction(0)
147
    {
148
        ASSERT(m_profiledBlock);
149
        
150
        for (int i = 0; i < m_codeBlock->m_numVars; ++i)
151
            m_preservedVars.set(i);
152
    }
153
    
154
    // Parse a full CodeBlock of bytecode.
155
    bool parse();
156
    
157
private:
158
    // Just parse from m_currentIndex to the end of the current CodeBlock.
159
    void parseCodeBlock();
160

161
    // Helper for min and max.
162
    bool handleMinMax(bool usesResult, int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis);
163
    
164 165
    // Handle calls. This resolves issues surrounding inlining and intrinsics.
    void handleCall(Interpreter*, Instruction* currentInstruction, NodeType op, CodeSpecializationKind);
166
    void emitFunctionChecks(const CallLinkStatus&, Node* callTarget, int registerOffset, CodeSpecializationKind);
167
    void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind);
fpizlo@apple.com's avatar
fpizlo@apple.com committed
168
    // Handle inlining. Return true if it succeeded, false if we need to plant a call.
169
    bool handleInlining(bool usesResult, Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind);
170
    // Handle setting the result of an intrinsic.
171
    void setIntrinsicResult(bool usesResult, int resultOperand, Node*);
fpizlo@apple.com's avatar
fpizlo@apple.com committed
172
    // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
173
    bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction);
174
    bool handleConstantInternalFunction(bool usesResult, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
175
    Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset);
176
    void handleGetByOffset(
177
        int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber,
178
        PropertyOffset);
179
    void handleGetById(
180
        int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber,
181
        const GetByIdStatus&);
182

183
    Node* getScope(bool skipTop, unsigned skipCount);
184
    
185
    // Convert a set of ResolveOperations into graph nodes
186
    bool parseResolveOperations(SpeculatedType, unsigned identifierNumber, ResolveOperations*, PutToBaseOperation*, Node** base, Node** value);
187

188 189
    // Prepare to parse a block.
    void prepareToParseBlock();
190
    // Parse a single basic block of bytecode instructions.
191
    bool parseBlock(unsigned limit);
192 193
    // Link block successors.
    void linkBlock(BasicBlock*, Vector<BlockIndex>& possibleTargets);
fpizlo@apple.com's avatar
fpizlo@apple.com committed
194
    void linkBlocks(Vector<UnlinkedBlock>& unlinkedBlocks, Vector<BlockIndex>& possibleTargets);
195
    
196
    VariableAccessData* newVariableAccessData(int operand, bool isCaptured)
197 198 199
    {
        ASSERT(operand < FirstConstantRegisterIndex);
        
200
        m_graph.m_variableAccessData.append(VariableAccessData(static_cast<VirtualRegister>(operand), isCaptured));
201 202 203
        return &m_graph.m_variableAccessData.last();
    }
    
204
    // Get/Set the operands/result of a bytecode instruction.
205
    Node* getDirect(int operand)
206 207 208 209
    {
        // Is this a constant?
        if (operand >= FirstConstantRegisterIndex) {
            unsigned constant = operand - FirstConstantRegisterIndex;
210
            ASSERT(constant < m_constants.size());
211 212 213
            return getJSConstant(constant);
        }

214
        ASSERT(operand != JSStack::Callee);
215
        
216
        // Is this an argument?
217
        if (operandIsArgument(operand))
218
            return getArgument(operand);
219

220 221
        // Must be a local.
        return getLocal((unsigned)operand);
222
    }
223
    Node* get(int operand)
fpizlo@apple.com's avatar
fpizlo@apple.com committed
224
    {
225
        if (operand == JSStack::Callee) {
226 227
            if (inlineCallFrame() && inlineCallFrame()->callee)
                return cellConstant(inlineCallFrame()->callee.get());
228 229 230 231
            
            return getCallee();
        }
        
fpizlo@apple.com's avatar
fpizlo@apple.com committed
232 233
        return getDirect(m_inlineStackTop->remapOperand(operand));
    }
234
    enum SetMode { NormalSet, SetOnEntry };
235
    void setDirect(int operand, Node* value, SetMode setMode = NormalSet)
236 237
    {
        // Is this an argument?
238
        if (operandIsArgument(operand)) {
239
            setArgument(operand, value, setMode);
240
            return;
241 242
        }

243
        // Must be a local.
244
        setLocal((unsigned)operand, value, setMode);
245
    }
246
    void set(int operand, Node* value, SetMode setMode = NormalSet)
fpizlo@apple.com's avatar
fpizlo@apple.com committed
247
    {
248
        setDirect(m_inlineStackTop->remapOperand(operand), value, setMode);
fpizlo@apple.com's avatar
fpizlo@apple.com committed
249
    }
250
    
251
    void setPair(int operand1, Node* value1, int operand2, Node* value2)
252 253 254 255 256 257 258 259 260 261
    {
        // First emit dead SetLocals for the benefit of OSR.
        set(operand1, value1);
        set(operand2, value2);
        
        // Now emit the real SetLocals.
        set(operand1, value1);
        set(operand2, value2);
    }
    
262
    Node* injectLazyOperandSpeculation(Node* node)
263
    {
264 265
        ASSERT(node->op() == GetLocal);
        ASSERT(node->codeOrigin.bytecodeIndex == m_currentIndex);
266
        SpeculatedType prediction = 
267
            m_inlineStackTop->m_lazyOperands.prediction(
268
                LazyOperandValueProfileKey(m_currentIndex, node->local()));
269
#if DFG_ENABLE(DEBUG_VERBOSE)
270
        dataLog("Lazy operand [@", node->index(), ", bc#", m_currentIndex, ", r", node->local(), "] prediction: ", SpeculationDump(prediction), "\n");
271
#endif
272 273
        node->variableAccessData()->predict(prediction);
        return node;
274
    }
275

276
    // Used in implementing get/set, above, where the operand is a local variable.
277
    Node* getLocal(unsigned operand)
278
    {
279
        Node* node = m_currentBlock->variablesAtTail.local(operand);
280
        bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame());
fpizlo@apple.com's avatar
fpizlo@apple.com committed
281
        
282 283 284 285 286 287 288 289
        // This has two goals: 1) link together variable access datas, and 2)
        // try to avoid creating redundant GetLocals. (1) is required for
        // correctness - no other phase will ensure that block-local variable
        // access data unification is done correctly. (2) is purely opportunistic
        // and is meant as an compile-time optimization only.
        
        VariableAccessData* variable;
        
290
        if (node) {
291 292
            variable = node->variableAccessData();
            variable->mergeIsCaptured(isCaptured);
293
            
294 295 296 297 298 299 300 301 302
            if (!isCaptured) {
                switch (node->op()) {
                case GetLocal:
                    return node;
                case SetLocal:
                    return node->child1().node();
                default:
                    break;
                }
303 304 305 306
            }
        } else {
            m_preservedVars.set(operand);
            variable = newVariableAccessData(operand, isCaptured);
307
        }
308
        
309
        node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable)));
310 311
        m_currentBlock->variablesAtTail.local(operand) = node;
        return node;
312
    }
313
    void setLocal(unsigned operand, Node* value, SetMode setMode = NormalSet)
314
    {
315
        bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame());
316
        
317 318 319 320 321 322
        if (setMode == NormalSet) {
            ArgumentPosition* argumentPosition = findArgumentPositionForLocal(operand);
            if (isCaptured || argumentPosition)
                flushDirect(operand, argumentPosition);
        }

323
        VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
324 325
        variableAccessData->mergeStructureCheckHoistingFailed(
            m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
326 327
        Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value);
        m_currentBlock->variablesAtTail.local(operand) = node;
328 329 330
    }

    // Used in implementing get/set, above, where the operand is an argument.
331
    Node* getArgument(unsigned operand)
332
    {
333
        unsigned argument = operandToArgument(operand);
334
        ASSERT(argument < m_numArguments);
335
        
336
        Node* node = m_currentBlock->variablesAtTail.argument(argument);
337
        bool isCaptured = m_codeBlock->isCaptured(operand);
338

339 340
        VariableAccessData* variable;
        
341
        if (node) {
342 343
            variable = node->variableAccessData();
            variable->mergeIsCaptured(isCaptured);
344
            
345 346
            switch (node->op()) {
            case GetLocal:
347
                return node;
348 349 350 351
            case SetLocal:
                return node->child1().node();
            default:
                break;
352
            }
353 354
        } else
            variable = newVariableAccessData(operand, isCaptured);
355
        
356
        node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable)));
357 358
        m_currentBlock->variablesAtTail.argument(argument) = node;
        return node;
359
    }
360
    void setArgument(int operand, Node* value, SetMode setMode = NormalSet)
361
    {
362
        unsigned argument = operandToArgument(operand);
363
        ASSERT(argument < m_numArguments);
364
        
365 366
        bool isCaptured = m_codeBlock->isCaptured(operand);

367
        VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
368 369 370 371 372 373 374 375 376

        // Always flush arguments, except for 'this'. If 'this' is created by us,
        // then make sure that it's never unboxed.
        if (argument) {
            if (setMode == NormalSet)
                flushDirect(operand);
        } else if (m_codeBlock->specializationKind() == CodeForConstruct)
            variableAccessData->mergeShouldNeverUnbox(true);
        
377 378
        variableAccessData->mergeStructureCheckHoistingFailed(
            m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
379 380
        Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value);
        m_currentBlock->variablesAtTail.argument(argument) = node;
381
    }
fpizlo@apple.com's avatar
fpizlo@apple.com committed
382
    
383 384 385 386 387 388 389 390 391 392 393 394 395 396
    ArgumentPosition* findArgumentPositionForArgument(int argument)
    {
        InlineStackEntry* stack = m_inlineStackTop;
        while (stack->m_inlineCallFrame)
            stack = stack->m_caller;
        return stack->m_argumentPositions[argument];
    }
    
    ArgumentPosition* findArgumentPositionForLocal(int operand)
    {
        for (InlineStackEntry* stack = m_inlineStackTop; ; stack = stack->m_caller) {
            InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame;
            if (!inlineCallFrame)
                break;
397
            if (operand >= static_cast<int>(inlineCallFrame->stackOffset - JSStack::CallFrameHeaderSize))
398 399 400
                continue;
            if (operand == inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset())
                continue;
401
            if (operand < static_cast<int>(inlineCallFrame->stackOffset - JSStack::CallFrameHeaderSize - inlineCallFrame->arguments.size()))
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
                continue;
            int argument = operandToArgument(operand - inlineCallFrame->stackOffset);
            return stack->m_argumentPositions[argument];
        }
        return 0;
    }
    
    ArgumentPosition* findArgumentPosition(int operand)
    {
        if (operandIsArgument(operand))
            return findArgumentPositionForArgument(operandToArgument(operand));
        return findArgumentPositionForLocal(operand);
    }
    
    void flush(int operand)
    {
        flushDirect(m_inlineStackTop->remapOperand(operand));
    }
    
    void flushDirect(int operand)
    {
        flushDirect(operand, findArgumentPosition(operand));
    }
    
    void flushDirect(int operand, ArgumentPosition* argumentPosition)
fpizlo@apple.com's avatar
fpizlo@apple.com committed
427
    {
428
        bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame());
fpizlo@apple.com's avatar
fpizlo@apple.com committed
429 430 431
        
        ASSERT(operand < FirstConstantRegisterIndex);
        
432
        if (!operandIsArgument(operand))
fpizlo@apple.com's avatar
fpizlo@apple.com committed
433
            m_preservedVars.set(operand);
434 435 436 437
        
        Node* node = m_currentBlock->variablesAtTail.operand(operand);
        
        VariableAccessData* variable;
fpizlo@apple.com's avatar
fpizlo@apple.com committed
438
        
439
        if (node) {
440 441 442 443
            variable = node->variableAccessData();
            variable->mergeIsCaptured(isCaptured);
        } else
            variable = newVariableAccessData(operand, isCaptured);
fpizlo@apple.com's avatar
fpizlo@apple.com committed
444
        
445 446
        node = addToGraph(Flush, OpInfo(variable));
        m_currentBlock->variablesAtTail.operand(operand) = node;
447
        if (argumentPosition)
448
            argumentPosition->addVariable(variable);
449 450 451 452 453
    }
    
    void flushArgumentsAndCapturedVariables()
    {
        int numArguments;
454 455
        if (inlineCallFrame())
            numArguments = inlineCallFrame()->arguments.size();
456 457 458 459
        else
            numArguments = m_inlineStackTop->m_codeBlock->numParameters();
        for (unsigned argument = numArguments; argument-- > 1;)
            flush(argumentToOperand(argument));
460 461 462
        for (int local = 0; local < m_inlineStackTop->m_codeBlock->m_numVars; ++local) {
            if (!m_inlineStackTop->m_codeBlock->isCaptured(local))
                continue;
463
            flush(local);
464
        }
fpizlo@apple.com's avatar
fpizlo@apple.com committed
465
    }
466 467

    // Get an operand, and perform a ToInt32/ToNumber conversion on it.
468
    Node* getToInt32(int operand)
469 470 471 472 473
    {
        return toInt32(get(operand));
    }

    // Perform an ES5 ToInt32 operation - returns a node of type NodeResultInt32.
474
    Node* toInt32(Node* node)
475
    {
476 477
        if (node->hasInt32Result())
            return node;
478

479 480
        if (node->op() == UInt32ToNumber)
            return node->child1().node();
481 482

        // Check for numeric constants boxed as JSValues.
483
        if (canFold(node)) {
484
            JSValue v = valueOfJSConstant(node);
485
            if (v.isInt32())
486
                return getJSConstant(node->constantNumber());
487 488
            if (v.isNumber())
                return getJSConstantForValue(JSValue(JSC::toInt32(v.asNumber())));
489 490
        }

491
        return addToGraph(ValueToInt32, node);
492 493
    }

494 495 496 497
    // NOTE: Only use this to construct constants that arise from non-speculative
    // constant folding. I.e. creating constants using this if we had constant
    // field inference would be a bad idea, since the bytecode parser's folding
    // doesn't handle liveness preservation.
498
    Node* getJSConstantForValue(JSValue constantValue)
499 500 501 502 503 504 505 506 507
    {
        unsigned constantIndex = m_codeBlock->addOrFindConstant(constantValue);
        if (constantIndex >= m_constants.size())
            m_constants.append(ConstantRecord());
        
        ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
        
        return getJSConstant(constantIndex);
    }
508

509
    Node* getJSConstant(unsigned constant)
510
    {
511 512 513
        Node* node = m_constants[constant].asJSValue;
        if (node)
            return node;
514

515 516 517
        Node* result = addToGraph(JSConstant, OpInfo(constant));
        m_constants[constant].asJSValue = result;
        return result;
518 519
    }

520
    Node* getCallee()
521 522 523 524
    {
        return addToGraph(GetCallee);
    }

525
    // Helper functions to get/set the this value.
526
    Node* getThis()
527
    {
528
        return get(m_inlineStackTop->m_codeBlock->thisRegister());
529
    }
530
    void setThis(Node* value)
531
    {
532
        set(m_inlineStackTop->m_codeBlock->thisRegister(), value);
533 534 535
    }

    // Convenience methods for checking nodes for constants.
536
    bool isJSConstant(Node* node)
537
    {
538
        return node->op() == JSConstant;
539
    }
540
    bool isInt32Constant(Node* node)
541
    {
542
        return isJSConstant(node) && valueOfJSConstant(node).isInt32();
543
    }
544
    // Convenience methods for getting constant values.
545
    JSValue valueOfJSConstant(Node* node)
546
    {
547 548
        ASSERT(isJSConstant(node));
        return m_codeBlock->getConstant(FirstConstantRegisterIndex + node->constantNumber());
549
    }
550
    int32_t valueOfInt32Constant(Node* node)
551
    {
552 553
        ASSERT(isInt32Constant(node));
        return valueOfJSConstant(node).asInt32();
554
    }
555
    
556
    // This method returns a JSConstant with the value 'undefined'.
557
    Node* constantUndefined()
558 559 560 561 562 563 564 565 566 567 568
    {
        // Has m_constantUndefined been set up yet?
        if (m_constantUndefined == UINT_MAX) {
            // Search the constant pool for undefined, if we find it, we can just reuse this!
            unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
            for (m_constantUndefined = 0; m_constantUndefined < numberOfConstants; ++m_constantUndefined) {
                JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined);
                if (testMe.isUndefined())
                    return getJSConstant(m_constantUndefined);
            }

569 570
            // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constants.
            ASSERT(m_constants.size() == numberOfConstants);
571
            m_codeBlock->addConstant(jsUndefined());
572 573
            m_constants.append(ConstantRecord());
            ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
574 575 576 577 578 579 580
        }

        // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'.
        ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined).isUndefined());
        return getJSConstant(m_constantUndefined);
    }

581
    // This method returns a JSConstant with the value 'null'.
582
    Node* constantNull()
583 584 585 586 587 588 589 590 591 592 593
    {
        // Has m_constantNull been set up yet?
        if (m_constantNull == UINT_MAX) {
            // Search the constant pool for null, if we find it, we can just reuse this!
            unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
            for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) {
                JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull);
                if (testMe.isNull())
                    return getJSConstant(m_constantNull);
            }

594 595
            // Add null to the CodeBlock's constants, and add a corresponding slot in m_constants.
            ASSERT(m_constants.size() == numberOfConstants);
596
            m_codeBlock->addConstant(jsNull());
597 598
            m_constants.append(ConstantRecord());
            ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
599 600 601 602 603 604 605
        }

        // m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'.
        ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull());
        return getJSConstant(m_constantNull);
    }

606
    // This method returns a DoubleConstant with the value 1.
607
    Node* one()
608 609 610 611 612 613 614 615
    {
        // Has m_constant1 been set up yet?
        if (m_constant1 == UINT_MAX) {
            // Search the constant pool for the value 1, if we find it, we can just reuse this!
            unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
            for (m_constant1 = 0; m_constant1 < numberOfConstants; ++m_constant1) {
                JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1);
                if (testMe.isInt32() && testMe.asInt32() == 1)
616
                    return getJSConstant(m_constant1);
617 618
            }

619 620
            // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constants.
            ASSERT(m_constants.size() == numberOfConstants);
621
            m_codeBlock->addConstant(jsNumber(1));
622 623
            m_constants.append(ConstantRecord());
            ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
624 625 626 627 628
        }

        // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1.
        ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).isInt32());
        ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).asInt32() == 1);
629
        return getJSConstant(m_constant1);
630
    }
631
    
632
    // This method returns a DoubleConstant with the value NaN.
633
    Node* constantNaN()
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
    {
        JSValue nan = jsNaN();
        
        // Has m_constantNaN been set up yet?
        if (m_constantNaN == UINT_MAX) {
            // Search the constant pool for the value NaN, if we find it, we can just reuse this!
            unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
            for (m_constantNaN = 0; m_constantNaN < numberOfConstants; ++m_constantNaN) {
                JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN);
                if (JSValue::encode(testMe) == JSValue::encode(nan))
                    return getJSConstant(m_constantNaN);
            }

            // Add the value nan to the CodeBlock's constants, and add a corresponding slot in m_constants.
            ASSERT(m_constants.size() == numberOfConstants);
            m_codeBlock->addConstant(nan);
            m_constants.append(ConstantRecord());
            ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
        }

        // m_constantNaN must refer to an entry in the CodeBlock's constant pool that has the value nan.
        ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).isDouble());
656
        ASSERT(std::isnan(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).asDouble()));
657 658 659
        return getJSConstant(m_constantNaN);
    }
    
660
    Node* cellConstant(JSCell* cell)
661
    {
662
        HashMap<JSCell*, Node*>::AddResult result = m_cellConstantNodes.add(cell, 0);
663
        if (result.isNewEntry)
664
            result.iterator->value = addToGraph(WeakJSConstant, OpInfo(cell));
665
        
666
        return result.iterator->value;
667 668
    }
    
669
    InlineCallFrame* inlineCallFrame()
670
    {
671
        return m_inlineStackTop->m_inlineCallFrame;
672
    }
673

674 675 676 677 678 679 680 681 682 683
    CodeOrigin currentCodeOrigin()
    {
        return CodeOrigin(m_currentIndex, inlineCallFrame(), m_currentProfilingIndex - m_currentIndex);
    }
    
    bool canFold(Node* node)
    {
        return node->isStronglyProvedConstantIn(inlineCallFrame());
    }
    
684 685 686 687 688 689 690 691
    bool isConstantForCompareStrictEq(Node* node)
    {
        if (!node->isConstant())
            return false;
        JSValue value = valueOfJSConstant(node);
        return value.isBoolean() || value.isUndefinedOrNull();
    }
    
692
    Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
693 694
    {
        Node* result = m_graph.addNode(
695
            SpecNone, op, currentCodeOrigin(), Edge(child1), Edge(child2), Edge(child3));
696 697 698 699 700
        ASSERT(op != Phi);
        m_currentBlock->append(result);
        return result;
    }
    Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
701
    {
702
        Node* result = m_graph.addNode(
703
            SpecNone, op, currentCodeOrigin(), child1, child2, child3);
704
        ASSERT(op != Phi);
705 706
        m_currentBlock->append(result);
        return result;
707
    }
708
    Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
709
    {
710
        Node* result = m_graph.addNode(
711
            SpecNone, op, currentCodeOrigin(), info, Edge(child1), Edge(child2), Edge(child3));
712 713
        ASSERT(op != Phi);
        m_currentBlock->append(result);
714
        return result;
715
    }
716
    Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
717
    {
718
        Node* result = m_graph.addNode(
719 720
            SpecNone, op, currentCodeOrigin(), info1, info2,
            Edge(child1), Edge(child2), Edge(child3));
721
        ASSERT(op != Phi);
722 723
        m_currentBlock->append(result);
        return result;
724
    }
725
    
726
    Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
727
    {
728
        Node* result = m_graph.addNode(
729
            SpecNone, Node::VarArg, op, currentCodeOrigin(), info1, info2,
730
            m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs);
731
        ASSERT(op != Phi);
732
        m_currentBlock->append(result);
733 734 735
        
        m_numPassedVarArgs = 0;
        
736
        return result;
737
    }
738

739
    void addVarArgChild(Node* child)
740
    {
741
        m_graph.m_varArgChildren.append(Edge(child));
742 743
        m_numPassedVarArgs++;
    }
744
    
745
    Node* addCall(Interpreter* interpreter, Instruction* currentInstruction, NodeType op)
746
    {
747 748
        Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call);

749
        SpeculatedType prediction = SpecNone;
750 751
        if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) {
            m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call);
752
            prediction = getPrediction();
753
        }
754
        
755 756
        addVarArgChild(get(currentInstruction[1].u.operand));
        int argCount = currentInstruction[2].u.operand;
757 758
        if (JSStack::CallFrameHeaderSize + (unsigned)argCount > m_parameterSlots)
            m_parameterSlots = JSStack::CallFrameHeaderSize + argCount;
759

760
        int registerOffset = currentInstruction[3].u.operand;
761 762 763 764
        int dummyThisArgument = op == Call ? 0 : 1;
        for (int i = 0 + dummyThisArgument; i < argCount; ++i)
            addVarArgChild(get(registerOffset + argumentToOperand(i)));

765
        Node* call = addToGraph(Node::VarArg, op, OpInfo(0), OpInfo(prediction));
766
        if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result)
767 768 769
            set(putInstruction[1].u.operand, call);
        return call;
    }
770
    
771
    Node* addStructureTransitionCheck(JSCell* object, Structure* structure)
772 773 774
    {
        // Add a weak JS constant for the object regardless, since the code should
        // be jettisoned if the object ever dies.
775
        Node* objectNode = cellConstant(object);
776 777
        
        if (object->structure() == structure && structure->transitionWatchpointSetIsStillValid()) {
778 779
            addToGraph(StructureTransitionWatchpoint, OpInfo(structure), objectNode);
            return objectNode;
780 781
        }
        
782
        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), objectNode);
783
        
784
        return objectNode;
785 786
    }
    
787
    Node* addStructureTransitionCheck(JSCell* object)
788 789
    {
        return addStructureTransitionCheck(object, object->structure());
790 791
    }
    
792
    SpeculatedType getPredictionWithoutOSRExit(unsigned bytecodeIndex)
793
    {
794
        return m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex);
795 796
    }

797
    SpeculatedType getPrediction(unsigned bytecodeIndex)