// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_IC_STATE_H_ #define V8_IC_STATE_H_ #include "src/macro-assembler.h" namespace v8 { namespace internal { const int kMaxKeyedPolymorphism = 4; class ICUtility : public AllStatic { public: // Clear the inline cache to initial state. static void Clear(Isolate* isolate, Address address, ConstantPoolArray* constant_pool); }; class CallICState FINAL BASE_EMBEDDED { public: explicit CallICState(ExtraICState extra_ic_state); enum CallType { METHOD, FUNCTION }; CallICState(int argc, CallType call_type) : argc_(argc), call_type_(call_type) {} ExtraICState GetExtraICState() const; static void GenerateAheadOfTime(Isolate*, void (*Generate)(Isolate*, const CallICState&)); int arg_count() const { return argc_; } CallType call_type() const { return call_type_; } bool CallAsMethod() const { return call_type_ == METHOD; } private: class ArgcBits : public BitField<int, 0, Code::kArgumentsBits> {}; class CallTypeBits : public BitField<CallType, Code::kArgumentsBits, 1> {}; const int argc_; const CallType call_type_; }; OStream& operator<<(OStream& os, const CallICState& s); // Mode to overwrite BinaryExpression values. enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; class BinaryOpICState FINAL BASE_EMBEDDED { public: BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state); BinaryOpICState(Isolate* isolate, Token::Value op, OverwriteMode mode) : op_(op), mode_(mode), left_kind_(NONE), right_kind_(NONE), result_kind_(NONE), isolate_(isolate) { DCHECK_LE(FIRST_TOKEN, op); DCHECK_LE(op, LAST_TOKEN); } InlineCacheState GetICState() const { if (Max(left_kind_, right_kind_) == NONE) { return ::v8::internal::UNINITIALIZED; } if (Max(left_kind_, right_kind_) == GENERIC) { return ::v8::internal::MEGAMORPHIC; } if (Min(left_kind_, right_kind_) == GENERIC) { return ::v8::internal::GENERIC; } return ::v8::internal::MONOMORPHIC; } ExtraICState GetExtraICState() const; static void GenerateAheadOfTime(Isolate*, void (*Generate)(Isolate*, const BinaryOpICState&)); bool CanReuseDoubleBox() const { return (result_kind_ > SMI && result_kind_ <= NUMBER) && ((mode_ == OVERWRITE_LEFT && left_kind_ > SMI && left_kind_ <= NUMBER) || (mode_ == OVERWRITE_RIGHT && right_kind_ > SMI && right_kind_ <= NUMBER)); } // Returns true if the IC _could_ create allocation mementos. bool CouldCreateAllocationMementos() const { if (left_kind_ == STRING || right_kind_ == STRING) { DCHECK_EQ(Token::ADD, op_); return true; } return false; } // Returns true if the IC _should_ create allocation mementos. bool ShouldCreateAllocationMementos() const { return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos(); } bool HasSideEffects() const { return Max(left_kind_, right_kind_) == GENERIC; } // Returns true if the IC should enable the inline smi code (i.e. if either // parameter may be a smi). bool UseInlinedSmiCode() const { return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_); } static const int FIRST_TOKEN = Token::BIT_OR; static const int LAST_TOKEN = Token::MOD; Token::Value op() const { return op_; } OverwriteMode mode() const { return mode_; } Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } Type* GetLeftType(Zone* zone) const { return KindToType(left_kind_, zone); } Type* GetRightType(Zone* zone) const { return KindToType(right_kind_, zone); } Type* GetResultType(Zone* zone) const; void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result); Isolate* isolate() const { return isolate_; } private: friend OStream& operator<<(OStream& os, const BinaryOpICState& s); enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC }; Kind UpdateKind(Handle<Object> object, Kind kind) const; static const char* KindToString(Kind kind); static Type* KindToType(Kind kind, Zone* zone); static bool KindMaybeSmi(Kind kind) { return (kind >= SMI && kind <= NUMBER) || kind == GENERIC; } // We truncate the last bit of the token. STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4)); class OpField : public BitField<int, 0, 4> {}; class OverwriteModeField : public BitField<OverwriteMode, 4, 2> {}; class ResultKindField : public BitField<Kind, 6, 3> {}; class LeftKindField : public BitField<Kind, 9, 3> {}; // When fixed right arg is set, we don't need to store the right kind. // Thus the two fields can overlap. class HasFixedRightArgField : public BitField<bool, 12, 1> {}; class FixedRightArgValueField : public BitField<int, 13, 4> {}; class RightKindField : public BitField<Kind, 13, 3> {}; Token::Value op_; OverwriteMode mode_; Kind left_kind_; Kind right_kind_; Kind result_kind_; Maybe<int> fixed_right_arg_; Isolate* isolate_; }; OStream& operator<<(OStream& os, const BinaryOpICState& s); class CompareICState { public: // The type/state lattice is defined by the following inequations: // UNINITIALIZED < ... // ... < GENERIC // SMI < NUMBER // INTERNALIZED_STRING < STRING // KNOWN_OBJECT < OBJECT enum State { UNINITIALIZED, SMI, NUMBER, STRING, INTERNALIZED_STRING, UNIQUE_NAME, // Symbol or InternalizedString OBJECT, // JSObject KNOWN_OBJECT, // JSObject with specific map (faster check) GENERIC }; static Type* StateToType(Zone* zone, State state, Handle<Map> map = Handle<Map>()); static State NewInputState(State old_state, Handle<Object> value); static const char* GetStateName(CompareICState::State state); static State TargetState(State old_state, State old_left, State old_right, Token::Value op, bool has_inlined_smi_code, Handle<Object> x, Handle<Object> y); }; class LoadICState FINAL BASE_EMBEDDED { public: explicit LoadICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {} explicit LoadICState(ContextualMode mode) : state_(ContextualModeBits::encode(mode)) {} ExtraICState GetExtraICState() const { return state_; } ContextualMode contextual_mode() const { return ContextualModeBits::decode(state_); } static ContextualMode GetContextualMode(ExtraICState state) { return LoadICState(state).contextual_mode(); } private: class ContextualModeBits : public BitField<ContextualMode, 0, 1> {}; STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0); const ExtraICState state_; }; } } #endif // V8_IC_STATE_H_