text: // Copyright 2006-2008 the V8 project authors. All rights reserved.
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  //     * Redistributions of source code must retain the above copyright
  //       notice, this list of conditions and the following disclaimer.
  //     * 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.
  //     * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
  // OWNER 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.
  
  #ifndef V8_CODEGEN_H_
  #define V8_CODEGEN_H_
  
  #include "code-stubs.h"
  #include "runtime.h"
  #include "type-info.h"
  
  // Include the declaration of the architecture defined class CodeGenerator.
  // The contract  to the shared code is that the the CodeGenerator is a subclass
  // of Visitor and that the following methods are available publicly:
  //   MakeCode
  //   MakeCodePrologue
  //   MakeCodeEpilogue
  //   masm
  //   frame
  //   script
  //   has_valid_frame
  //   SetFrame
  //   DeleteFrame
  //   allocator
  //   AddDeferred
  //   in_spilled_code
  //   set_in_spilled_code
  //   RecordPositions
  //
  // These methods are either used privately by the shared code or implemented as
  // shared code:
  //   CodeGenerator
  //   ~CodeGenerator
  //   ProcessDeferred
  //   Generate
  //   ComputeLazyCompile
  //   BuildFunctionInfo
  //   ComputeCallInitialize
  //   ComputeCallInitializeInLoop
  //   ProcessDeclarations
  //   DeclareGlobals
  //   FindInlineRuntimeLUT
  //   CheckForInlineRuntimeCall
  //   PatchInlineRuntimeEntry
  //   AnalyzeCondition
  //   CodeForFunctionPosition
  //   CodeForReturnPosition
  //   CodeForStatementPosition
  //   CodeForDoWhileConditionPosition
  //   CodeForSourcePosition
  
  
  // Mode to overwrite BinaryExpression values.
  enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
  
  // Types of uncatchable exceptions.
  enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
  
  
  #if V8_TARGET_ARCH_IA32
  #include "ia32/codegen-ia32.h"
  #elif V8_TARGET_ARCH_X64
  #include "x64/codegen-x64.h"
  #elif V8_TARGET_ARCH_ARM
  #include "arm/codegen-arm.h"
  #elif V8_TARGET_ARCH_MIPS
  #include "mips/codegen-mips.h"
  #else
  #error Unsupported target architecture.
  #endif
  
  #include "register-allocator.h"
  
  namespace v8 {
  namespace internal {
  
  
  #define INLINE_RUNTIME_FUNCTION_LIST(F) \
    F(IsSmi, 1, 1)                                                             \
    F(IsNonNegativeSmi, 1, 1)                                                  \
    F(IsArray, 1, 1)                                                           \
    F(IsRegExp, 1, 1)                                                          \
    F(CallFunction, -1 /* receiver + n args + function */, 1)                  \
    F(IsConstructCall, 0, 1)                                                   \
    F(ArgumentsLength, 0, 1)                                                   \
    F(Arguments, 1, 1)                                                         \
    F(ClassOf, 1, 1)                                                           \
    F(ValueOf, 1, 1)                                                           \
    F(SetValueOf, 2, 1)                                                        \
    F(FastCharCodeAt, 2, 1)                                                    \
    F(CharFromCode, 1, 1)                                                      \
    F(ObjectEquals, 2, 1)                                                      \
    F(Log, 3, 1)                                                               \
    F(RandomHeapNumber, 0, 1)                                                  \
    F(IsObject, 1, 1)                                                          \
    F(IsFunction, 1, 1)                                                        \
    F(IsUndetectableObject, 1, 1)                                              \
    F(StringAdd, 2, 1)                                                         \
    F(SubString, 3, 1)                                                         \
    F(StringCompare, 2, 1)                                                     \
    F(RegExpExec, 4, 1)                                                        \
    F(RegExpConstructResult, 3, 1)                                             \
    F(GetFromCache, 2, 1)                                                      \
    F(NumberToString, 1, 1)                                                    \
    F(SwapElements, 3, 1)                                                      \
    F(MathPow, 2, 1)                                                           \
    F(MathSin, 1, 1)                                                           \
    F(MathCos, 1, 1)                                                           \
    F(MathSqrt, 1, 1)
  
  
  // Support for "structured" code comments.
  #ifdef DEBUG
  
  class Comment BASE_EMBEDDED {
   public:
    Comment(MacroAssembler* masm, const char* msg);
    ~Comment();
  
   private:
    MacroAssembler* masm_;
    const char* msg_;
  };
  
  #else
  
  class Comment BASE_EMBEDDED {
   public:
    Comment(MacroAssembler*, const char*)  {}
  };
  
  #endif  // DEBUG
  
  
  // Code generation can be nested.  Code generation scopes form a stack
  // of active code generators.
  class CodeGeneratorScope BASE_EMBEDDED {
   public:
    explicit CodeGeneratorScope(CodeGenerator* cgen) {
      previous_ = top_;
      top_ = cgen;
    }
  
    ~CodeGeneratorScope() {
      top_ = previous_;
    }
  
    static CodeGenerator* Current() {
      ASSERT(top_ != NULL);
      return top_;
    }
  
   private:
    static CodeGenerator* top_;
    CodeGenerator* previous_;
  };
  
  
  // Deferred code objects are small pieces of code that are compiled
  // out of line. They are used to defer the compilation of uncommon
  // paths thereby avoiding expensive jumps around uncommon code parts.
  class DeferredCode: public ZoneObject {
   public:
    DeferredCode();
    virtual ~DeferredCode() { }
  
    virtual void Generate() = 0;
  
    MacroAssembler* masm() { return masm_; }
  
    int statement_position() const { return statement_position_; }
    int position() const { return position_; }
  
    Label* entry_label() { return &entry_label_; }
    Label* exit_label() { return &exit_label_; }
  
  #ifdef DEBUG
    void set_comment(const char* comment) { comment_ = comment; }
    const char* comment() const { return comment_; }
  #else
    void set_comment(const char* comment) { }
    const char* comment() const { return ""; }
  #endif
  
    inline void Jump();
    inline void Branch(Condition cc);
    void BindExit() { masm_->bind(&exit_label_); }
  
    void SaveRegisters();
    void RestoreRegisters();
  
   protected:
    MacroAssembler* masm_;
  
   private:
    // Constants indicating special actions.  They should not be multiples
    // of kPointerSize so they will not collide with valid offsets from
    // the frame pointer.
    static const int kIgnore = -1;
    static const int kPush = 1;
  
    // This flag is ored with a valid offset from the frame pointer, so
    // it should fit in the low zero bits of a valid offset.
    static const int kSyncedFlag = 2;
  
    int statement_position_;
    int position_;
  
    Label entry_label_;
    Label exit_label_;
  
    // C++ doesn't allow zero length arrays, so we make the array length 1 even
    // if we don't need it.
    static const int kRegistersArrayLength =
        (RegisterAllocator::kNumRegisters == 0) ?
            1 : RegisterAllocator::kNumRegisters;
    int registers_[kRegistersArrayLength];
  
  #ifdef DEBUG
    const char* comment_;
  #endif
    DISALLOW_COPY_AND_ASSIGN(DeferredCode);
  };
  
  class StackCheckStub : public CodeStub {
   public:
    StackCheckStub() { }
  
    void Generate(MacroAssembler* masm);
  
   private:
  
    const char* GetName() { return "StackCheckStub"; }
  
    Major MajorKey() { return StackCheck; }
    int MinorKey() { return 0; }
  };
  
  
  class FastNewClosureStub : public CodeStub {
   public:
    void Generate(MacroAssembler* masm);
  
   private:
    const char* GetName() { return "FastNewClosureStub"; }
    Major MajorKey() { return FastNewClosure; }
    int MinorKey() { return 0; }
  };
  
  
  class FastNewContextStub : public CodeStub {
   public:
    static const int kMaximumSlots = 64;
  
    explicit FastNewContextStub(int slots) : slots_(slots) {
      ASSERT(slots_ > 0 && slots <= kMaximumSlots);
    }
  
    void Generate(MacroAssembler* masm);
  
   private:
    int slots_;
  
    const char* GetName() { return "FastNewContextStub"; }
    Major MajorKey() { return FastNewContext; }
    int MinorKey() { return slots_; }
  };
  
  
  class FastCloneShallowArrayStub : public CodeStub {
   public:
    static const int kMaximumLength = 8;
  
    explicit FastCloneShallowArrayStub(int length) : length_(length) {
      ASSERT(length >= 0 && length <= kMaximumLength);
    }
  
    void Generate(MacroAssembler* masm);
  
   private:
    int length_;
  
    const char* GetName() { return "FastCloneShallowArrayStub"; }
    Major MajorKey() { return FastCloneShallowArray; }
    int MinorKey() { return length_; }
  };
  
  
  class InstanceofStub: public CodeStub {
   public:
    InstanceofStub() { }
  
    void Generate(MacroAssembler* masm);
  
   private:
    Major MajorKey() { return Instanceof; }
    int MinorKey() { return 0; }
  };
  
  
  class GenericUnaryOpStub : public CodeStub {
   public:
    GenericUnaryOpStub(Token::Value op, bool overwrite)
        : op_(op), overwrite_(overwrite) { }
  
   private:
    Token::Value op_;
    bool overwrite_;
  
    class OverwriteField: public BitField<int, 0, 1> {};
    class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
  
    Major MajorKey() { return GenericUnaryOp; }
    int MinorKey() {
      return OpField::encode(op_) | OverwriteField::encode(overwrite_);
    }
  
    void Generate(MacroAssembler* masm);
  
    const char* GetName();
  };
  
  
  enum NaNInformation {
    kBothCouldBeNaN,
    kCantBothBeNaN
  };
  
  
  class CompareStub: public CodeStub {
   public:
    CompareStub(Condition cc,
                bool strict,
                NaNInformation nan_info = kBothCouldBeNaN,
                bool include_number_compare = true) :
        cc_(cc),
        strict_(strict),
        never_nan_nan_(nan_info == kCantBothBeNaN),
        include_number_compare_(include_number_compare),
        name_(NULL) { }
  
    void Generate(MacroAssembler* masm);
  
   private:
    Condition cc_;
    bool strict_;
    // Only used for 'equal' comparisons.  Tells the stub that we already know
    // that at least one side of the comparison is not NaN.  This allows the
    // stub to use object identity in the positive case.  We ignore it when
    // generating the minor key for other comparisons to avoid creating more
    // stubs.
    bool never_nan_nan_;
    // Do generate the number comparison code in the stub. Stubs without number
    // comparison code is used when the number comparison has been inlined, and
    // the stub will be called if one of the operands is not a number.
    bool include_number_compare_;
  
    // Encoding of the minor key CCCCCCCCCCCCCCNS.
    class StrictField: public BitField<bool, 0, 1> {};
    class NeverNanNanField: public BitField<bool, 1, 1> {};
    class IncludeNumberCompareField: public BitField<bool, 2, 1> {};
    class ConditionField: public BitField<int, 3, 13> {};
  
    Major MajorKey() { return Compare; }
  
    int MinorKey();
  
    // Branch to the label if the given object isn't a symbol.
    void BranchIfNonSymbol(MacroAssembler* masm,
                           Label* label,
                           Register object,
                           Register scratch);
  
    // Unfortunately you have to run without snapshots to see most of these
    // names in the profile since most compare stubs end up in the snapshot.
    char* name_;
    const char* GetName();
  #ifdef DEBUG
    void Print() {
      PrintF("CompareStub (cc %d), (strict %s), "
             "(never_nan_nan %s), (number_compare %s)\n",
             static_cast<int>(cc_),
             strict_ ? "true" : "false",
             never_nan_nan_ ? "true" : "false",
             include_number_compare_ ? "included" : "not included");
    }
  #endif
  };
  
  
  class CEntryStub : public CodeStub {
   public:
    explicit CEntryStub(int result_size,
                        ExitFrame::Mode mode = ExitFrame::MODE_NORMAL)
        : result_size_(result_size), mode_(mode) { }
  
    void Generate(MacroAssembler* masm);
  
   private:
    void GenerateCore(MacroAssembler* masm,
                      Label* throw_normal_exception,
                      Label* throw_termination_exception,
                      Label* throw_out_of_memory_exception,
                      bool do_gc,
                      bool always_allocate_scope,
                      int alignment_skew = 0);
    void GenerateThrowTOS(MacroAssembler* masm);
    void GenerateThrowUncatchable(MacroAssembler* masm,
                                  UncatchableExceptionType type);
  
    // Number of pointers/values returned.
    const int result_size_;
    const ExitFrame::Mode mode_;
  
    // Minor key encoding
    class ExitFrameModeBits: public BitField<ExitFrame::Mode, 0, 1> {};
    class IndirectResultBits: public BitField<bool, 1, 1> {};
  
    Major MajorKey() { return CEntry; }
    // Minor key must differ if different result_size_ values means different
    // code is generated.
    int MinorKey();
  
    const char* GetName() { return "CEntryStub"; }
  };
  
  
  class ApiGetterEntryStub : public CodeStub {
   public:
    ApiGetterEntryStub(Handle<AccessorInfo> info,
                       ApiFunction* fun)
        : info_(info),
          fun_(fun) { }
    void Generate(MacroAssembler* masm);
    virtual bool has_custom_cache() { return true; }
    virtual bool GetCustomCache(Code** code_out);
    virtual void SetCustomCache(Code* value);
  
    static const int kStackSpace = 5;
    static const int kArgc = 4;
   private:
    Handle<AccessorInfo> info() { return info_; }
    ApiFunction* fun() { return fun_; }
    Major MajorKey() { return NoCache; }
    int MinorKey() { return 0; }
    const char* GetName() { return "ApiEntryStub"; }
    // The accessor info associated with the function.
    Handle<AccessorInfo> info_;
    // The function to be called.
    ApiFunction* fun_;
  };
  
  
  class JSEntryStub : public CodeStub {
   public:
    JSEntryStub() { }
  
    void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
  
   protected:
    void GenerateBody(MacroAssembler* masm, bool is_construct);
  
   private:
    Major MajorKey() { return JSEntry; }
    int MinorKey() { return 0; }
  
    const char* GetName() { return "JSEntryStub"; }
  };
  
  
  class JSConstructEntryStub : public JSEntryStub {
   public:
    JSConstructEntryStub() { }
  
    void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
  
   private:
    int MinorKey() { return 1; }
  
    const char* GetName() { return "JSConstructEntryStub"; }
  };
  
  
  class ArgumentsAccessStub: public CodeStub {
   public:
    enum Type {
      READ_ELEMENT,
      NEW_OBJECT
    };
  
    explicit ArgumentsAccessStub(Type type) : type_(type) { }
  
   private:
    Type type_;
  
    Major MajorKey() { return ArgumentsAccess; }
    int MinorKey() { return type_; }
  
    void Generate(MacroAssembler* masm);
    void GenerateReadElement(MacroAssembler* masm);
    void GenerateNewObject(MacroAssembler* masm);
  
    const char* GetName() { return "ArgumentsAccessStub"; }
  
  #ifdef DEBUG
    void Print() {
      PrintF("ArgumentsAccessStub (type %d)\n", type_);
    }
  #endif
  };
  
  
  class RegExpExecStub: public CodeStub {
   public:
    RegExpExecStub() { }
  
   private:
    Major MajorKey() { return RegExpExec; }
    int MinorKey() { return 0; }
  
    void Generate(MacroAssembler* masm);
  
    const char* GetName() { return "RegExpExecStub"; }
  
  #ifdef DEBUG
    void Print() {
      PrintF("RegExpExecStub\n");
    }
  #endif
  };
  
  
  class CallFunctionStub: public CodeStub {
   public:
    CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
        : argc_(argc), in_loop_(in_loop), flags_(flags) { }
  
    void Generate(MacroAssembler* masm);
  
   private:
    int argc_;
    InLoopFlag in_loop_;
    CallFunctionFlags flags_;
  
  #ifdef DEBUG
    void Print() {
      PrintF("CallFunctionStub (args %d, in_loop %d, flags %d)\n",
             argc_,
             static_cast<int>(in_loop_),
             static_cast<int>(flags_));
    }
  #endif
  
    // Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
    class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
    class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
    class ArgcBits: public BitField<int, 2, 32 - 2> {};
  
    Major MajorKey() { return CallFunction; }
    int MinorKey() {
      // Encode the parameters in a unique 32 bit value.
      return InLoopBits::encode(in_loop_)
             | FlagBits::encode(flags_)
             | ArgcBits::encode(argc_);
    }
  
    InLoopFlag InLoop() { return in_loop_; }
    bool ReceiverMightBeValue() {
      return (flags_ & RECEIVER_MIGHT_BE_VALUE) != 0;
    }
  
   public:
    static int ExtractArgcFromMinorKey(int minor_key) {
      return ArgcBits::decode(minor_key);
    }
  };
  
  
  class ToBooleanStub: public CodeStub {
   public:
    ToBooleanStub() { }
  
    void Generate(MacroAssembler* masm);
  
   private:
    Major MajorKey() { return ToBoolean; }
    int MinorKey() { return 0; }
  };
  
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_CODEGEN_H_
  