summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/v8/src/hydrogen-instructions.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/v8/src/hydrogen-instructions.h')
-rw-r--r--src/3rdparty/v8/src/hydrogen-instructions.h994
1 files changed, 620 insertions, 374 deletions
diff --git a/src/3rdparty/v8/src/hydrogen-instructions.h b/src/3rdparty/v8/src/hydrogen-instructions.h
index c2c51ca..7136657 100644
--- a/src/3rdparty/v8/src/hydrogen-instructions.h
+++ b/src/3rdparty/v8/src/hydrogen-instructions.h
@@ -53,6 +53,7 @@ class LChunkBuilder;
#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \
+ V(BinaryOperation) \
V(BitwiseBinaryOperation) \
V(ControlInstruction) \
V(Instruction) \
@@ -124,7 +125,6 @@ class LChunkBuilder;
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
- V(StringCompareAndBranch) \
V(JSArrayLength) \
V(LeaveInlined) \
V(LoadContextSlot) \
@@ -133,14 +133,14 @@ class LChunkBuilder;
V(LoadFunctionPrototype) \
V(LoadGlobalCell) \
V(LoadGlobalGeneric) \
- V(LoadKeyedFastDoubleElement) \
- V(LoadKeyedFastElement) \
+ V(LoadKeyed) \
V(LoadKeyedGeneric) \
- V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MapEnumLength) \
V(MathFloorOfDiv) \
+ V(MathMinMax) \
V(Mod) \
V(Mul) \
V(ObjectLiteral) \
@@ -152,6 +152,7 @@ class LChunkBuilder;
V(Random) \
V(RegExpLiteral) \
V(Return) \
+ V(Ror) \
V(Sar) \
V(Shl) \
V(Shr) \
@@ -161,15 +162,14 @@ class LChunkBuilder;
V(StoreContextSlot) \
V(StoreGlobalCell) \
V(StoreGlobalGeneric) \
- V(StoreKeyedFastDoubleElement) \
- V(StoreKeyedFastElement) \
+ V(StoreKeyed) \
V(StoreKeyedGeneric) \
- V(StoreKeyedSpecializedArrayElement) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
V(StringAdd) \
V(StringCharCodeAt) \
V(StringCharFromCode) \
+ V(StringCompareAndBranch) \
V(StringLength) \
V(Sub) \
V(ThisFunction) \
@@ -224,6 +224,16 @@ class LChunkBuilder;
virtual Opcode opcode() const { return HValue::k##type; }
+#ifdef DEBUG
+#define ASSERT_ALLOCATION_DISABLED do { \
+ OptimizingCompilerThread* thread = \
+ ISOLATE->optimizing_compiler_thread(); \
+ ASSERT(thread->IsOptimizerThread() || !HEAP->IsAllocationAllowed()); \
+ } while (0)
+#else
+#define ASSERT_ALLOCATION_DISABLED do {} while (0)
+#endif
+
class Range: public ZoneObject {
public:
Range()
@@ -276,6 +286,8 @@ class Range: public ZoneObject {
void Intersect(Range* other);
void Union(Range* other);
+ void CombinedMax(Range* other);
+ void CombinedMin(Range* other);
void AddConstant(int32_t value);
void Sar(int32_t value);
@@ -549,7 +561,14 @@ class HValue: public ZoneObject {
kIsArguments,
kTruncatingToInt32,
kIsDead,
- kLastFlag = kIsDead
+ // Instructions that are allowed to produce full range unsigned integer
+ // values are marked with kUint32 flag. If arithmetic shift or a load from
+ // EXTERNAL_UNSIGNED_INT_ELEMENTS array is not marked with this flag
+ // it will deoptimize if result does not fit into signed integer range.
+ // HGraph::ComputeSafeUint32Operations is responsible for setting this
+ // flag.
+ kUint32,
+ kLastFlag = kUint32
};
STATIC_ASSERT(kLastFlag < kBitsPerInt);
@@ -645,7 +664,7 @@ class HValue: public ZoneObject {
// Operands.
virtual int OperandCount() = 0;
- virtual HValue* OperandAt(int index) = 0;
+ virtual HValue* OperandAt(int index) const = 0;
void SetOperandAt(int index, HValue* value);
void DeleteAndReplaceWith(HValue* other);
@@ -720,6 +739,11 @@ class HValue: public ZoneObject {
return representation();
}
+ // Type feedback access.
+ virtual Representation ObservedInputRepresentation(int index) {
+ return RequiredInputRepresentation(index);
+ }
+
// This gives the instruction an opportunity to replace itself with an
// instruction that does the same in some better way. To replace an
// instruction with a new one, first add the new instruction to the graph,
@@ -751,6 +775,10 @@ class HValue: public ZoneObject {
UNREACHABLE();
}
+ bool IsDead() const {
+ return HasNoUses() && !HasObservableSideEffects() && IsDeletable();
+ }
+
#ifdef DEBUG
virtual void Verify() = 0;
#endif
@@ -835,6 +863,8 @@ class HValue: public ZoneObject {
GVNFlagSet gvn_flags_;
private:
+ virtual bool IsDeletable() const { return false; }
+
DISALLOW_COPY_AND_ASSIGN(HValue);
};
@@ -852,9 +882,14 @@ class HInstruction: public HValue {
void InsertBefore(HInstruction* next);
void InsertAfter(HInstruction* previous);
+ // The position is a write-once variable.
int position() const { return position_; }
bool has_position() const { return position_ != RelocInfo::kNoPosition; }
- void set_position(int position) { position_ = position; }
+ void set_position(int position) {
+ ASSERT(!has_position());
+ ASSERT(position != RelocInfo::kNoPosition);
+ position_ = position;
+ }
bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); }
@@ -898,7 +933,7 @@ template<int V>
class HTemplateInstruction : public HInstruction {
public:
int OperandCount() { return V; }
- HValue* OperandAt(int i) { return inputs_[i]; }
+ HValue* OperandAt(int i) const { return inputs_[i]; }
protected:
void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; }
@@ -950,7 +985,7 @@ class HTemplateControlInstruction: public HControlInstruction {
void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; }
int OperandCount() { return V; }
- HValue* OperandAt(int i) { return inputs_[i]; }
+ HValue* OperandAt(int i) const { return inputs_[i]; }
protected:
@@ -987,14 +1022,15 @@ class HSoftDeoptimize: public HTemplateInstruction<0> {
class HDeoptimize: public HControlInstruction {
public:
- explicit HDeoptimize(int environment_length) : values_(environment_length) { }
+ HDeoptimize(int environment_length, Zone* zone)
+ : values_(environment_length, zone) { }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
virtual int OperandCount() { return values_.length(); }
- virtual HValue* OperandAt(int index) { return values_[index]; }
+ virtual HValue* OperandAt(int index) const { return values_[index]; }
virtual void PrintDataTo(StringStream* stream);
virtual int SuccessorCount() { return 0; }
@@ -1006,8 +1042,8 @@ class HDeoptimize: public HControlInstruction {
UNREACHABLE();
}
- void AddEnvironmentValue(HValue* value) {
- values_.Add(NULL);
+ void AddEnvironmentValue(HValue* value, Zone* zone) {
+ values_.Add(NULL, zone);
SetOperandAt(values_.length() - 1, value);
}
@@ -1155,7 +1191,7 @@ class HUnaryOperation: public HTemplateInstruction<1> {
return reinterpret_cast<HUnaryOperation*>(value);
}
- HValue* value() { return OperandAt(0); }
+ HValue* value() const { return OperandAt(0); }
virtual void PrintDataTo(StringStream* stream);
};
@@ -1231,8 +1267,8 @@ class HChange: public HUnaryOperation {
virtual HType CalculateInferredType();
virtual HValue* Canonicalize();
- Representation from() { return value()->representation(); }
- Representation to() { return representation(); }
+ Representation from() const { return value()->representation(); }
+ Representation to() const { return representation(); }
bool deoptimize_on_undefined() const {
return CheckFlag(kDeoptimizeOnUndefined);
}
@@ -1251,6 +1287,11 @@ class HChange: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const {
+ return !from().IsTagged() || value()->type().IsSmi();
+ }
};
@@ -1270,23 +1311,27 @@ class HClampToUint8: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
class HSimulate: public HInstruction {
public:
- HSimulate(int ast_id, int pop_count)
+ HSimulate(BailoutId ast_id, int pop_count, Zone* zone)
: ast_id_(ast_id),
pop_count_(pop_count),
- values_(2),
- assigned_indexes_(2) {}
+ values_(2, zone),
+ assigned_indexes_(2, zone),
+ zone_(zone) {}
virtual ~HSimulate() {}
virtual void PrintDataTo(StringStream* stream);
- bool HasAstId() const { return ast_id_ != AstNode::kNoNumber; }
- int ast_id() const { return ast_id_; }
- void set_ast_id(int id) {
+ bool HasAstId() const { return !ast_id_.IsNone(); }
+ BailoutId ast_id() const { return ast_id_; }
+ void set_ast_id(BailoutId id) {
ASSERT(!HasAstId());
ast_id_ = id;
}
@@ -1307,7 +1352,7 @@ class HSimulate: public HInstruction {
AddValue(kNoIndex, value);
}
virtual int OperandCount() { return values_.length(); }
- virtual HValue* OperandAt(int index) { return values_[index]; }
+ virtual HValue* OperandAt(int index) const { return values_[index]; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -1327,17 +1372,18 @@ class HSimulate: public HInstruction {
private:
static const int kNoIndex = -1;
void AddValue(int index, HValue* value) {
- assigned_indexes_.Add(index);
+ assigned_indexes_.Add(index, zone_);
// Resize the list of pushed values.
- values_.Add(NULL);
+ values_.Add(NULL, zone_);
// Set the operand through the base method in HValue to make sure that the
// use lists are correctly updated.
SetOperandAt(values_.length() - 1, value);
}
- int ast_id_;
+ BailoutId ast_id_;
int pop_count_;
ZoneList<HValue*> values_;
ZoneList<int> assigned_indexes_;
+ Zone* zone_;
};
@@ -1377,20 +1423,30 @@ class HStackCheck: public HTemplateInstruction<1> {
};
+enum InliningKind {
+ NORMAL_RETURN, // Normal function/method call and return.
+ DROP_EXTRA_ON_RETURN, // Drop an extra value from the environment on return.
+ CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value.
+ GETTER_CALL_RETURN, // Returning from a getter, need to restore context.
+ SETTER_CALL_RETURN // Use the RHS of the assignment as the return value.
+};
+
+
class HEnterInlined: public HTemplateInstruction<0> {
public:
HEnterInlined(Handle<JSFunction> closure,
int arguments_count,
FunctionLiteral* function,
CallKind call_kind,
- bool is_construct,
+ InliningKind inlining_kind,
Variable* arguments_var,
ZoneList<HValue*>* arguments_values)
: closure_(closure),
arguments_count_(arguments_count),
+ arguments_pushed_(false),
function_(function),
call_kind_(call_kind),
- is_construct_(is_construct),
+ inlining_kind_(inlining_kind),
arguments_var_(arguments_var),
arguments_values_(arguments_values) {
}
@@ -1399,9 +1455,11 @@ class HEnterInlined: public HTemplateInstruction<0> {
Handle<JSFunction> closure() const { return closure_; }
int arguments_count() const { return arguments_count_; }
+ bool arguments_pushed() const { return arguments_pushed_; }
+ void set_arguments_pushed() { arguments_pushed_ = true; }
FunctionLiteral* function() const { return function_; }
CallKind call_kind() const { return call_kind_; }
- bool is_construct() const { return is_construct_; }
+ InliningKind inlining_kind() const { return inlining_kind_; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -1415,9 +1473,10 @@ class HEnterInlined: public HTemplateInstruction<0> {
private:
Handle<JSFunction> closure_;
int arguments_count_;
+ bool arguments_pushed_;
FunctionLiteral* function_;
CallKind call_kind_;
- bool is_construct_;
+ InliningKind inlining_kind_;
Variable* arguments_var_;
ZoneList<HValue*>* arguments_values_;
};
@@ -1425,21 +1484,13 @@ class HEnterInlined: public HTemplateInstruction<0> {
class HLeaveInlined: public HTemplateInstruction<0> {
public:
- explicit HLeaveInlined(bool arguments_pushed)
- : arguments_pushed_(arguments_pushed) { }
+ HLeaveInlined() { }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
- bool arguments_pushed() {
- return arguments_pushed_;
- }
-
DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
-
- private:
- bool arguments_pushed_;
};
@@ -1461,7 +1512,7 @@ class HPushArgument: public HUnaryOperation {
class HThisFunction: public HTemplateInstruction<0> {
public:
- explicit HThisFunction(Handle<JSFunction> closure) : closure_(closure) {
+ HThisFunction() {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
}
@@ -1470,18 +1521,13 @@ class HThisFunction: public HTemplateInstruction<0> {
return Representation::None();
}
- Handle<JSFunction> closure() const { return closure_; }
-
DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
protected:
- virtual bool DataEquals(HValue* other) {
- HThisFunction* b = HThisFunction::cast(other);
- return *closure() == *b->closure();
- }
+ virtual bool DataEquals(HValue* other) { return true; }
private:
- Handle<JSFunction> closure_;
+ virtual bool IsDeletable() const { return true; }
};
@@ -1500,6 +1546,9 @@ class HContext: public HTemplateInstruction<0> {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -1518,6 +1567,9 @@ class HOuterContext: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -1573,6 +1625,7 @@ class HGlobalObject: public HUnaryOperation {
}
private:
+ virtual bool IsDeletable() const { return true; }
bool qml_global_;
};
@@ -1593,6 +1646,9 @@ class HGlobalReceiver: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -1855,7 +1911,9 @@ class HCallRuntime: public HCall<1> {
class HJSArrayLength: public HTemplateInstruction<2> {
public:
- HJSArrayLength(HValue* value, HValue* typecheck) {
+ HJSArrayLength(HValue* value, HValue* typecheck,
+ HType type = HType::Tagged()) {
+ set_type(type);
// The length of an array is stored as a tagged value in the array
// object. It is guaranteed to be 32 bit integer, but it can be
// represented as either a smi or heap number.
@@ -1879,13 +1937,17 @@ class HJSArrayLength: public HTemplateInstruction<2> {
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
protected:
- virtual bool DataEquals(HValue* other) { return true; }
+ virtual bool DataEquals(HValue* other_raw) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
class HFixedArrayBaseLength: public HUnaryOperation {
public:
explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) {
+ set_type(HType::Smi());
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnArrayLengths);
@@ -1899,6 +1961,32 @@ class HFixedArrayBaseLength: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
+};
+
+
+class HMapEnumLength: public HUnaryOperation {
+ public:
+ explicit HMapEnumLength(HValue* value) : HUnaryOperation(value) {
+ set_type(HType::Smi());
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ SetGVNFlag(kDependsOnMaps);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -1918,6 +2006,9 @@ class HElementsKind: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -1940,6 +2031,9 @@ class HBitNot: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -2022,18 +2116,27 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
}
private:
+ virtual bool IsDeletable() const { return true; }
+
BuiltinFunctionId op_;
};
-class HLoadElements: public HUnaryOperation {
+class HLoadElements: public HTemplateInstruction<2> {
public:
- explicit HLoadElements(HValue* value) : HUnaryOperation(value) {
+ HLoadElements(HValue* value, HValue* typecheck) {
+ SetOperandAt(0, value);
+ SetOperandAt(1, typecheck);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnElementsPointer);
}
+ HValue* value() { return OperandAt(0); }
+ HValue* typecheck() { return OperandAt(1); }
+
+ virtual void PrintDataTo(StringStream* stream);
+
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
@@ -2042,6 +2145,9 @@ class HLoadElements: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -2065,12 +2171,16 @@ class HLoadExternalArrayPointer: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
class HCheckMaps: public HTemplateInstruction<2> {
public:
- HCheckMaps(HValue* value, Handle<Map> map, HValue* typecheck = NULL) {
+ HCheckMaps(HValue* value, Handle<Map> map, Zone* zone,
+ HValue* typecheck = NULL) {
SetOperandAt(0, value);
// If callers don't depend on a typecheck, they can pass in NULL. In that
// case we use a copy of the |value| argument as a dummy value.
@@ -2079,9 +2189,9 @@ class HCheckMaps: public HTemplateInstruction<2> {
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnElementsKind);
- map_set()->Add(map);
+ map_set()->Add(map, zone);
}
- HCheckMaps(HValue* value, SmallMapList* maps) {
+ HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone) {
SetOperandAt(0, value);
SetOperandAt(1, value);
set_representation(Representation::Tagged());
@@ -2089,37 +2199,31 @@ class HCheckMaps: public HTemplateInstruction<2> {
SetGVNFlag(kDependsOnMaps);
SetGVNFlag(kDependsOnElementsKind);
for (int i = 0; i < maps->length(); i++) {
- map_set()->Add(maps->at(i));
+ map_set()->Add(maps->at(i), zone);
}
map_set()->Sort();
}
- static HCheckMaps* NewWithTransitions(HValue* object, Handle<Map> map) {
- HCheckMaps* check_map = new HCheckMaps(object, map);
+ static HCheckMaps* NewWithTransitions(HValue* object, Handle<Map> map,
+ Zone* zone) {
+ HCheckMaps* check_map = new(zone) HCheckMaps(object, map, zone);
SmallMapList* map_set = check_map->map_set();
- // If the map to check has the untransitioned elements, it can be hoisted
- // above TransitionElements instructions.
- if (map->has_fast_smi_only_elements()) {
- check_map->ClearGVNFlag(kDependsOnElementsKind);
- }
-
- Map* transitioned_fast_element_map =
- map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL);
- ASSERT(transitioned_fast_element_map == NULL ||
- map->elements_kind() != FAST_ELEMENTS);
- if (transitioned_fast_element_map != NULL) {
- map_set->Add(Handle<Map>(transitioned_fast_element_map));
- }
- Map* transitioned_double_map =
- map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL);
- ASSERT(transitioned_double_map == NULL ||
- map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
- if (transitioned_double_map != NULL) {
- map_set->Add(Handle<Map>(transitioned_double_map));
- }
+ // Since transitioned elements maps of the initial map don't fail the map
+ // check, the CheckMaps instruction doesn't need to depend on ElementsKinds.
+ check_map->ClearGVNFlag(kDependsOnElementsKind);
+
+ ElementsKind kind = map->elements_kind();
+ bool packed = IsFastPackedElementsKind(kind);
+ while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
+ kind = GetNextMoreGeneralFastElementsKind(kind, packed);
+ Map* transitioned_map =
+ map->LookupElementsTransitionMap(kind);
+ if (transitioned_map) {
+ map_set->Add(Handle<Map>(transitioned_map), zone);
+ }
+ };
map_set->Sort();
-
return check_map;
}
@@ -2185,17 +2289,17 @@ class HCheckFunction: public HUnaryOperation {
class HCheckInstanceType: public HUnaryOperation {
public:
- static HCheckInstanceType* NewIsSpecObject(HValue* value) {
- return new HCheckInstanceType(value, IS_SPEC_OBJECT);
+ static HCheckInstanceType* NewIsSpecObject(HValue* value, Zone* zone) {
+ return new(zone) HCheckInstanceType(value, IS_SPEC_OBJECT);
}
- static HCheckInstanceType* NewIsJSArray(HValue* value) {
- return new HCheckInstanceType(value, IS_JS_ARRAY);
+ static HCheckInstanceType* NewIsJSArray(HValue* value, Zone* zone) {
+ return new(zone) HCheckInstanceType(value, IS_JS_ARRAY);
}
- static HCheckInstanceType* NewIsString(HValue* value) {
- return new HCheckInstanceType(value, IS_STRING);
+ static HCheckInstanceType* NewIsString(HValue* value, Zone* zone) {
+ return new(zone) HCheckInstanceType(value, IS_STRING);
}
- static HCheckInstanceType* NewIsSymbol(HValue* value) {
- return new HCheckInstanceType(value, IS_SYMBOL);
+ static HCheckInstanceType* NewIsSymbol(HValue* value, Zone* zone) {
+ return new(zone) HCheckInstanceType(value, IS_SYMBOL);
}
virtual void PrintDataTo(StringStream* stream);
@@ -2286,10 +2390,6 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
SetGVNFlag(kDependsOnMaps);
}
-#ifdef DEBUG
- virtual void Verify();
-#endif
-
Handle<JSObject> prototype() const { return prototype_; }
Handle<JSObject> holder() const { return holder_; }
@@ -2299,8 +2399,10 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
return Representation::None();
}
+ virtual void PrintDataTo(StringStream* stream);
+
virtual intptr_t Hashcode() {
- ASSERT(!HEAP->IsAllocationAllowed());
+ ASSERT_ALLOCATION_DISABLED;
intptr_t hash = reinterpret_cast<intptr_t>(*prototype());
hash = 17 * hash + reinterpret_cast<intptr_t>(*holder());
return hash;
@@ -2344,8 +2446,8 @@ class HCheckSmi: public HUnaryOperation {
class HPhi: public HValue {
public:
- explicit HPhi(int merged_index)
- : inputs_(2),
+ HPhi(int merged_index, Zone* zone)
+ : inputs_(2, zone),
merged_index_(merged_index),
phi_id_(-1),
is_live_(false),
@@ -2367,7 +2469,7 @@ class HPhi: public HValue {
}
virtual HType CalculateInferredType();
virtual int OperandCount() { return inputs_.length(); }
- virtual HValue* OperandAt(int index) { return inputs_[index]; }
+ virtual HValue* OperandAt(int index) const { return inputs_[index]; }
HValue* GetRedundantReplacement();
void AddInput(HValue* value);
bool HasRealUses();
@@ -2424,11 +2526,15 @@ class HPhi: public HValue {
bool AllOperandsConvertibleToInteger() {
for (int i = 0; i < OperandCount(); ++i) {
- if (!OperandAt(i)->IsConvertibleToInteger()) return false;
+ if (!OperandAt(i)->IsConvertibleToInteger()) {
+ return false;
+ }
}
return true;
}
+ void ResetInteger32Uses();
+
protected:
virtual void DeleteFromGraph();
virtual void InternalSetOperandAt(int index, HValue* value) {
@@ -2459,26 +2565,51 @@ class HArgumentsObject: public HTemplateInstruction<0> {
}
DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
class HConstant: public HTemplateInstruction<0> {
public:
HConstant(Handle<Object> handle, Representation r);
+ HConstant(int32_t value, Representation r);
+ HConstant(double value, Representation r);
- Handle<Object> handle() const { return handle_; }
+ Handle<Object> handle() {
+ if (handle_.is_null()) {
+ handle_ = FACTORY->NewNumber(double_value_, TENURED);
+ }
+ ASSERT(has_int32_value_ || !handle_->IsSmi());
+ return handle_;
+ }
bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); }
bool ImmortalImmovable() const {
+ if (has_int32_value_) {
+ return false;
+ }
+ if (has_double_value_) {
+ if (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
+ isnan(double_value_)) {
+ return true;
+ }
+ return false;
+ }
+
+ ASSERT(!handle_.is_null());
Heap* heap = HEAP;
+ // We should have handled minus_zero_value and nan_value in the
+ // has_double_value_ clause above.
+ ASSERT(*handle_ != heap->minus_zero_value());
+ ASSERT(*handle_ != heap->nan_value());
if (*handle_ == heap->undefined_value()) return true;
if (*handle_ == heap->null_value()) return true;
if (*handle_ == heap->true_value()) return true;
if (*handle_ == heap->false_value()) return true;
if (*handle_ == heap->the_hole_value()) return true;
- if (*handle_ == heap->minus_zero_value()) return true;
- if (*handle_ == heap->nan_value()) return true;
if (*handle_ == heap->empty_string()) return true;
return false;
}
@@ -2488,20 +2619,15 @@ class HConstant: public HTemplateInstruction<0> {
}
virtual bool IsConvertibleToInteger() const {
- if (handle_->IsSmi()) return true;
- if (handle_->IsHeapNumber() &&
- (HeapNumber::cast(*handle_)->value() ==
- static_cast<double>(NumberToInt32(*handle_)))) return true;
- return false;
+ return has_int32_value_;
}
virtual bool EmitAtUses() { return !representation().IsDouble(); }
- virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
- bool IsInteger() const { return handle_->IsSmi(); }
- HConstant* CopyToRepresentation(Representation r) const;
- HConstant* CopyToTruncatedInt32() const;
+ bool IsInteger() { return handle()->IsSmi(); }
+ HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
+ HConstant* CopyToTruncatedInt32(Zone* zone) const;
bool HasInteger32Value() const { return has_int32_value_; }
int32_t Integer32Value() const {
ASSERT(HasInteger32Value());
@@ -2512,24 +2638,35 @@ class HConstant: public HTemplateInstruction<0> {
ASSERT(HasDoubleValue());
return double_value_;
}
- bool HasNumberValue() const { return has_int32_value_ || has_double_value_; }
+ bool HasNumberValue() const { return has_double_value_; }
int32_t NumberValueAsInteger32() const {
ASSERT(HasNumberValue());
- if (has_int32_value_) return int32_value_;
- return DoubleToInt32(double_value_);
+ // Irrespective of whether a numeric HConstant can be safely
+ // represented as an int32, we store the (in some cases lossy)
+ // representation of the number in int32_value_.
+ return int32_value_;
}
- bool HasStringValue() const { return handle_->IsString(); }
- bool ToBoolean() const;
+ bool ToBoolean();
+
+ bool IsUint32() {
+ return HasInteger32Value() && (Integer32Value() >= 0);
+ }
virtual intptr_t Hashcode() {
- ASSERT(!HEAP->allow_allocation(false));
- intptr_t hash = reinterpret_cast<intptr_t>(*handle());
- // Prevent smis from having fewer hash values when truncated to
- // the least significant bits.
- const int kShiftSize = kSmiShiftSize + kSmiTagSize;
- STATIC_ASSERT(kShiftSize != 0);
- return hash ^ (hash >> kShiftSize);
+ ASSERT_ALLOCATION_DISABLED;
+ intptr_t hash;
+
+ if (has_int32_value_) {
+ hash = static_cast<intptr_t>(int32_value_);
+ } else if (has_double_value_) {
+ hash = static_cast<intptr_t>(BitCast<int64_t>(double_value_));
+ } else {
+ ASSERT(!handle_.is_null());
+ hash = reinterpret_cast<intptr_t>(*handle_);
+ }
+
+ return hash;
}
#ifdef DEBUG
@@ -2543,15 +2680,34 @@ class HConstant: public HTemplateInstruction<0> {
virtual bool DataEquals(HValue* other) {
HConstant* other_constant = HConstant::cast(other);
- return handle().is_identical_to(other_constant->handle());
+ if (has_int32_value_) {
+ return other_constant->has_int32_value_ &&
+ int32_value_ == other_constant->int32_value_;
+ } else if (has_double_value_) {
+ return other_constant->has_double_value_ &&
+ BitCast<int64_t>(double_value_) ==
+ BitCast<int64_t>(other_constant->double_value_);
+ } else {
+ ASSERT(!handle_.is_null());
+ return !other_constant->handle_.is_null() &&
+ *handle_ == *other_constant->handle_;
+ }
}
private:
+ virtual bool IsDeletable() const { return true; }
+
+ // If this is a numerical constant, handle_ either points to to the
+ // HeapObject the constant originated from or is null. If the
+ // constant is non-numeric, handle_ always points to a valid
+ // constant HeapObject.
Handle<Object> handle_;
- // The following two values represent the int32 and the double value of the
- // given constant if there is a lossless conversion between the constant
- // and the specific representation.
+ // We store the HConstant in the most specific form safely possible.
+ // The two flags, has_int32_value_ and has_double_value_ tell us if
+ // int32_value_ and double_value_ hold valid, safe representations
+ // of the constant. has_int32_value_ implies has_double_value_ but
+ // not the converse.
bool has_int32_value_ : 1;
bool has_double_value_ : 1;
int32_t int32_value_;
@@ -2578,6 +2734,7 @@ class HBinaryOperation: public HTemplateInstruction<3> {
if (IsCommutative() && left()->IsConstant()) return right();
return left();
}
+
HValue* MostConstantOperand() {
if (IsCommutative() && left()->IsConstant()) return left();
return right();
@@ -2586,6 +2743,8 @@ class HBinaryOperation: public HTemplateInstruction<3> {
virtual bool IsCommutative() const { return false; }
virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
};
@@ -2660,6 +2819,9 @@ class HArgumentsElements: public HTemplateInstruction<0> {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+ private:
+ virtual bool IsDeletable() const { return true; }
+
bool from_inlined_;
};
@@ -2679,6 +2841,9 @@ class HArgumentsLength: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -2711,16 +2876,42 @@ class HAccessArgumentsAt: public HTemplateInstruction<3> {
};
+enum BoundsCheckKeyMode {
+ DONT_ALLOW_SMI_KEY,
+ ALLOW_SMI_KEY
+};
+
+
class HBoundsCheck: public HTemplateInstruction<2> {
public:
- HBoundsCheck(HValue* index, HValue* length) {
+ HBoundsCheck(HValue* index, HValue* length,
+ BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY)
+ : key_mode_(key_mode) {
SetOperandAt(0, index);
SetOperandAt(1, length);
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
}
- virtual Representation RequiredInputRepresentation(int index) {
+ virtual Representation RequiredInputRepresentation(int arg_index) {
+ if (key_mode_ == DONT_ALLOW_SMI_KEY ||
+ !length()->representation().IsTagged()) {
+ return Representation::Integer32();
+ }
+ // If the index is tagged and isn't constant, then allow the length
+ // to be tagged, since it is usually already tagged from loading it out of
+ // the length field of a JSArray. This allows for direct comparison without
+ // untagging.
+ if (index()->representation().IsTagged() && !index()->IsConstant()) {
+ return Representation::Tagged();
+ }
+ // Also allow the length to be tagged if the index is constant, because
+ // it can be tagged to allow direct comparison.
+ if (index()->IsConstant() &&
+ index()->representation().IsInteger32() &&
+ arg_index == 1) {
+ return Representation::Tagged();
+ }
return Representation::Integer32();
}
@@ -2733,6 +2924,7 @@ class HBoundsCheck: public HTemplateInstruction<2> {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+ BoundsCheckKeyMode key_mode_;
};
@@ -2743,6 +2935,9 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
set_representation(Representation::Tagged());
SetFlag(kFlexibleRepresentation);
SetAllSideEffects();
+ observed_input_representation_[0] = Representation::Tagged();
+ observed_input_representation_[1] = Representation::None();
+ observed_input_representation_[2] = Representation::None();
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -2762,7 +2957,21 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
virtual HType CalculateInferredType();
+ virtual Representation ObservedInputRepresentation(int index) {
+ return observed_input_representation_[index];
+ }
+
+ void InitializeObservedInputRepresentation(Representation r) {
+ observed_input_representation_[1] = r;
+ observed_input_representation_[2] = r;
+ }
+
DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
+
+ private:
+ virtual bool IsDeletable() const { return true; }
+
+ Representation observed_input_representation_[3];
};
@@ -2772,8 +2981,11 @@ class HMathFloorOfDiv: public HBinaryOperation {
: HBinaryOperation(context, left, right) {
set_representation(Representation::Integer32());
SetFlag(kUseGVN);
+ SetFlag(kCanOverflow);
}
+ virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited);
+
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Integer32();
}
@@ -2782,6 +2994,9 @@ class HMathFloorOfDiv: public HBinaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -2814,6 +3029,9 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
}
return HValue::InferredRepresentation();
}
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -3099,6 +3317,9 @@ class HGetCachedArrayIndex: public HUnaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -3203,7 +3424,7 @@ class HPower: public HTemplateInstruction<2> {
}
HValue* left() { return OperandAt(0); }
- HValue* right() { return OperandAt(1); }
+ HValue* right() const { return OperandAt(1); }
virtual Representation RequiredInputRepresentation(int index) {
return index == 0
@@ -3215,6 +3436,11 @@ class HPower: public HTemplateInstruction<2> {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+ virtual bool IsDeletable() const {
+ return !right()->representation().IsTagged();
+ }
};
@@ -3232,6 +3458,9 @@ class HRandom: public HTemplateInstruction<1> {
}
DECLARE_CONCRETE_INSTRUCTION(Random)
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -3378,6 +3607,47 @@ class HDiv: public HArithmeticBinaryOperation {
};
+class HMathMinMax: public HArithmeticBinaryOperation {
+ public:
+ enum Operation { kMathMin, kMathMax };
+
+ HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
+ : HArithmeticBinaryOperation(context, left, right),
+ operation_(op) { }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return index == 0
+ ? Representation::Tagged()
+ : representation();
+ }
+
+ virtual Representation InferredRepresentation() {
+ if (left()->representation().IsInteger32() &&
+ right()->representation().IsInteger32()) {
+ return Representation::Integer32();
+ }
+ return Representation::Double();
+ }
+
+ virtual bool IsCommutative() const { return true; }
+
+ Operation operation() { return operation_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
+
+ protected:
+ virtual bool DataEquals(HValue* other) {
+ return other->IsMathMinMax() &&
+ HMathMinMax::cast(other)->operation_ == operation_;
+ }
+
+ virtual Range* InferRange(Zone* zone);
+
+ private:
+ Operation operation_;
+};
+
+
class HBitwise: public HBitwiseBinaryOperation {
public:
HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
@@ -3472,13 +3742,32 @@ class HSar: public HBitwiseBinaryOperation {
};
+class HRor: public HBitwiseBinaryOperation {
+ public:
+ HRor(HValue* context, HValue* left, HValue* right)
+ : HBitwiseBinaryOperation(context, left, right) {
+ ChangeRepresentation(Representation::Integer32());
+ }
+
+ static HInstruction* NewHRor(Zone* zone,
+ HValue* context,
+ HValue* left,
+ HValue* right);
+
+ DECLARE_CONCRETE_INSTRUCTION(Ror)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+};
+
+
class HOsrEntry: public HTemplateInstruction<0> {
public:
- explicit HOsrEntry(int ast_id) : ast_id_(ast_id) {
+ explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
SetGVNFlag(kChangesOsrEntries);
}
- int ast_id() const { return ast_id_; }
+ BailoutId ast_id() const { return ast_id_; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
@@ -3487,7 +3776,7 @@ class HOsrEntry: public HTemplateInstruction<0> {
DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
private:
- int ast_id_;
+ BailoutId ast_id_;
};
@@ -3581,12 +3870,12 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
}
Handle<JSGlobalPropertyCell> cell() const { return cell_; }
- bool RequiresHoleCheck();
+ bool RequiresHoleCheck() const;
virtual void PrintDataTo(StringStream* stream);
virtual intptr_t Hashcode() {
- ASSERT(!HEAP->allow_allocation(false));
+ ASSERT_ALLOCATION_DISABLED;
return reinterpret_cast<intptr_t>(*cell_);
}
@@ -3603,6 +3892,8 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
}
private:
+ virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
+
Handle<JSGlobalPropertyCell> cell_;
PropertyDetails details_;
};
@@ -3650,7 +3941,8 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) {
inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
HValue* new_space_dominator) {
- return !object->IsAllocateObject() || (object != new_space_dominator);
+ return (!object->IsAllocateObject() && !object->IsFastLiteral()) ||
+ (object != new_space_dominator);
}
@@ -3763,7 +4055,7 @@ class HLoadContextSlot: public HUnaryOperation {
return mode_ == kCheckDeoptimize;
}
- bool RequiresHoleCheck() {
+ bool RequiresHoleCheck() const {
return mode_ != kNoCheck;
}
@@ -3782,6 +4074,8 @@ class HLoadContextSlot: public HUnaryOperation {
}
private:
+ virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
+
int slot_index_;
Mode mode_;
};
@@ -3874,6 +4168,8 @@ class HLoadNamedField: public HUnaryOperation {
}
private:
+ virtual bool IsDeletable() const { return true; }
+
bool is_in_object_;
int offset_;
};
@@ -3884,7 +4180,8 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> {
HLoadNamedFieldPolymorphic(HValue* context,
HValue* object,
SmallMapList* types,
- Handle<String> name);
+ Handle<String> name,
+ Zone* zone);
HValue* context() { return OperandAt(0); }
HValue* object() { return OperandAt(1); }
@@ -3971,162 +4268,134 @@ class ArrayInstructionInterface {
virtual ~ArrayInstructionInterface() { };
};
-class HLoadKeyedFastElement
- : public HTemplateInstruction<2>, public ArrayInstructionInterface {
+
+class HLoadKeyed
+ : public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
- enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK };
+ HLoadKeyed(HValue* obj,
+ HValue* key,
+ HValue* dependency,
+ ElementsKind elements_kind)
+ : bit_field_(0) {
+ bit_field_ = ElementsKindField::encode(elements_kind);
- HLoadKeyedFastElement(HValue* obj,
- HValue* key,
- HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK)
- : hole_check_mode_(hole_check_mode),
- index_offset_(0),
- is_dehoisted_(false) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
- set_representation(Representation::Tagged());
- SetGVNFlag(kDependsOnArrayElements);
- SetFlag(kUseGVN);
- }
+ SetOperandAt(2, dependency);
- HValue* object() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
-
- virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32.
- return index == 0
- ? Representation::Tagged()
- : Representation::Integer32();
- }
+ if (!is_external()) {
+ // I can detect the case between storing double (holey and fast) and
+ // smi/object by looking at elements_kind_.
+ ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
+ IsFastDoubleElementsKind(elements_kind));
- virtual void PrintDataTo(StringStream* stream);
+ if (IsFastSmiOrObjectElementsKind(elements_kind)) {
+ if (IsFastSmiElementsKind(elements_kind) &&
+ IsFastPackedElementsKind(elements_kind)) {
+ set_type(HType::Smi());
+ }
- bool RequiresHoleCheck();
-
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement)
-
- protected:
- virtual bool DataEquals(HValue* other) {
- if (!other->IsLoadKeyedFastElement()) return false;
- HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other);
- if (is_dehoisted_ && index_offset_ != other_load->index_offset_)
- return false;
- return hole_check_mode_ == other_load->hole_check_mode_;
- }
-
- private:
- HoleCheckMode hole_check_mode_;
- uint32_t index_offset_;
- bool is_dehoisted_;
-};
+ set_representation(Representation::Tagged());
+ SetGVNFlag(kDependsOnArrayElements);
+ } else {
+ set_representation(Representation::Double());
+ SetGVNFlag(kDependsOnDoubleArrayElements);
+ }
+ } else {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
+ set_representation(Representation::Double());
+ } else {
+ set_representation(Representation::Integer32());
+ }
+ SetGVNFlag(kDependsOnSpecializedArrayElements);
+ // Native code could change the specialized array.
+ SetGVNFlag(kDependsOnCalls);
+ }
-class HLoadKeyedFastDoubleElement
- : public HTemplateInstruction<2>, public ArrayInstructionInterface {
- public:
- HLoadKeyedFastDoubleElement(HValue* elements, HValue* key)
- : index_offset_(0), is_dehoisted_(false) {
- SetOperandAt(0, elements);
- SetOperandAt(1, key);
- set_representation(Representation::Double());
- SetGVNFlag(kDependsOnDoubleArrayElements);
SetFlag(kUseGVN);
}
+ bool is_external() const {
+ return IsExternalArrayElementsKind(elements_kind());
+ }
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
+ HValue* dependency() { return OperandAt(2); }
+ uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); }
+ void SetIndexOffset(uint32_t index_offset) {
+ bit_field_ = IndexOffsetField::update(bit_field_, index_offset);
+ }
HValue* GetKey() { return key(); }
void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
-
- virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32.
- return index == 0
- ? Representation::Tagged()
- : Representation::Integer32();
+ bool IsDehoisted() { return IsDehoistedField::decode(bit_field_); }
+ void SetDehoisted(bool is_dehoisted) {
+ bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
+ }
+ ElementsKind elements_kind() const {
+ return ElementsKindField::decode(bit_field_);
}
- virtual void PrintDataTo(StringStream* stream);
-
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement)
-
- protected:
- virtual bool DataEquals(HValue* other) { return true; }
-
- private:
- uint32_t index_offset_;
- bool is_dehoisted_;
-};
-
-
-class HLoadKeyedSpecializedArrayElement
- : public HTemplateInstruction<2>, public ArrayInstructionInterface {
- public:
- HLoadKeyedSpecializedArrayElement(HValue* external_elements,
- HValue* key,
- ElementsKind elements_kind)
- : elements_kind_(elements_kind),
- index_offset_(0),
- is_dehoisted_(false) {
- SetOperandAt(0, external_elements);
- SetOperandAt(1, key);
- if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
- set_representation(Representation::Double());
- } else {
- set_representation(Representation::Integer32());
+ virtual Representation RequiredInputRepresentation(int index) {
+ // kind_fast: tagged[int32] (none)
+ // kind_double: tagged[int32] (none)
+ // kind_external: external[int32] (none)
+ if (index == 0) {
+ return is_external() ? Representation::External()
+ : Representation::Tagged();
}
- SetGVNFlag(kDependsOnSpecializedArrayElements);
- // Native code could change the specialized array.
- SetGVNFlag(kDependsOnCalls);
- SetFlag(kUseGVN);
+ if (index == 1) return Representation::Integer32();
+ return Representation::None();
}
virtual void PrintDataTo(StringStream* stream);
- virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32, but the base pointer
- // for the element load is a naked pointer.
- return index == 0
- ? Representation::External()
- : Representation::Integer32();
- }
-
- HValue* external_pointer() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- ElementsKind elements_kind() const { return elements_kind_; }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
+ bool RequiresHoleCheck() const;
virtual Range* InferRange(Zone* zone);
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
protected:
virtual bool DataEquals(HValue* other) {
- if (!other->IsLoadKeyedSpecializedArrayElement()) return false;
- HLoadKeyedSpecializedArrayElement* cast_other =
- HLoadKeyedSpecializedArrayElement::cast(other);
- return elements_kind_ == cast_other->elements_kind();
+ if (!other->IsLoadKeyed()) return false;
+ HLoadKeyed* other_load = HLoadKeyed::cast(other);
+
+ if (IsDehoisted() && index_offset() != other_load->index_offset())
+ return false;
+ return elements_kind() == other_load->elements_kind();
}
private:
- ElementsKind elements_kind_;
- uint32_t index_offset_;
- bool is_dehoisted_;
+ virtual bool IsDeletable() const {
+ return !RequiresHoleCheck();
+ }
+
+ // Establish some checks around our packed fields
+ enum LoadKeyedBits {
+ kBitsForElementsKind = 5,
+ kBitsForIndexOffset = 26,
+ kBitsForIsDehoisted = 1,
+
+ kStartElementsKind = 0,
+ kStartIndexOffset = kStartElementsKind + kBitsForElementsKind,
+ kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset
+ };
+
+ STATIC_ASSERT((kBitsForElementsKind + kBitsForIndexOffset +
+ kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
+ STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
+ class ElementsKindField:
+ public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
+ {}; // NOLINT
+ class IndexOffsetField:
+ public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset>
+ {}; // NOLINT
+ class IsDehoistedField:
+ public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
+ {}; // NOLINT
+ uint32_t bit_field_;
};
@@ -4147,6 +4416,7 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> {
virtual void PrintDataTo(StringStream* stream);
virtual Representation RequiredInputRepresentation(int index) {
+ // tagged[tagged]
return Representation::Tagged();
}
@@ -4204,6 +4474,10 @@ class HStoreNamedField: public HTemplateInstruction<2> {
ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
}
+ bool NeedsWriteBarrierForMap() {
+ return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
+ }
+
private:
Handle<String> name_;
bool is_in_object_;
@@ -4248,83 +4522,56 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> {
};
-class HStoreKeyedFastElement
+class HStoreKeyed
: public HTemplateInstruction<3>, public ArrayInstructionInterface {
public:
- HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val,
- ElementsKind elements_kind = FAST_ELEMENTS)
+ HStoreKeyed(HValue* obj, HValue* key, HValue* val,
+ ElementsKind elements_kind)
: elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
SetOperandAt(2, val);
- SetGVNFlag(kChangesArrayElements);
- }
-
- virtual Representation RequiredInputRepresentation(int index) {
- // The key is supposed to be Integer32.
- return index == 1
- ? Representation::Integer32()
- : Representation::Tagged();
- }
-
- HValue* object() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- HValue* value() { return OperandAt(2); }
- bool value_is_smi() {
- return elements_kind_ == FAST_SMI_ONLY_ELEMENTS;
- }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
- bool NeedsWriteBarrier() {
- if (value_is_smi()) {
- return false;
+ if (is_external()) {
+ SetGVNFlag(kChangesSpecializedArrayElements);
+ } else if (IsFastDoubleElementsKind(elements_kind)) {
+ SetGVNFlag(kChangesDoubleArrayElements);
+ SetFlag(kDeoptimizeOnUndefined);
} else {
- return StoringValueNeedsWriteBarrier(value());
+ SetGVNFlag(kChangesArrayElements);
}
}
- virtual void PrintDataTo(StringStream* stream);
-
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement)
-
- private:
- ElementsKind elements_kind_;
- uint32_t index_offset_;
- bool is_dehoisted_;
-};
-
-
-class HStoreKeyedFastDoubleElement
- : public HTemplateInstruction<3>, public ArrayInstructionInterface {
- public:
- HStoreKeyedFastDoubleElement(HValue* elements,
- HValue* key,
- HValue* val)
- : index_offset_(0), is_dehoisted_(false) {
- SetOperandAt(0, elements);
- SetOperandAt(1, key);
- SetOperandAt(2, val);
- SetGVNFlag(kChangesDoubleArrayElements);
- }
-
virtual Representation RequiredInputRepresentation(int index) {
- if (index == 1) {
+ // kind_fast: tagged[int32] = tagged
+ // kind_double: tagged[int32] = double
+ // kind_external: external[int32] = (double | int32)
+ if (index == 0) {
+ return is_external() ? Representation::External()
+ : Representation::Tagged();
+ } else if (index == 1) {
return Representation::Integer32();
- } else if (index == 2) {
+ }
+
+ ASSERT_EQ(index, 2);
+ if (IsDoubleOrFloatElementsKind(elements_kind())) {
return Representation::Double();
- } else {
- return Representation::Tagged();
}
+
+ return is_external() ? Representation::Integer32()
+ : Representation::Tagged();
}
+ bool is_external() const {
+ return IsExternalArrayElementsKind(elements_kind());
+ }
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
+ bool value_is_smi() const {
+ return IsFastSmiElementsKind(elements_kind_);
+ }
+ ElementsKind elements_kind() const { return elements_kind_; }
uint32_t index_offset() { return index_offset_; }
void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
HValue* GetKey() { return key(); }
@@ -4333,64 +4580,18 @@ class HStoreKeyedFastDoubleElement
void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
bool NeedsWriteBarrier() {
- return StoringValueNeedsWriteBarrier(value());
+ if (value_is_smi()) {
+ return false;
+ } else {
+ return StoringValueNeedsWriteBarrier(value());
+ }
}
bool NeedsCanonicalization();
virtual void PrintDataTo(StringStream* stream);
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
-
- private:
- uint32_t index_offset_;
- bool is_dehoisted_;
-};
-
-
-class HStoreKeyedSpecializedArrayElement
- : public HTemplateInstruction<3>, public ArrayInstructionInterface {
- public:
- HStoreKeyedSpecializedArrayElement(HValue* external_elements,
- HValue* key,
- HValue* val,
- ElementsKind elements_kind)
- : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) {
- SetGVNFlag(kChangesSpecializedArrayElements);
- SetOperandAt(0, external_elements);
- SetOperandAt(1, key);
- SetOperandAt(2, val);
- }
-
- virtual void PrintDataTo(StringStream* stream);
-
- virtual Representation RequiredInputRepresentation(int index) {
- if (index == 0) {
- return Representation::External();
- } else {
- bool float_or_double_elements =
- elements_kind() == EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind() == EXTERNAL_DOUBLE_ELEMENTS;
- if (index == 2 && float_or_double_elements) {
- return Representation::Double();
- } else {
- return Representation::Integer32();
- }
- }
- }
-
- HValue* external_pointer() { return OperandAt(0); }
- HValue* key() { return OperandAt(1); }
- HValue* value() { return OperandAt(2); }
- ElementsKind elements_kind() const { return elements_kind_; }
- uint32_t index_offset() { return index_offset_; }
- void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; }
- HValue* GetKey() { return key(); }
- void SetKey(HValue* key) { SetOperandAt(1, key); }
- bool IsDehoisted() { return is_dehoisted_; }
- void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; }
-
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
private:
ElementsKind elements_kind_;
@@ -4421,6 +4622,7 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> {
StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
virtual Representation RequiredInputRepresentation(int index) {
+ // tagged[tagged] = tagged
return Representation::Tagged();
}
@@ -4443,8 +4645,14 @@ class HTransitionElementsKind: public HTemplateInstruction<1> {
SetOperandAt(0, object);
SetFlag(kUseGVN);
SetGVNFlag(kChangesElementsKind);
- SetGVNFlag(kChangesElementsPointer);
- SetGVNFlag(kChangesNewSpacePromotion);
+ if (original_map->has_fast_double_elements()) {
+ SetGVNFlag(kChangesElementsPointer);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
+ if (transitioned_map->has_fast_double_elements()) {
+ SetGVNFlag(kChangesElementsPointer);
+ SetGVNFlag(kChangesNewSpacePromotion);
+ }
set_representation(Representation::Tagged());
}
@@ -4480,6 +4688,7 @@ class HStringAdd: public HBinaryOperation {
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetGVNFlag(kDependsOnMaps);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -4494,6 +4703,10 @@ class HStringAdd: public HBinaryOperation {
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+ // private:
+ // virtual bool IsDeletable() const { return true; }
};
@@ -4528,6 +4741,10 @@ class HStringCharCodeAt: public HTemplateInstruction<3> {
virtual Range* InferRange(Zone* zone) {
return new(zone) Range(0, String::kMaxUtf16CodeUnit);
}
+
+ // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+ // private:
+ // virtual bool IsDeletable() const { return true; }
};
@@ -4554,6 +4771,10 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
virtual bool DataEquals(HValue* other) { return true; }
DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
+
+ // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+ // private:
+ // virtual bool IsDeletable() const { return true; }
};
@@ -4582,6 +4803,9 @@ class HStringLength: public HUnaryOperation {
virtual Range* InferRange(Zone* zone) {
return new(zone) Range(0, String::kMaxLength);
}
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -4608,6 +4832,9 @@ class HAllocateObject: public HTemplateInstruction<1> {
DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
private:
+ // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+ // virtual bool IsDeletable() const { return true; }
+
Handle<JSFunction> constructor_;
};
@@ -4624,6 +4851,8 @@ class HMaterializedLiteral: public HTemplateInstruction<V> {
int depth() const { return depth_; }
private:
+ virtual bool IsDeletable() const { return true; }
+
int literal_index_;
int depth_;
};
@@ -4682,7 +4911,7 @@ class HArrayLiteral: public HMaterializedLiteral<1> {
HValue* context() { return OperandAt(0); }
ElementsKind boilerplate_elements_kind() const {
if (!boilerplate_object_->IsJSObject()) {
- return FAST_ELEMENTS;
+ return TERMINAL_FAST_ELEMENTS_KIND;
}
return Handle<JSObject>::cast(boilerplate_object_)->GetElementsKind();
}
@@ -4744,10 +4973,12 @@ class HObjectLiteral: public HMaterializedLiteral<1> {
class HRegExpLiteral: public HMaterializedLiteral<1> {
public:
HRegExpLiteral(HValue* context,
+ Handle<FixedArray> literals,
Handle<String> pattern,
Handle<String> flags,
int literal_index)
: HMaterializedLiteral<1>(literal_index, 0),
+ literals_(literals),
pattern_(pattern),
flags_(flags) {
SetOperandAt(0, context);
@@ -4755,6 +4986,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> {
}
HValue* context() { return OperandAt(0); }
+ Handle<FixedArray> literals() { return literals_; }
Handle<String> pattern() { return pattern_; }
Handle<String> flags() { return flags_; }
@@ -4766,6 +4998,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> {
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral)
private:
+ Handle<FixedArray> literals_;
Handle<String> pattern_;
Handle<String> flags_;
};
@@ -4795,6 +5028,8 @@ class HFunctionLiteral: public HTemplateInstruction<1> {
bool pretenure() const { return pretenure_; }
private:
+ virtual bool IsDeletable() const { return true; }
+
Handle<SharedFunctionInfo> shared_info_;
bool pretenure_;
};
@@ -4811,7 +5046,6 @@ class HTypeof: public HTemplateInstruction<2> {
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
- virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual Representation RequiredInputRepresentation(int index) {
@@ -4819,6 +5053,9 @@ class HTypeof: public HTemplateInstruction<2> {
}
DECLARE_CONCRETE_INSTRUCTION(Typeof)
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -4837,6 +5074,9 @@ class HToFastProperties: public HUnaryOperation {
}
DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -4851,6 +5091,9 @@ class HValueOf: public HUnaryOperation {
}
DECLARE_CONCRETE_INSTRUCTION(ValueOf)
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};
@@ -5047,6 +5290,9 @@ class HLoadFieldByIndex : public HTemplateInstruction<2> {
}
DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
+
+ private:
+ virtual bool IsDeletable() const { return true; }
};