blob: 72fc865c68d1ebe221f37829f5e457bf7c12cd84 [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"
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_;
};
std::ostream& operator<<(std::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 std::ostream& operator<<(std::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_;
};
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
// 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_