blob: 1ba37b99dbfd4d7e722452fde28475a3d58a5480 [file] [log] [blame]
// 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"
#include "src/parsing/token.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, Address constant_pool);
};
class CallICState final BASE_EMBEDDED {
public:
explicit CallICState(ExtraICState extra_ic_state)
: bit_field_(extra_ic_state) {}
CallICState(ConvertReceiverMode convert_mode, TailCallMode tail_call_mode)
: bit_field_(ConvertModeBits::encode(convert_mode) |
TailCallModeBits::encode(tail_call_mode)) {}
ExtraICState GetExtraICState() const { return bit_field_; }
static void GenerateAheadOfTime(Isolate*,
void (*Generate)(Isolate*,
const CallICState&));
ConvertReceiverMode convert_mode() const {
return ConvertModeBits::decode(bit_field_);
}
TailCallMode tail_call_mode() const {
return TailCallModeBits::decode(bit_field_);
}
private:
typedef BitField<ConvertReceiverMode, 0, 2> ConvertModeBits;
typedef BitField<TailCallMode, ConvertModeBits::kNext, 1> TailCallModeBits;
int const bit_field_;
};
std::ostream& operator<<(std::ostream& os, const CallICState& s);
class BinaryOpICState final BASE_EMBEDDED {
public:
BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state);
BinaryOpICState(Isolate* isolate, Token::Value op)
: op_(op),
left_kind_(NONE),
right_kind_(NONE),
result_kind_(NONE),
fixed_right_arg_(Nothing<int>()),
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&));
// 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_; }
Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
AstType* GetLeftType() const { return KindToType(left_kind_); }
AstType* GetRightType() const { return KindToType(right_kind_); }
AstType* GetResultType() const;
void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result);
Isolate* isolate() const { return isolate_; }
enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
Kind kind() const {
return KindGeneralize(KindGeneralize(left_kind_, right_kind_),
result_kind_);
}
private:
friend std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
Kind UpdateKind(Handle<Object> object, Kind kind) const;
static const char* KindToString(Kind kind);
static AstType* KindToType(Kind kind);
static bool KindMaybeSmi(Kind kind) {
return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
}
static bool KindLessGeneralThan(Kind kind1, Kind kind2) {
if (kind1 == NONE) return true;
if (kind1 == kind2) return true;
if (kind2 == GENERIC) return true;
if (kind2 == STRING) return false;
return kind1 <= kind2;
}
static Kind KindGeneralize(Kind kind1, Kind kind2) {
if (KindLessGeneralThan(kind1, kind2)) return kind2;
if (KindLessGeneralThan(kind2, kind1)) return kind1;
return 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 ResultKindField : public BitField<Kind, 4, 3> {};
class LeftKindField : public BitField<Kind, 7, 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, 10, 1> {};
class FixedRightArgValueField : public BitField<int, 11, 4> {};
class RightKindField : public BitField<Kind, 11, 3> {};
Token::Value op_;
Kind left_kind_;
Kind right_kind_;
Kind result_kind_;
Maybe<int> fixed_right_arg_;
Isolate* isolate_;
};
std::ostream& operator<<(std::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
// INTERNALIZED_STRING < UNIQUE_NAME
// KNOWN_RECEIVER < RECEIVER
enum State {
UNINITIALIZED,
BOOLEAN,
SMI,
NUMBER,
STRING,
INTERNALIZED_STRING,
UNIQUE_NAME, // Symbol or InternalizedString
RECEIVER, // JSReceiver
KNOWN_RECEIVER, // JSReceiver with specific map (faster check)
GENERIC
};
static AstType* 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(Isolate* isolate, State old_state, State old_left,
State old_right, Token::Value op,
bool has_inlined_smi_code, Handle<Object> x,
Handle<Object> y);
};
class LoadGlobalICState final BASE_EMBEDDED {
private:
class TypeofModeBits : public BitField<TypeofMode, 0, 1> {};
STATIC_ASSERT(static_cast<int>(INSIDE_TYPEOF) == 0);
const ExtraICState state_;
public:
static const uint32_t kNextBitFieldOffset = TypeofModeBits::kNext;
explicit LoadGlobalICState(ExtraICState extra_ic_state)
: state_(extra_ic_state) {}
explicit LoadGlobalICState(TypeofMode typeof_mode)
: state_(TypeofModeBits::encode(typeof_mode)) {}
ExtraICState GetExtraICState() const { return state_; }
TypeofMode typeof_mode() const { return TypeofModeBits::decode(state_); }
static TypeofMode GetTypeofMode(ExtraICState state) {
return LoadGlobalICState(state).typeof_mode();
}
};
class StoreICState final BASE_EMBEDDED {
public:
explicit StoreICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {}
explicit StoreICState(LanguageMode mode)
: state_(LanguageModeState::encode(mode)) {}
ExtraICState GetExtraICState() const { return state_; }
LanguageMode language_mode() const {
return LanguageModeState::decode(state_);
}
static LanguageMode GetLanguageMode(ExtraICState state) {
return StoreICState(state).language_mode();
}
class LanguageModeState : public BitField<LanguageMode, 1, 1> {};
STATIC_ASSERT(i::LANGUAGE_END == 2);
// For convenience, a statically declared encoding of strict mode extra
// IC state.
static const ExtraICState kStrictModeState = STRICT
<< LanguageModeState::kShift;
private:
const ExtraICState state_;
};
} // namespace internal
} // namespace v8
#endif // V8_IC_STATE_H_