aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Chromium Automerger <chromium-automerger@android>2014-11-06 12:27:01 +0000
committerAndroid Chromium Automerger <chromium-automerger@android>2014-11-06 12:27:01 +0000
commit1be894bddf75cd9c7c7fb70be799509a9bb5db67 (patch)
treec7a2c40173c3580552bf9be3f44d0f03dc34c253
parentd07e97064dabc32fba2092ff45db7d74a2cf650b (diff)
parentbb795f939b910c87673062e98640d11a20fe258d (diff)
downloadv8-1be894bddf75cd9c7c7fb70be799509a9bb5db67.tar.gz
Merge v8 from https://chromium.googlesource.com/v8/v8.git at bb795f939b910c87673062e98640d11a20fe258d
This commit was generated by merge_from_chromium.py. Change-Id: I22d0044df55087fb517c35c392ad4f08a4b6bbd2
-rw-r--r--src/arm64/delayed-masm-arm64.cc4
-rw-r--r--src/ast.cc21
-rw-r--r--src/ast.h191
-rw-r--r--src/base/atomicops_internals_mac.h23
-rw-r--r--src/compiler/ast-graph-builder.cc20
-rw-r--r--src/compiler/ast-graph-builder.h4
-rw-r--r--src/compiler/register-allocator.cc304
-rw-r--r--src/compiler/register-allocator.h18
-rw-r--r--src/compiler/scheduler.cc19
-rw-r--r--src/heap-snapshot-generator-inl.h2
-rw-r--r--src/heap-snapshot-generator.cc6
-rw-r--r--src/heap-snapshot-generator.h18
-rw-r--r--src/hydrogen-instructions.cc252
-rw-r--r--src/hydrogen-instructions.h351
-rw-r--r--src/profile-generator-inl.h15
-rw-r--r--src/profile-generator.cc20
-rw-r--r--src/profile-generator.h13
-rw-r--r--src/runtime/runtime-array.cc36
-rw-r--r--src/scanner.cc25
-rw-r--r--src/unicode-inl.h2
-rw-r--r--src/unicode.h23
-rw-r--r--src/utils.h8
-rw-r--r--src/version.cc2
-rw-r--r--test/mjsunit/mjsunit.status7
-rw-r--r--test/mjsunit/regress/regress-assignment-in-test-context.js20
-rw-r--r--test/unittests/compiler/mips/instruction-selector-mips-unittest.cc10
-rwxr-xr-xtools/push-to-trunk/merge_to_branch.py89
-rwxr-xr-xtools/push-to-trunk/releases.py25
-rw-r--r--tools/push-to-trunk/test_scripts.py220
-rwxr-xr-xtools/run-tests.py8
-rw-r--r--tools/testrunner/local/testsuite.py13
-rw-r--r--tools/whitespace.txt2
32 files changed, 977 insertions, 794 deletions
diff --git a/src/arm64/delayed-masm-arm64.cc b/src/arm64/delayed-masm-arm64.cc
index c3bda915e..b51e77ec8 100644
--- a/src/arm64/delayed-masm-arm64.cc
+++ b/src/arm64/delayed-masm-arm64.cc
@@ -16,8 +16,8 @@ namespace internal {
void DelayedMasm::StackSlotMove(LOperand* src, LOperand* dst) {
- DCHECK(src->IsStackSlot());
- DCHECK(dst->IsStackSlot());
+ DCHECK((src->IsStackSlot() && dst->IsStackSlot()) ||
+ (src->IsDoubleStackSlot() && dst->IsDoubleStackSlot()));
MemOperand src_operand = cgen_->ToMemOperand(src);
MemOperand dst_operand = cgen_->ToMemOperand(dst);
if (pending_ == kStackSlotMove) {
diff --git a/src/ast.cc b/src/ast.cc
index 1df668ddf..26bc49155 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -61,9 +61,9 @@ bool Expression::IsUndefinedLiteral(Isolate* isolate) const {
VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
: Expression(zone, position),
- is_this_(var->is_this()),
- is_assigned_(false),
- is_resolved_(false),
+ bit_field_(IsThisField::encode(var->is_this()) |
+ IsAssignedField::encode(false) |
+ IsResolvedField::encode(false)),
variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
raw_name_(var->raw_name()),
interface_(var->interface()) {
@@ -74,9 +74,8 @@ VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
Interface* interface, int position)
: Expression(zone, position),
- is_this_(is_this),
- is_assigned_(false),
- is_resolved_(false),
+ bit_field_(IsThisField::encode(is_this) | IsAssignedField::encode(false) |
+ IsResolvedField::encode(false)),
variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
raw_name_(name),
interface_(interface) {}
@@ -99,17 +98,17 @@ void VariableProxy::BindTo(Variable* var) {
Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
Expression* value, int pos)
: Expression(zone, pos),
- is_uninitialized_(false),
- key_type_(ELEMENT),
- store_mode_(STANDARD_STORE),
- op_(op),
+ bit_field_(IsUninitializedField::encode(false) |
+ KeyTypeField::encode(ELEMENT) |
+ StoreModeField::encode(STANDARD_STORE) |
+ TokenField::encode(op)),
target_(target),
value_(value),
binary_operation_(NULL) {}
Token::Value Assignment::binary_op() const {
- switch (op_) {
+ switch (op()) {
case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
diff --git a/src/ast.h b/src/ast.h
index aa23b4e23..749e57999 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -359,11 +359,16 @@ class Expression : public AstNode {
void set_bounds(Bounds bounds) { bounds_ = bounds; }
// Whether the expression is parenthesized
- bool is_parenthesized() const { return is_parenthesized_; }
- bool is_multi_parenthesized() const { return is_multi_parenthesized_; }
+ bool is_parenthesized() const {
+ return IsParenthesizedField::decode(bit_field_);
+ }
+ bool is_multi_parenthesized() const {
+ return IsMultiParenthesizedField::decode(bit_field_);
+ }
void increase_parenthesization_level() {
- is_multi_parenthesized_ = is_parenthesized_;
- is_parenthesized_ = true;
+ bit_field_ =
+ IsMultiParenthesizedField::update(bit_field_, is_parenthesized());
+ bit_field_ = IsParenthesizedField::update(bit_field_, true);
}
// Type feedback information for assignments and properties.
@@ -375,18 +380,20 @@ class Expression : public AstNode {
UNREACHABLE();
return NULL;
}
- virtual KeyedAccessStoreMode GetStoreMode() {
+ virtual KeyedAccessStoreMode GetStoreMode() const {
UNREACHABLE();
return STANDARD_STORE;
}
- virtual IcCheckType GetKeyType() {
+ virtual IcCheckType GetKeyType() const {
UNREACHABLE();
return ELEMENT;
}
// TODO(rossberg): this should move to its own AST node eventually.
virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
- byte to_boolean_types() const { return to_boolean_types_; }
+ byte to_boolean_types() const {
+ return ToBooleanTypesField::decode(bit_field_);
+ }
void set_base_id(int id) { base_id_ = id; }
static int num_ids() { return parent_num_ids() + 2; }
@@ -398,10 +405,11 @@ class Expression : public AstNode {
: AstNode(pos),
base_id_(BailoutId::None().ToInt()),
bounds_(Bounds::Unbounded(zone)),
- is_parenthesized_(false),
- is_multi_parenthesized_(false) {}
+ bit_field_(0) {}
static int parent_num_ids() { return 0; }
- void set_to_boolean_types(byte types) { to_boolean_types_ = types; }
+ void set_to_boolean_types(byte types) {
+ bit_field_ = ToBooleanTypesField::update(bit_field_, types);
+ }
int base_id() const {
DCHECK(!BailoutId(base_id_).IsNone());
@@ -413,9 +421,12 @@ class Expression : public AstNode {
int base_id_;
Bounds bounds_;
- byte to_boolean_types_;
- bool is_parenthesized_ : 1;
- bool is_multi_parenthesized_ : 1;
+ class ToBooleanTypesField : public BitField16<byte, 0, 8> {};
+ class IsParenthesizedField : public BitField16<bool, 8, 1> {};
+ class IsMultiParenthesizedField : public BitField16<bool, 9, 1> {};
+ uint16_t bit_field_;
+ // Ends with 16-bit field; deriving classes in turn begin with
+ // 16-bit fields for optimum packing efficiency.
};
@@ -1697,13 +1708,17 @@ class VariableProxy FINAL : public Expression {
var_ = v;
}
- bool is_this() const { return is_this_; }
+ bool is_this() const { return IsThisField::decode(bit_field_); }
- bool is_assigned() const { return is_assigned_; }
- void set_is_assigned() { is_assigned_ = true; }
+ bool is_assigned() const { return IsAssignedField::decode(bit_field_); }
+ void set_is_assigned() {
+ bit_field_ = IsAssignedField::update(bit_field_, true);
+ }
- bool is_resolved() const { return is_resolved_; }
- void set_is_resolved() { is_resolved_ = true; }
+ bool is_resolved() const { return IsResolvedField::decode(bit_field_); }
+ void set_is_resolved() {
+ bit_field_ = IsResolvedField::update(bit_field_, true);
+ }
Interface* interface() const { return interface_; }
@@ -1727,9 +1742,13 @@ class VariableProxy FINAL : public Expression {
VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
Interface* interface, int position);
- bool is_this_ : 1;
- bool is_assigned_ : 1;
- bool is_resolved_ : 1;
+ class IsThisField : public BitField8<bool, 0, 1> {};
+ class IsAssignedField : public BitField8<bool, 1, 1> {};
+ class IsResolvedField : public BitField8<bool, 2, 1> {};
+
+ // Start with 16-bit (or smaller) field, which should get packed together
+ // with Expression's trailing 16-bit field.
+ uint8_t bit_field_;
FeedbackVectorICSlot variable_feedback_slot_;
union {
const AstRawString* raw_name_; // if !is_resolved_
@@ -1752,7 +1771,9 @@ class Property FINAL : public Expression {
BailoutId LoadId() const { return BailoutId(local_id(0)); }
TypeFeedbackId PropertyFeedbackId() { return TypeFeedbackId(local_id(1)); }
- bool IsStringAccess() const { return is_string_access_; }
+ bool IsStringAccess() const {
+ return IsStringAccessField::decode(bit_field_);
+ }
// Type feedback information.
virtual bool IsMonomorphic() OVERRIDE {
@@ -1761,21 +1782,29 @@ class Property FINAL : public Expression {
virtual SmallMapList* GetReceiverTypes() OVERRIDE {
return &receiver_types_;
}
- virtual KeyedAccessStoreMode GetStoreMode() OVERRIDE {
+ virtual KeyedAccessStoreMode GetStoreMode() const OVERRIDE {
return STANDARD_STORE;
}
- virtual IcCheckType GetKeyType() OVERRIDE {
+ virtual IcCheckType GetKeyType() const OVERRIDE {
// PROPERTY key types currently aren't implemented for KeyedLoadICs.
return ELEMENT;
}
- bool IsUninitialized() { return !is_for_call_ && is_uninitialized_; }
- bool HasNoTypeInformation() {
- return is_uninitialized_;
+ bool IsUninitialized() const {
+ return !is_for_call() && HasNoTypeInformation();
+ }
+ bool HasNoTypeInformation() const {
+ return IsUninitializedField::decode(bit_field_);
+ }
+ void set_is_uninitialized(bool b) {
+ bit_field_ = IsUninitializedField::update(bit_field_, b);
}
- void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
- void set_is_string_access(bool b) { is_string_access_ = b; }
- void mark_for_call() { is_for_call_ = true; }
- bool IsForCall() { return is_for_call_; }
+ void set_is_string_access(bool b) {
+ bit_field_ = IsStringAccessField::update(bit_field_, b);
+ }
+ void mark_for_call() {
+ bit_field_ = IsForCallField::update(bit_field_, true);
+ }
+ bool is_for_call() const { return IsForCallField::decode(bit_field_); }
bool IsSuperAccess() {
return obj()->IsSuperReference();
@@ -1795,9 +1824,9 @@ class Property FINAL : public Expression {
protected:
Property(Zone* zone, Expression* obj, Expression* key, int pos)
: Expression(zone, pos),
- is_for_call_(false),
- is_uninitialized_(false),
- is_string_access_(false),
+ bit_field_(IsForCallField::encode(false) |
+ IsUninitializedField::encode(false) |
+ IsStringAccessField::encode(false)),
property_feedback_slot_(FeedbackVectorICSlot::Invalid()),
obj_(obj),
key_(key) {}
@@ -1806,9 +1835,10 @@ class Property FINAL : public Expression {
private:
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
- bool is_for_call_ : 1;
- bool is_uninitialized_ : 1;
- bool is_string_access_ : 1;
+ class IsForCallField : public BitField8<bool, 0, 1> {};
+ class IsUninitializedField : public BitField8<bool, 1, 1> {};
+ class IsStringAccessField : public BitField8<bool, 2, 1> {};
+ uint8_t bit_field_;
FeedbackVectorICSlot property_feedback_slot_;
Expression* obj_;
Expression* key_;
@@ -2120,10 +2150,10 @@ class CountOperation FINAL : public Expression {
public:
DECLARE_NODE_TYPE(CountOperation)
- bool is_prefix() const { return is_prefix_; }
- bool is_postfix() const { return !is_prefix_; }
+ bool is_prefix() const { return IsPrefixField::decode(bit_field_); }
+ bool is_postfix() const { return !is_prefix(); }
- Token::Value op() const { return op_; }
+ Token::Value op() const { return TokenField::decode(bit_field_); }
Token::Value binary_op() {
return (op() == Token::INC) ? Token::ADD : Token::SUB;
}
@@ -2136,13 +2166,19 @@ class CountOperation FINAL : public Expression {
virtual SmallMapList* GetReceiverTypes() OVERRIDE {
return &receiver_types_;
}
- virtual IcCheckType GetKeyType() OVERRIDE { return key_type_; }
- virtual KeyedAccessStoreMode GetStoreMode() OVERRIDE {
- return store_mode_;
+ virtual IcCheckType GetKeyType() const OVERRIDE {
+ return KeyTypeField::decode(bit_field_);
+ }
+ virtual KeyedAccessStoreMode GetStoreMode() const OVERRIDE {
+ return StoreModeField::decode(bit_field_);
}
Type* type() const { return type_; }
- void set_key_type(IcCheckType type) { key_type_ = type; }
- void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; }
+ void set_key_type(IcCheckType type) {
+ bit_field_ = KeyTypeField::update(bit_field_, type);
+ }
+ void set_store_mode(KeyedAccessStoreMode mode) {
+ bit_field_ = StoreModeField::update(bit_field_, mode);
+ }
void set_type(Type* type) { type_ = type; }
static int num_ids() { return parent_num_ids() + 3; }
@@ -2158,21 +2194,25 @@ class CountOperation FINAL : public Expression {
CountOperation(Zone* zone, Token::Value op, bool is_prefix, Expression* expr,
int pos)
: Expression(zone, pos),
- op_(op),
- is_prefix_(is_prefix),
- key_type_(ELEMENT),
- store_mode_(STANDARD_STORE),
+ bit_field_(IsPrefixField::encode(is_prefix) |
+ KeyTypeField::encode(ELEMENT) |
+ StoreModeField::encode(STANDARD_STORE) |
+ TokenField::encode(op)),
+ type_(NULL),
expression_(expr) {}
static int parent_num_ids() { return Expression::num_ids(); }
private:
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
- Token::Value op_;
- bool is_prefix_ : 1;
- IcCheckType key_type_ : 1;
- KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
- // must have extra bit.
+ class IsPrefixField : public BitField16<bool, 0, 1> {};
+ class KeyTypeField : public BitField16<IcCheckType, 1, 1> {};
+ class StoreModeField : public BitField16<KeyedAccessStoreMode, 2, 4> {};
+ class TokenField : public BitField16<Token::Value, 6, 8> {};
+
+ // Starts with 16-bit field, which should get packed together with
+ // Expression's trailing 16-bit field.
+ uint16_t bit_field_;
Type* type_;
Expression* expression_;
SmallMapList receiver_types_;
@@ -2261,7 +2301,7 @@ class Assignment FINAL : public Expression {
Token::Value binary_op() const;
- Token::Value op() const { return op_; }
+ Token::Value op() const { return TokenField::decode(bit_field_); }
Expression* target() const { return target_; }
Expression* value() const { return value_; }
BinaryOperation* binary_operation() const { return binary_operation_; }
@@ -2277,20 +2317,30 @@ class Assignment FINAL : public Expression {
virtual bool IsMonomorphic() OVERRIDE {
return receiver_types_.length() == 1;
}
- bool IsUninitialized() { return is_uninitialized_; }
+ bool IsUninitialized() const {
+ return IsUninitializedField::decode(bit_field_);
+ }
bool HasNoTypeInformation() {
- return is_uninitialized_;
+ return IsUninitializedField::decode(bit_field_);
}
virtual SmallMapList* GetReceiverTypes() OVERRIDE {
return &receiver_types_;
}
- virtual IcCheckType GetKeyType() OVERRIDE { return key_type_; }
- virtual KeyedAccessStoreMode GetStoreMode() OVERRIDE {
- return store_mode_;
+ virtual IcCheckType GetKeyType() const OVERRIDE {
+ return KeyTypeField::decode(bit_field_);
+ }
+ virtual KeyedAccessStoreMode GetStoreMode() const OVERRIDE {
+ return StoreModeField::decode(bit_field_);
+ }
+ void set_is_uninitialized(bool b) {
+ bit_field_ = IsUninitializedField::update(bit_field_, b);
+ }
+ void set_key_type(IcCheckType key_type) {
+ bit_field_ = KeyTypeField::update(bit_field_, key_type);
+ }
+ void set_store_mode(KeyedAccessStoreMode mode) {
+ bit_field_ = StoreModeField::update(bit_field_, mode);
}
- void set_is_uninitialized(bool b) { is_uninitialized_ = b; }
- void set_key_type(IcCheckType key_type) { key_type_ = key_type; }
- void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; }
protected:
Assignment(Zone* zone, Token::Value op, Expression* target, Expression* value,
@@ -2299,7 +2349,7 @@ class Assignment FINAL : public Expression {
template <class Visitor>
void Init(AstNodeFactory<Visitor>* factory) {
- DCHECK(Token::IsAssignmentOp(op_));
+ DCHECK(Token::IsAssignmentOp(op()));
if (is_compound()) {
binary_operation_ = factory->NewBinaryOperation(
binary_op(), target_, value_, position() + 1);
@@ -2309,11 +2359,14 @@ class Assignment FINAL : public Expression {
private:
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
- bool is_uninitialized_ : 1;
- IcCheckType key_type_ : 1;
- KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
- // must have extra bit.
- Token::Value op_;
+ class IsUninitializedField : public BitField16<bool, 0, 1> {};
+ class KeyTypeField : public BitField16<IcCheckType, 1, 1> {};
+ class StoreModeField : public BitField16<KeyedAccessStoreMode, 2, 4> {};
+ class TokenField : public BitField16<Token::Value, 6, 8> {};
+
+ // Starts with 16-bit field, which should get packed together with
+ // Expression's trailing 16-bit field.
+ uint16_t bit_field_;
Expression* target_;
Expression* value_;
BinaryOperation* binary_operation_;
diff --git a/src/base/atomicops_internals_mac.h b/src/base/atomicops_internals_mac.h
index a046872e4..84f9dbcd7 100644
--- a/src/base/atomicops_internals_mac.h
+++ b/src/base/atomicops_internals_mac.h
@@ -12,6 +12,20 @@
namespace v8 {
namespace base {
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+inline void MemoryBarrier() { OSMemoryBarrier(); }
+
+inline void AcquireMemoryBarrier() {
+// On x86 processors, loads already have acquire semantics, so
+// there is no need to put a full barrier here.
+#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
+ ATOMICOPS_COMPILER_BARRIER();
+#else
+ MemoryBarrier();
+#endif
+}
+
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
@@ -46,10 +60,6 @@ inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
}
-inline void MemoryBarrier() {
- OSMemoryBarrier();
-}
-
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
@@ -98,7 +108,7 @@ inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
Atomic32 value = *ptr;
- MemoryBarrier();
+ AcquireMemoryBarrier();
return value;
}
@@ -188,7 +198,7 @@ inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
Atomic64 value = *ptr;
- MemoryBarrier();
+ AcquireMemoryBarrier();
return value;
}
@@ -199,6 +209,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
#endif // defined(__LP64__)
+#undef ATOMICOPS_COMPILER_BARRIER
} } // namespace v8::base
#endif // V8_BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
index 7b5abd191..805afc5a3 100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -1173,8 +1173,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
switch (assign_type) {
case VARIABLE: {
Variable* variable = expr->target()->AsVariableProxy()->var();
- BuildVariableAssignment(variable, value, expr->op(),
- expr->AssignmentId());
+ BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(),
+ ast_context()->GetStateCombine());
break;
}
case NAMED_PROPERTY: {
@@ -1183,7 +1183,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
Node* store =
NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
- PrepareFrameState(store, expr->AssignmentId());
+ PrepareFrameState(store, expr->AssignmentId(),
+ ast_context()->GetStateCombine());
break;
}
case KEYED_PROPERTY: {
@@ -1191,7 +1192,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
Node* object = environment()->Pop();
Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
key, value);
- PrepareFrameState(store, expr->AssignmentId());
+ PrepareFrameState(store, expr->AssignmentId(),
+ ast_context()->GetStateCombine());
break;
}
}
@@ -1957,9 +1959,9 @@ Node* AstGraphBuilder::BuildVariableDelete(
}
-Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
- Token::Value op,
- BailoutId bailout_id) {
+Node* AstGraphBuilder::BuildVariableAssignment(
+ Variable* variable, Node* value, Token::Value op, BailoutId bailout_id,
+ OutputFrameStateCombine combine) {
Node* the_hole = jsgraph()->TheHoleConstant();
VariableMode mode = variable->mode();
switch (variable->location()) {
@@ -1969,7 +1971,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
Unique<Name> name = MakeUnique(variable->name());
const Operator* op = javascript()->StoreNamed(strict_mode(), name);
Node* store = NewNode(op, global, value);
- PrepareFrameState(store, bailout_id);
+ PrepareFrameState(store, bailout_id, combine);
return store;
}
case Variable::PARAMETER:
@@ -2035,7 +2037,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
const Operator* op =
javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
Node* store = NewNode(op, value, current_context(), name, strict);
- PrepareFrameState(store, bailout_id);
+ PrepareFrameState(store, bailout_id, combine);
return store;
}
}
diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h
index 6e51723e0..518f23f46 100644
--- a/src/compiler/ast-graph-builder.h
+++ b/src/compiler/ast-graph-builder.h
@@ -80,7 +80,9 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
// Builders for variable load and assignment.
Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op,
- BailoutId bailout_id);
+ BailoutId bailout_id,
+ OutputFrameStateCombine state_combine =
+ OutputFrameStateCombine::Ignore());
Node* BuildVariableDelete(Variable* var, BailoutId bailout_id,
OutputFrameStateCombine state_combine);
Node* BuildVariableLoad(Variable* var, BailoutId bailout_id,
diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc
index 7a8276849..c65b906bb 100644
--- a/src/compiler/register-allocator.cc
+++ b/src/compiler/register-allocator.cc
@@ -199,7 +199,7 @@ bool LiveRange::CanBeSpilled(LifetimePosition pos) {
}
-InstructionOperand* LiveRange::CreateAssignedOperand(Zone* zone) {
+InstructionOperand* LiveRange::CreateAssignedOperand(Zone* zone) const {
InstructionOperand* op = NULL;
if (HasRegisterAssigned()) {
DCHECK(!IsSpilled());
@@ -507,23 +507,24 @@ LifetimePosition LiveRange::FirstIntersection(LiveRange* other) {
RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config,
- Zone* local_zone, Frame* frame,
+ Zone* zone, Frame* frame,
InstructionSequence* code,
const char* debug_name)
- : zone_(local_zone),
+ : local_zone_(zone),
frame_(frame),
code_(code),
debug_name_(debug_name),
config_(config),
- live_in_sets_(code->InstructionBlockCount(), zone()),
- live_ranges_(code->VirtualRegisterCount() * 2, zone()),
- fixed_live_ranges_(this->config()->num_general_registers(), NULL, zone()),
+ live_in_sets_(code->InstructionBlockCount(), local_zone()),
+ live_ranges_(code->VirtualRegisterCount() * 2, local_zone()),
+ fixed_live_ranges_(this->config()->num_general_registers(), NULL,
+ local_zone()),
fixed_double_live_ranges_(this->config()->num_double_registers(), NULL,
- zone()),
- unhandled_live_ranges_(code->VirtualRegisterCount() * 2, zone()),
- active_live_ranges_(8, zone()),
- inactive_live_ranges_(8, zone()),
- reusable_slots_(8, zone()),
+ local_zone()),
+ unhandled_live_ranges_(code->VirtualRegisterCount() * 2, local_zone()),
+ active_live_ranges_(8, local_zone()),
+ inactive_live_ranges_(8, local_zone()),
+ reusable_slots_(8, local_zone()),
mode_(UNALLOCATED_REGISTERS),
num_registers_(-1),
allocation_ok_(true) {
@@ -541,16 +542,16 @@ RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config,
void RegisterAllocator::InitializeLivenessAnalysis() {
// Initialize the live_in sets for each block to NULL.
int block_count = code()->InstructionBlockCount();
- live_in_sets_.Initialize(block_count, zone());
- live_in_sets_.AddBlock(NULL, block_count, zone());
+ live_in_sets_.Initialize(block_count, local_zone());
+ live_in_sets_.AddBlock(NULL, block_count, local_zone());
}
BitVector* RegisterAllocator::ComputeLiveOut(const InstructionBlock* block) {
// Compute live out for the given block, except not including backward
// successor edges.
- BitVector* live_out =
- new (zone()) BitVector(code()->VirtualRegisterCount(), zone());
+ BitVector* live_out = new (local_zone())
+ BitVector(code()->VirtualRegisterCount(), local_zone());
// Process all successor blocks.
for (auto succ : block->successors()) {
@@ -584,7 +585,7 @@ void RegisterAllocator::AddInitialIntervals(const InstructionBlock* block,
while (!iterator.Done()) {
int operand_index = iterator.Current();
LiveRange* range = LiveRangeFor(operand_index);
- range->AddUseInterval(start, end, zone());
+ range->AddUseInterval(start, end, local_zone());
iterator.Advance();
}
}
@@ -630,7 +631,7 @@ LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) {
// The LiveRange object itself can go in this zone, but the
// InstructionOperand needs
// to go in the code zone, since it may survive register allocation.
- result = new (zone()) LiveRange(FixedLiveRangeID(index), code_zone());
+ result = new (local_zone()) LiveRange(FixedLiveRangeID(index), code_zone());
DCHECK(result->IsFixed());
result->kind_ = GENERAL_REGISTERS;
SetLiveRangeAssignedRegister(result, index);
@@ -644,7 +645,8 @@ LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) {
DCHECK(index < config()->num_aliased_double_registers());
LiveRange* result = fixed_double_live_ranges_[index];
if (result == NULL) {
- result = new (zone()) LiveRange(FixedDoubleLiveRangeID(index), code_zone());
+ result = new (local_zone())
+ LiveRange(FixedDoubleLiveRangeID(index), code_zone());
DCHECK(result->IsFixed());
result->kind_ = DOUBLE_REGISTERS;
SetLiveRangeAssignedRegister(result, index);
@@ -656,11 +658,12 @@ LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) {
LiveRange* RegisterAllocator::LiveRangeFor(int index) {
if (index >= live_ranges_.length()) {
- live_ranges_.AddBlock(NULL, index - live_ranges_.length() + 1, zone());
+ live_ranges_.AddBlock(NULL, index - live_ranges_.length() + 1,
+ local_zone());
}
LiveRange* result = live_ranges_[index];
if (result == NULL) {
- result = new (zone()) LiveRange(index, code_zone());
+ result = new (local_zone()) LiveRange(index, code_zone());
live_ranges_[index] = result;
}
return result;
@@ -694,15 +697,15 @@ void RegisterAllocator::Define(LifetimePosition position,
if (range->IsEmpty() || range->Start().Value() > position.Value()) {
// Can happen if there is a definition without use.
- range->AddUseInterval(position, position.NextInstruction(), zone());
- range->AddUsePosition(position.NextInstruction(), NULL, NULL, zone());
+ range->AddUseInterval(position, position.NextInstruction(), local_zone());
+ range->AddUsePosition(position.NextInstruction(), NULL, NULL, local_zone());
} else {
range->ShortenTo(position);
}
if (operand->IsUnallocated()) {
UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand);
- range->AddUsePosition(position, unalloc_operand, hint, zone());
+ range->AddUsePosition(position, unalloc_operand, hint, local_zone());
}
}
@@ -715,9 +718,9 @@ void RegisterAllocator::Use(LifetimePosition block_start,
if (range == NULL) return;
if (operand->IsUnallocated()) {
UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand);
- range->AddUsePosition(position, unalloc_operand, hint, zone());
+ range->AddUsePosition(position, unalloc_operand, hint, local_zone());
}
- range->AddUseInterval(block_start, position, zone());
+ range->AddUseInterval(block_start, position, local_zone());
}
@@ -1023,7 +1026,7 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
if (!IsOutputRegisterOf(instr, i)) {
LiveRange* range = FixedLiveRangeFor(i);
range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
- zone());
+ local_zone());
}
}
}
@@ -1033,7 +1036,7 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
if (!IsOutputDoubleRegisterOf(instr, i)) {
LiveRange* range = FixedDoubleLiveRangeFor(i);
range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
- zone());
+ local_zone());
}
}
}
@@ -1160,9 +1163,8 @@ bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
void RegisterAllocator::MeetRegisterConstraints() {
- for (int i = 0; i < code()->InstructionBlockCount(); ++i) {
- MeetRegisterConstraints(
- code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i)));
+ for (auto block : code()->instruction_blocks()) {
+ MeetRegisterConstraints(block);
if (!AllocationOk()) return;
}
}
@@ -1170,55 +1172,9 @@ void RegisterAllocator::MeetRegisterConstraints() {
void RegisterAllocator::ResolvePhis() {
// Process the blocks in reverse order.
- for (int i = code()->InstructionBlockCount() - 1; i >= 0; --i) {
- ResolvePhis(code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i)));
- }
-}
-
-
-void RegisterAllocator::ResolveControlFlow(LiveRange* range,
- const InstructionBlock* block,
- const InstructionBlock* pred) {
- LifetimePosition pred_end =
- LifetimePosition::FromInstructionIndex(pred->last_instruction_index());
- LifetimePosition cur_start =
- LifetimePosition::FromInstructionIndex(block->first_instruction_index());
- LiveRange* pred_cover = NULL;
- LiveRange* cur_cover = NULL;
- LiveRange* cur_range = range;
- while (cur_range != NULL && (cur_cover == NULL || pred_cover == NULL)) {
- if (cur_range->CanCover(cur_start)) {
- DCHECK(cur_cover == NULL);
- cur_cover = cur_range;
- }
- if (cur_range->CanCover(pred_end)) {
- DCHECK(pred_cover == NULL);
- pred_cover = cur_range;
- }
- cur_range = cur_range->next();
- }
-
- if (cur_cover->IsSpilled()) return;
- DCHECK(pred_cover != NULL && cur_cover != NULL);
- if (pred_cover != cur_cover) {
- InstructionOperand* pred_op =
- pred_cover->CreateAssignedOperand(code_zone());
- InstructionOperand* cur_op = cur_cover->CreateAssignedOperand(code_zone());
- if (!pred_op->Equals(cur_op)) {
- GapInstruction* gap = NULL;
- if (block->PredecessorCount() == 1) {
- gap = code()->GapAt(block->first_instruction_index());
- } else {
- DCHECK(pred->SuccessorCount() == 1);
- gap = GetLastGap(pred);
-
- Instruction* branch = InstructionAt(pred->last_instruction_index());
- DCHECK(!branch->HasPointerMap());
- USE(branch);
- }
- gap->GetOrCreateParallelMove(GapInstruction::START, code_zone())
- ->AddMove(pred_op, cur_op, code_zone());
- }
+ for (auto i = code()->instruction_blocks().rbegin();
+ i != code()->instruction_blocks().rend(); ++i) {
+ ResolvePhis(*i);
}
}
@@ -1288,20 +1244,146 @@ bool RegisterAllocator::CanEagerlyResolveControlFlow(
}
+namespace {
+
+class LiveRangeBound {
+ public:
+ explicit LiveRangeBound(const LiveRange* range)
+ : range_(range), start_(range->Start()), end_(range->End()) {
+ DCHECK(!range->IsEmpty());
+ }
+
+ bool CanCover(LifetimePosition position) {
+ return start_.Value() <= position.Value() &&
+ position.Value() < end_.Value();
+ }
+
+ const LiveRange* const range_;
+ const LifetimePosition start_;
+ const LifetimePosition end_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LiveRangeBound);
+};
+
+
+struct FindResult {
+ const LiveRange* cur_cover_;
+ const LiveRange* pred_cover_;
+};
+
+
+class LiveRangeBoundArray {
+ public:
+ LiveRangeBoundArray() : length_(0), start_(nullptr) {}
+
+ bool ShouldInitialize() { return start_ == NULL; }
+
+ void Initialize(Zone* zone, const LiveRange* const range) {
+ size_t length = 0;
+ for (const LiveRange* i = range; i != NULL; i = i->next()) length++;
+ start_ = zone->NewArray<LiveRangeBound>(static_cast<int>(length));
+ length_ = length;
+ LiveRangeBound* curr = start_;
+ for (const LiveRange* i = range; i != NULL; i = i->next(), ++curr) {
+ new (curr) LiveRangeBound(i);
+ }
+ }
+
+ LiveRangeBound* Find(const LifetimePosition position) const {
+ size_t left_index = 0;
+ size_t right_index = length_;
+ while (true) {
+ size_t current_index = left_index + (right_index - left_index) / 2;
+ DCHECK(right_index > current_index);
+ LiveRangeBound* bound = &start_[current_index];
+ if (bound->start_.Value() <= position.Value()) {
+ if (position.Value() < bound->end_.Value()) return bound;
+ DCHECK(left_index < current_index);
+ left_index = current_index;
+ } else {
+ right_index = current_index;
+ }
+ }
+ }
+
+ void Find(const InstructionBlock* block, const InstructionBlock* pred,
+ FindResult* result) const {
+ const LifetimePosition pred_end =
+ LifetimePosition::FromInstructionIndex(pred->last_instruction_index());
+ LiveRangeBound* bound = Find(pred_end);
+ result->pred_cover_ = bound->range_;
+ const LifetimePosition cur_start = LifetimePosition::FromInstructionIndex(
+ block->first_instruction_index());
+ // Common case.
+ if (bound->CanCover(cur_start)) {
+ result->cur_cover_ = bound->range_;
+ return;
+ }
+ result->cur_cover_ = Find(cur_start)->range_;
+ DCHECK(result->pred_cover_ != NULL && result->cur_cover_ != NULL);
+ }
+
+ private:
+ size_t length_;
+ LiveRangeBound* start_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiveRangeBoundArray);
+};
+
+
+class LiveRangeFinder {
+ public:
+ explicit LiveRangeFinder(const RegisterAllocator& allocator)
+ : allocator_(allocator),
+ bounds_length_(allocator.live_ranges().length()),
+ bounds_(allocator.local_zone()->NewArray<LiveRangeBoundArray>(
+ bounds_length_)) {
+ for (int i = 0; i < bounds_length_; ++i) {
+ new (&bounds_[i]) LiveRangeBoundArray();
+ }
+ }
+
+ LiveRangeBoundArray* ArrayFor(int operand_index) {
+ DCHECK(operand_index < bounds_length_);
+ const LiveRange* range = allocator_.live_ranges()[operand_index];
+ DCHECK(range != nullptr && !range->IsEmpty());
+ LiveRangeBoundArray* array = &bounds_[operand_index];
+ if (array->ShouldInitialize()) {
+ array->Initialize(allocator_.local_zone(), range);
+ }
+ return array;
+ }
+
+ private:
+ const RegisterAllocator& allocator_;
+ const int bounds_length_;
+ LiveRangeBoundArray* const bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder);
+};
+
+} // namespace
+
+
void RegisterAllocator::ResolveControlFlow() {
- for (int block_id = 1; block_id < code()->InstructionBlockCount();
- ++block_id) {
- const InstructionBlock* block =
- code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(block_id));
+ // Lazily linearize live ranges in memory for fast lookup.
+ LiveRangeFinder finder(*this);
+ for (auto block : code()->instruction_blocks()) {
if (CanEagerlyResolveControlFlow(block)) continue;
BitVector* live = live_in_sets_[block->rpo_number().ToInt()];
BitVector::Iterator iterator(live);
while (!iterator.Done()) {
- int operand_index = iterator.Current();
+ LiveRangeBoundArray* array = finder.ArrayFor(iterator.Current());
for (auto pred : block->predecessors()) {
- const InstructionBlock* cur = code()->InstructionBlockAt(pred);
- LiveRange* cur_range = LiveRangeFor(operand_index);
- ResolveControlFlow(cur_range, block, cur);
+ FindResult result;
+ const InstructionBlock* pred_block = code()->InstructionBlockAt(pred);
+ array->Find(block, pred_block, &result);
+ if (result.cur_cover_ == result.pred_cover_ ||
+ result.cur_cover_->IsSpilled())
+ continue;
+ ResolveControlFlow(block, result.cur_cover_, pred_block,
+ result.pred_cover_);
}
iterator.Advance();
}
@@ -1309,6 +1391,30 @@ void RegisterAllocator::ResolveControlFlow() {
}
+void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block,
+ const LiveRange* cur_cover,
+ const InstructionBlock* pred,
+ const LiveRange* pred_cover) {
+ InstructionOperand* pred_op = pred_cover->CreateAssignedOperand(code_zone());
+ InstructionOperand* cur_op = cur_cover->CreateAssignedOperand(code_zone());
+ if (!pred_op->Equals(cur_op)) {
+ GapInstruction* gap = NULL;
+ if (block->PredecessorCount() == 1) {
+ gap = code()->GapAt(block->first_instruction_index());
+ } else {
+ DCHECK(pred->SuccessorCount() == 1);
+ gap = GetLastGap(pred);
+
+ Instruction* branch = InstructionAt(pred->last_instruction_index());
+ DCHECK(!branch->HasPointerMap());
+ USE(branch);
+ }
+ gap->GetOrCreateParallelMove(GapInstruction::START, code_zone())
+ ->AddMove(pred_op, cur_op, code_zone());
+ }
+}
+
+
void RegisterAllocator::BuildLiveRanges() {
InitializeLivenessAnalysis();
// Process the blocks in reverse order.
@@ -1371,7 +1477,7 @@ void RegisterAllocator::BuildLiveRanges() {
while (!iterator.Done()) {
int operand_index = iterator.Current();
LiveRange* range = LiveRangeFor(operand_index);
- range->EnsureInterval(start, end, zone());
+ range->EnsureInterval(start, end, local_zone());
iterator.Advance();
}
@@ -1667,13 +1773,13 @@ RegisterKind RegisterAllocator::RequiredRegisterKind(
void RegisterAllocator::AddToActive(LiveRange* range) {
TraceAlloc("Add live range %d to active\n", range->id());
- active_live_ranges_.Add(range, zone());
+ active_live_ranges_.Add(range, local_zone());
}
void RegisterAllocator::AddToInactive(LiveRange* range) {
TraceAlloc("Add live range %d to inactive\n", range->id());
- inactive_live_ranges_.Add(range, zone());
+ inactive_live_ranges_.Add(range, local_zone());
}
@@ -1685,13 +1791,13 @@ void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) {
LiveRange* cur_range = unhandled_live_ranges_.at(i);
if (range->ShouldBeAllocatedBefore(cur_range)) {
TraceAlloc("Add live range %d to unhandled at %d\n", range->id(), i + 1);
- unhandled_live_ranges_.InsertAt(i + 1, range, zone());
+ unhandled_live_ranges_.InsertAt(i + 1, range, local_zone());
DCHECK(UnhandledIsSorted());
return;
}
}
TraceAlloc("Add live range %d to unhandled at start\n", range->id());
- unhandled_live_ranges_.InsertAt(0, range, zone());
+ unhandled_live_ranges_.InsertAt(0, range, local_zone());
DCHECK(UnhandledIsSorted());
}
@@ -1700,7 +1806,7 @@ void RegisterAllocator::AddToUnhandledUnsorted(LiveRange* range) {
if (range == NULL || range->IsEmpty()) return;
DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled());
TraceAlloc("Add live range %d to unhandled unsorted at end\n", range->id());
- unhandled_live_ranges_.Add(range, zone());
+ unhandled_live_ranges_.Add(range, local_zone());
}
@@ -1742,7 +1848,7 @@ void RegisterAllocator::FreeSpillSlot(LiveRange* range) {
InstructionOperand* spill_operand = range->TopLevel()->GetSpillOperand();
if (spill_operand->IsConstant()) return;
if (spill_operand->index() >= 0) {
- reusable_slots_.Add(range, zone());
+ reusable_slots_.Add(range, local_zone());
}
}
@@ -1771,7 +1877,7 @@ void RegisterAllocator::ActiveToHandled(LiveRange* range) {
void RegisterAllocator::ActiveToInactive(LiveRange* range) {
DCHECK(active_live_ranges_.Contains(range));
active_live_ranges_.RemoveElement(range);
- inactive_live_ranges_.Add(range, zone());
+ inactive_live_ranges_.Add(range, local_zone());
TraceAlloc("Moving live range %d from active to inactive\n", range->id());
}
@@ -1787,7 +1893,7 @@ void RegisterAllocator::InactiveToHandled(LiveRange* range) {
void RegisterAllocator::InactiveToActive(LiveRange* range) {
DCHECK(inactive_live_ranges_.Contains(range));
inactive_live_ranges_.RemoveElement(range);
- active_live_ranges_.Add(range, zone());
+ active_live_ranges_.Add(range, local_zone());
TraceAlloc("Moving live range %d from inactive to active\n", range->id());
}
@@ -2063,7 +2169,7 @@ LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range,
int vreg = GetVirtualRegister();
if (!AllocationOk()) return NULL;
LiveRange* result = LiveRangeFor(vreg);
- range->SplitAt(pos, result, zone());
+ range->SplitAt(pos, result, local_zone());
return result;
}
@@ -2171,10 +2277,10 @@ void RegisterAllocator::Spill(LiveRange* range) {
RegisterKind kind = range->Kind();
int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS);
if (kind == DOUBLE_REGISTERS) {
- op = DoubleStackSlotOperand::Create(index, zone());
+ op = DoubleStackSlotOperand::Create(index, local_zone());
} else {
DCHECK(kind == GENERAL_REGISTERS);
- op = StackSlotOperand::Create(index, zone());
+ op = StackSlotOperand::Create(index, local_zone());
}
}
first->SetSpillOperand(op);
diff --git a/src/compiler/register-allocator.h b/src/compiler/register-allocator.h
index b167437c5..a6578af7e 100644
--- a/src/compiler/register-allocator.h
+++ b/src/compiler/register-allocator.h
@@ -186,12 +186,15 @@ class LiveRange FINAL : public ZoneObject {
UsePosition* first_pos() const { return first_pos_; }
LiveRange* parent() const { return parent_; }
LiveRange* TopLevel() { return (parent_ == NULL) ? this : parent_; }
+ const LiveRange* TopLevel() const {
+ return (parent_ == NULL) ? this : parent_;
+ }
LiveRange* next() const { return next_; }
bool IsChild() const { return parent() != NULL; }
int id() const { return id_; }
bool IsFixed() const { return id_ < 0; }
bool IsEmpty() const { return first_interval() == NULL; }
- InstructionOperand* CreateAssignedOperand(Zone* zone);
+ InstructionOperand* CreateAssignedOperand(Zone* zone) const;
int assigned_register() const { return assigned_register_; }
int spill_start_index() const { return spill_start_index_; }
void set_assigned_register(int reg, Zone* zone);
@@ -337,6 +340,8 @@ class RegisterAllocator FINAL {
return fixed_double_live_ranges_;
}
InstructionSequence* code() const { return code_; }
+ // This zone is for datastructures only needed during register allocation.
+ Zone* local_zone() const { return local_zone_; }
private:
int GetVirtualRegister() {
@@ -356,9 +361,6 @@ class RegisterAllocator FINAL {
// Returns the register kind required by the given virtual register.
RegisterKind RequiredRegisterKind(int virtual_register) const;
- // This zone is for datastructures only needed during register allocation.
- Zone* zone() const { return zone_; }
-
// This zone is for InstructionOperands and moves that live beyond register
// allocation.
Zone* code_zone() const { return code()->zone(); }
@@ -465,8 +467,10 @@ class RegisterAllocator FINAL {
bool IsBlockBoundary(LifetimePosition pos);
// Helper methods for resolving control flow.
- void ResolveControlFlow(LiveRange* range, const InstructionBlock* block,
- const InstructionBlock* pred);
+ void ResolveControlFlow(const InstructionBlock* block,
+ const LiveRange* cur_cover,
+ const InstructionBlock* pred,
+ const LiveRange* pred_cover);
void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
@@ -494,7 +498,7 @@ class RegisterAllocator FINAL {
const char* debug_name() const { return debug_name_; }
const RegisterConfiguration* config() const { return config_; }
- Zone* const zone_;
+ Zone* const local_zone_;
Frame* const frame_;
InstructionSequence* const code_;
const char* const debug_name_;
diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc
index 9d0d7300c..92e05cb45 100644
--- a/src/compiler/scheduler.cc
+++ b/src/compiler/scheduler.cc
@@ -922,9 +922,9 @@ class SpecialRPONumberer : public ZoneObject {
// TODO(jarin,svenpanne): Add formatting here once we have support for
// that in streams (we want an equivalent of PrintF("%5d:", x) here).
os << " " << block->rpo_number() << ":";
- for (size_t j = 0; j < loops_.size(); j++) {
- bool membership = loops_[j].members->Contains(bid.ToInt());
- bool range = loops_[j].header->LoopContains(block);
+ for (size_t i = 0; i < loops_.size(); i++) {
+ bool range = loops_[i].header->LoopContains(block);
+ bool membership = loops_[i].header != block && range;
os << (membership ? " |" : " ");
os << (range ? "x" : " ");
}
@@ -982,23 +982,18 @@ class SpecialRPONumberer : public ZoneObject {
DCHECK(end_found);
// Check the contiguousness of loops.
- // TODO(mstarzinger): Loop membership bit-vector becomes stale.
- /*int count = 0;
+ int count = 0;
for (int j = 0; j < static_cast<int>(order->size()); j++) {
BasicBlock* block = order->at(j);
DCHECK(block->rpo_number() == j);
if (j < header->rpo_number() || j >= end->rpo_number()) {
- DCHECK(!loop->members->Contains(block->id().ToInt()));
+ DCHECK(!header->LoopContains(block));
} else {
- if (block == header) {
- DCHECK(!loop->members->Contains(block->id().ToInt()));
- } else {
- DCHECK(loop->members->Contains(block->id().ToInt()));
- }
+ DCHECK(header->LoopContains(block));
count++;
}
}
- DCHECK(links == count);*/
+ DCHECK(links == count);
}
}
#endif // DEBUG
diff --git a/src/heap-snapshot-generator-inl.h b/src/heap-snapshot-generator-inl.h
index 3f7e62216..ad95776cb 100644
--- a/src/heap-snapshot-generator-inl.h
+++ b/src/heap-snapshot-generator-inl.h
@@ -12,7 +12,7 @@ namespace internal {
HeapEntry* HeapGraphEdge::from() const {
- return &snapshot()->entries()[from_index_];
+ return &snapshot()->entries()[from_index()];
}
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index 68522fcce..7f217bb8d 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -18,8 +18,7 @@ namespace internal {
HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
- : type_(type),
- from_index_(from),
+ : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
to_index_(to),
name_(name) {
DCHECK(type == kContextVariable
@@ -31,8 +30,7 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
- : type_(type),
- from_index_(from),
+ : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
to_index_(to),
index_(index) {
DCHECK(type == kElement || type == kHidden);
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index 646d49708..fb4387617 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -28,22 +28,18 @@ class HeapGraphEdge BASE_EMBEDDED {
kWeak = v8::HeapGraphEdge::kWeak
};
- HeapGraphEdge() { }
HeapGraphEdge(Type type, const char* name, int from, int to);
HeapGraphEdge(Type type, int index, int from, int to);
void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
- Type type() const { return static_cast<Type>(type_); }
+ Type type() const { return TypeField::decode(bit_field_); }
int index() const {
- DCHECK(type_ == kElement || type_ == kHidden);
+ DCHECK(type() == kElement || type() == kHidden);
return index_;
}
const char* name() const {
- DCHECK(type_ == kContextVariable
- || type_ == kProperty
- || type_ == kInternal
- || type_ == kShortcut
- || type_ == kWeak);
+ DCHECK(type() == kContextVariable || type() == kProperty ||
+ type() == kInternal || type() == kShortcut || type() == kWeak);
return name_;
}
INLINE(HeapEntry* from() const);
@@ -51,9 +47,11 @@ class HeapGraphEdge BASE_EMBEDDED {
private:
INLINE(HeapSnapshot* snapshot() const);
+ int from_index() const { return FromIndexField::decode(bit_field_); }
- unsigned type_ : 3;
- int from_index_ : 29;
+ class TypeField : public BitField<Type, 0, 3> {};
+ class FromIndexField : public BitField<int, 3, 29> {};
+ uint32_t bit_field_;
union {
// During entries population |to_index_| is used for storing the index,
// afterwards it is replaced with a pointer to the entry.
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 188119d66..ce76fbeca 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1789,7 +1789,7 @@ Range* HChange::InferRange(Zone* zone) {
Range* HConstant::InferRange(Zone* zone) {
- if (has_int32_value_) {
+ if (HasInteger32Value()) {
Range* result = new(zone) Range(int32_value_, int32_value_);
result->set_can_be_minus_zero(false);
return result;
@@ -2606,7 +2606,7 @@ std::ostream& HSimulate::PrintDataTo(std::ostream& os) const { // NOLINT
void HSimulate::ReplayEnvironment(HEnvironment* env) {
- if (done_with_replay_) return;
+ if (is_done_with_replay()) return;
DCHECK(env != NULL);
env->set_ast_id(ast_id());
env->Drop(pop_count());
@@ -2618,7 +2618,7 @@ void HSimulate::ReplayEnvironment(HEnvironment* env) {
env->Push(value);
}
}
- done_with_replay_ = true;
+ set_done_with_replay();
}
@@ -2674,36 +2674,41 @@ static bool IsInteger32(double value) {
HConstant::HConstant(Handle<Object> object, Representation r)
- : HTemplateInstruction<0>(HType::FromValue(object)),
- object_(Unique<Object>::CreateUninitialized(object)),
- object_map_(Handle<Map>::null()),
- has_stable_map_value_(false),
- has_smi_value_(false),
- has_int32_value_(false),
- has_double_value_(false),
- has_external_reference_value_(false),
- is_not_in_new_space_(true),
- boolean_value_(object->BooleanValue()),
- is_undetectable_(false),
- instance_type_(kUnknownInstanceType) {
+ : HTemplateInstruction<0>(HType::FromValue(object)),
+ object_(Unique<Object>::CreateUninitialized(object)),
+ object_map_(Handle<Map>::null()),
+ bit_field_(HasStableMapValueField::encode(false) |
+ HasSmiValueField::encode(false) |
+ HasInt32ValueField::encode(false) |
+ HasDoubleValueField::encode(false) |
+ HasExternalReferenceValueField::encode(false) |
+ IsNotInNewSpaceField::encode(true) |
+ BooleanValueField::encode(object->BooleanValue()) |
+ IsUndetectableField::encode(false) |
+ InstanceTypeField::encode(kUnknownInstanceType)) {
if (object->IsHeapObject()) {
Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
Isolate* isolate = heap_object->GetIsolate();
Handle<Map> map(heap_object->map(), isolate);
- is_not_in_new_space_ = !isolate->heap()->InNewSpace(*object);
- instance_type_ = map->instance_type();
- is_undetectable_ = map->is_undetectable();
+ bit_field_ = IsNotInNewSpaceField::update(
+ bit_field_, !isolate->heap()->InNewSpace(*object));
+ bit_field_ = InstanceTypeField::update(bit_field_, map->instance_type());
+ bit_field_ =
+ IsUndetectableField::update(bit_field_, map->is_undetectable());
if (map->is_stable()) object_map_ = Unique<Map>::CreateImmovable(map);
- has_stable_map_value_ = (instance_type_ == MAP_TYPE &&
- Handle<Map>::cast(heap_object)->is_stable());
+ bit_field_ = HasStableMapValueField::update(
+ bit_field_,
+ HasMapValue() && Handle<Map>::cast(heap_object)->is_stable());
}
if (object->IsNumber()) {
double n = object->Number();
- has_int32_value_ = IsInteger32(n);
+ bool has_int32_value = IsInteger32(n);
+ bit_field_ = HasInt32ValueField::update(bit_field_, has_int32_value);
int32_value_ = DoubleToInt32(n);
- has_smi_value_ = has_int32_value_ && Smi::IsValid(int32_value_);
+ bit_field_ = HasSmiValueField::update(
+ bit_field_, has_int32_value && Smi::IsValid(int32_value_));
double_value_ = n;
- has_double_value_ = true;
+ bit_field_ = HasDoubleValueField::update(bit_field_, true);
// TODO(titzer): if this heap number is new space, tenure a new one.
}
@@ -2711,112 +2716,104 @@ HConstant::HConstant(Handle<Object> object, Representation r)
}
-HConstant::HConstant(Unique<Object> object,
- Unique<Map> object_map,
- bool has_stable_map_value,
- Representation r,
- HType type,
- bool is_not_in_new_space,
- bool boolean_value,
- bool is_undetectable,
- InstanceType instance_type)
- : HTemplateInstruction<0>(type),
- object_(object),
- object_map_(object_map),
- has_stable_map_value_(has_stable_map_value),
- has_smi_value_(false),
- has_int32_value_(false),
- has_double_value_(false),
- has_external_reference_value_(false),
- is_not_in_new_space_(is_not_in_new_space),
- boolean_value_(boolean_value),
- is_undetectable_(is_undetectable),
- instance_type_(instance_type) {
+HConstant::HConstant(Unique<Object> object, Unique<Map> object_map,
+ bool has_stable_map_value, Representation r, HType type,
+ bool is_not_in_new_space, bool boolean_value,
+ bool is_undetectable, InstanceType instance_type)
+ : HTemplateInstruction<0>(type),
+ object_(object),
+ object_map_(object_map),
+ bit_field_(HasStableMapValueField::encode(has_stable_map_value) |
+ HasSmiValueField::encode(false) |
+ HasInt32ValueField::encode(false) |
+ HasDoubleValueField::encode(false) |
+ HasExternalReferenceValueField::encode(false) |
+ IsNotInNewSpaceField::encode(is_not_in_new_space) |
+ BooleanValueField::encode(boolean_value) |
+ IsUndetectableField::encode(is_undetectable) |
+ InstanceTypeField::encode(instance_type)) {
DCHECK(!object.handle().is_null());
DCHECK(!type.IsTaggedNumber() || type.IsNone());
Initialize(r);
}
-HConstant::HConstant(int32_t integer_value,
- Representation r,
- bool is_not_in_new_space,
- Unique<Object> object)
- : object_(object),
- object_map_(Handle<Map>::null()),
- has_stable_map_value_(false),
- has_smi_value_(Smi::IsValid(integer_value)),
- has_int32_value_(true),
- has_double_value_(true),
- has_external_reference_value_(false),
- is_not_in_new_space_(is_not_in_new_space),
- boolean_value_(integer_value != 0),
- is_undetectable_(false),
- int32_value_(integer_value),
- double_value_(FastI2D(integer_value)),
- instance_type_(kUnknownInstanceType) {
+HConstant::HConstant(int32_t integer_value, Representation r,
+ bool is_not_in_new_space, Unique<Object> object)
+ : object_(object),
+ object_map_(Handle<Map>::null()),
+ bit_field_(HasStableMapValueField::encode(false) |
+ HasSmiValueField::encode(Smi::IsValid(integer_value)) |
+ HasInt32ValueField::encode(true) |
+ HasDoubleValueField::encode(true) |
+ HasExternalReferenceValueField::encode(false) |
+ IsNotInNewSpaceField::encode(is_not_in_new_space) |
+ BooleanValueField::encode(integer_value != 0) |
+ IsUndetectableField::encode(false) |
+ InstanceTypeField::encode(kUnknownInstanceType)),
+ int32_value_(integer_value),
+ double_value_(FastI2D(integer_value)) {
// It's possible to create a constant with a value in Smi-range but stored
// in a (pre-existing) HeapNumber. See crbug.com/349878.
bool could_be_heapobject = r.IsTagged() && !object.handle().is_null();
- bool is_smi = has_smi_value_ && !could_be_heapobject;
+ bool is_smi = HasSmiValue() && !could_be_heapobject;
set_type(is_smi ? HType::Smi() : HType::TaggedNumber());
Initialize(r);
}
-HConstant::HConstant(double double_value,
- Representation r,
- bool is_not_in_new_space,
- Unique<Object> object)
- : object_(object),
- object_map_(Handle<Map>::null()),
- has_stable_map_value_(false),
- has_int32_value_(IsInteger32(double_value)),
- has_double_value_(true),
- has_external_reference_value_(false),
- is_not_in_new_space_(is_not_in_new_space),
- boolean_value_(double_value != 0 && !std::isnan(double_value)),
- is_undetectable_(false),
- int32_value_(DoubleToInt32(double_value)),
- double_value_(double_value),
- instance_type_(kUnknownInstanceType) {
- has_smi_value_ = has_int32_value_ && Smi::IsValid(int32_value_);
+HConstant::HConstant(double double_value, Representation r,
+ bool is_not_in_new_space, Unique<Object> object)
+ : object_(object),
+ object_map_(Handle<Map>::null()),
+ bit_field_(HasStableMapValueField::encode(false) |
+ HasInt32ValueField::encode(IsInteger32(double_value)) |
+ HasDoubleValueField::encode(true) |
+ HasExternalReferenceValueField::encode(false) |
+ IsNotInNewSpaceField::encode(is_not_in_new_space) |
+ BooleanValueField::encode(double_value != 0 &&
+ !std::isnan(double_value)) |
+ IsUndetectableField::encode(false) |
+ InstanceTypeField::encode(kUnknownInstanceType)),
+ int32_value_(DoubleToInt32(double_value)),
+ double_value_(double_value) {
+ bit_field_ = HasSmiValueField::update(
+ bit_field_, HasInteger32Value() && Smi::IsValid(int32_value_));
// It's possible to create a constant with a value in Smi-range but stored
// in a (pre-existing) HeapNumber. See crbug.com/349878.
bool could_be_heapobject = r.IsTagged() && !object.handle().is_null();
- bool is_smi = has_smi_value_ && !could_be_heapobject;
+ bool is_smi = HasSmiValue() && !could_be_heapobject;
set_type(is_smi ? HType::Smi() : HType::TaggedNumber());
Initialize(r);
}
HConstant::HConstant(ExternalReference reference)
- : HTemplateInstruction<0>(HType::Any()),
- object_(Unique<Object>(Handle<Object>::null())),
- object_map_(Handle<Map>::null()),
- has_stable_map_value_(false),
- has_smi_value_(false),
- has_int32_value_(false),
- has_double_value_(false),
- has_external_reference_value_(true),
- is_not_in_new_space_(true),
- boolean_value_(true),
- is_undetectable_(false),
- external_reference_value_(reference),
- instance_type_(kUnknownInstanceType) {
+ : HTemplateInstruction<0>(HType::Any()),
+ object_(Unique<Object>(Handle<Object>::null())),
+ object_map_(Handle<Map>::null()),
+ bit_field_(
+ HasStableMapValueField::encode(false) |
+ HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) |
+ HasDoubleValueField::encode(false) |
+ HasExternalReferenceValueField::encode(true) |
+ IsNotInNewSpaceField::encode(true) | BooleanValueField::encode(true) |
+ IsUndetectableField::encode(false) |
+ InstanceTypeField::encode(kUnknownInstanceType)),
+ external_reference_value_(reference) {
Initialize(Representation::External());
}
void HConstant::Initialize(Representation r) {
if (r.IsNone()) {
- if (has_smi_value_ && SmiValuesAre31Bits()) {
+ if (HasSmiValue() && SmiValuesAre31Bits()) {
r = Representation::Smi();
- } else if (has_int32_value_) {
+ } else if (HasInteger32Value()) {
r = Representation::Integer32();
- } else if (has_double_value_) {
+ } else if (HasDoubleValue()) {
r = Representation::Double();
- } else if (has_external_reference_value_) {
+ } else if (HasExternalReferenceValue()) {
r = Representation::External();
} else {
Handle<Object> object = object_.handle();
@@ -2843,16 +2840,16 @@ void HConstant::Initialize(Representation r) {
bool HConstant::ImmortalImmovable() const {
- if (has_int32_value_) {
+ if (HasInteger32Value()) {
return false;
}
- if (has_double_value_) {
+ if (HasDoubleValue()) {
if (IsSpecialDouble()) {
return true;
}
return false;
}
- if (has_external_reference_value_) {
+ if (HasExternalReferenceValue()) {
return false;
}
@@ -2893,44 +2890,35 @@ bool HConstant::EmitAtUses() {
HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const {
- if (r.IsSmi() && !has_smi_value_) return NULL;
- if (r.IsInteger32() && !has_int32_value_) return NULL;
- if (r.IsDouble() && !has_double_value_) return NULL;
- if (r.IsExternal() && !has_external_reference_value_) return NULL;
- if (has_int32_value_) {
- return new(zone) HConstant(int32_value_, r, is_not_in_new_space_, object_);
+ if (r.IsSmi() && !HasSmiValue()) return NULL;
+ if (r.IsInteger32() && !HasInteger32Value()) return NULL;
+ if (r.IsDouble() && !HasDoubleValue()) return NULL;
+ if (r.IsExternal() && !HasExternalReferenceValue()) return NULL;
+ if (HasInteger32Value()) {
+ return new (zone) HConstant(int32_value_, r, NotInNewSpace(), object_);
}
- if (has_double_value_) {
- return new(zone) HConstant(double_value_, r, is_not_in_new_space_, object_);
+ if (HasDoubleValue()) {
+ return new (zone) HConstant(double_value_, r, NotInNewSpace(), object_);
}
- if (has_external_reference_value_) {
+ if (HasExternalReferenceValue()) {
return new(zone) HConstant(external_reference_value_);
}
DCHECK(!object_.handle().is_null());
- return new(zone) HConstant(object_,
- object_map_,
- has_stable_map_value_,
- r,
- type_,
- is_not_in_new_space_,
- boolean_value_,
- is_undetectable_,
- instance_type_);
+ return new (zone) HConstant(object_, object_map_, HasStableMapValue(), r,
+ type_, NotInNewSpace(), BooleanValue(),
+ IsUndetectable(), GetInstanceType());
}
Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) {
HConstant* res = NULL;
- if (has_int32_value_) {
- res = new(zone) HConstant(int32_value_,
- Representation::Integer32(),
- is_not_in_new_space_,
- object_);
- } else if (has_double_value_) {
- res = new(zone) HConstant(DoubleToInt32(double_value_),
- Representation::Integer32(),
- is_not_in_new_space_,
- object_);
+ if (HasInteger32Value()) {
+ res = new (zone) HConstant(int32_value_, Representation::Integer32(),
+ NotInNewSpace(), object_);
+ } else if (HasDoubleValue()) {
+ res = new (zone)
+ HConstant(DoubleToInt32(double_value_), Representation::Integer32(),
+ NotInNewSpace(), object_);
}
return Maybe<HConstant*>(res != NULL, res);
}
@@ -2952,11 +2940,11 @@ Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Zone* zone) {
std::ostream& HConstant::PrintDataTo(std::ostream& os) const { // NOLINT
- if (has_int32_value_) {
+ if (HasInteger32Value()) {
os << int32_value_ << " ";
- } else if (has_double_value_) {
+ } else if (HasDoubleValue()) {
os << double_value_ << " ";
- } else if (has_external_reference_value_) {
+ } else if (HasExternalReferenceValue()) {
os << reinterpret_cast<void*>(external_reference_value_.address()) << " ";
} else {
// The handle() method is silently and lazily mutating the object.
@@ -2965,7 +2953,7 @@ std::ostream& HConstant::PrintDataTo(std::ostream& os) const { // NOLINT
if (HasStableMapValue()) os << "[stable-map] ";
if (HasObjectMap()) os << "[map " << *ObjectMap().handle() << "] ";
}
- if (!is_not_in_new_space_) os << "[new space] ";
+ if (!NotInNewSpace()) os << "[new space] ";
return os;
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 810a2fdd5..233ca42f1 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -1497,13 +1497,18 @@ class HCompareMap FINAL : public HUnaryControlInstruction {
virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
static const int kNoKnownSuccessorIndex = -1;
- int known_successor_index() const { return known_successor_index_; }
- void set_known_successor_index(int known_successor_index) {
- known_successor_index_ = known_successor_index;
+ int known_successor_index() const {
+ return KnownSuccessorIndexField::decode(bit_field_) -
+ kInternalKnownSuccessorOffset;
+ }
+ void set_known_successor_index(int index) {
+ DCHECK(index >= 0 - kInternalKnownSuccessorOffset);
+ bit_field_ = KnownSuccessorIndexField::update(
+ bit_field_, index + kInternalKnownSuccessorOffset);
}
Unique<Map> map() const { return map_; }
- bool map_is_stable() const { return map_is_stable_; }
+ bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
return Representation::Tagged();
@@ -1515,19 +1520,25 @@ class HCompareMap FINAL : public HUnaryControlInstruction {
virtual int RedefinedOperandIndex() OVERRIDE { return 0; }
private:
- HCompareMap(HValue* value,
- Handle<Map> map,
- HBasicBlock* true_target = NULL,
+ HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL,
HBasicBlock* false_target = NULL)
: HUnaryControlInstruction(value, true_target, false_target),
- known_successor_index_(kNoKnownSuccessorIndex),
- map_is_stable_(map->is_stable()),
+ bit_field_(KnownSuccessorIndexField::encode(
+ kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) |
+ MapIsStableField::encode(map->is_stable())),
map_(Unique<Map>::CreateImmovable(map)) {
set_representation(Representation::Tagged());
}
- int known_successor_index_ : 31;
- bool map_is_stable_ : 1;
+ // BitFields can only store unsigned values, so use an offset.
+ // Adding kInternalKnownSuccessorOffset must yield an unsigned value.
+ static const int kInternalKnownSuccessorOffset = 1;
+ STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0);
+
+ class KnownSuccessorIndexField : public BitField<int, 0, 31> {};
+ class MapIsStableField : public BitField<bool, 31, 1> {};
+
+ uint32_t bit_field_;
Unique<Map> map_;
};
@@ -1803,17 +1814,15 @@ enum RemovableSimulate {
class HSimulate FINAL : public HInstruction {
public:
- HSimulate(BailoutId ast_id,
- int pop_count,
- Zone* zone,
+ HSimulate(BailoutId ast_id, int pop_count, Zone* zone,
RemovableSimulate removable)
: ast_id_(ast_id),
pop_count_(pop_count),
values_(2, zone),
assigned_indexes_(2, zone),
zone_(zone),
- removable_(removable),
- done_with_replay_(false) {}
+ bit_field_(RemovableField::encode(removable) |
+ DoneWithReplayField::encode(false)) {}
~HSimulate() {}
virtual std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
@@ -1857,7 +1866,9 @@ class HSimulate FINAL : public HInstruction {
}
void MergeWith(ZoneList<HSimulate*>* list);
- bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }
+ bool is_candidate_for_removal() {
+ return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE;
+ }
// Replay effects of this instruction on the given environment.
void ReplayEnvironment(HEnvironment* env);
@@ -1891,13 +1902,22 @@ class HSimulate FINAL : public HInstruction {
}
return false;
}
+ bool is_done_with_replay() const {
+ return DoneWithReplayField::decode(bit_field_);
+ }
+ void set_done_with_replay() {
+ bit_field_ = DoneWithReplayField::update(bit_field_, true);
+ }
+
+ class RemovableField : public BitField<RemovableSimulate, 0, 1> {};
+ class DoneWithReplayField : public BitField<bool, 1, 1> {};
+
BailoutId ast_id_;
int pop_count_;
ZoneList<HValue*> values_;
ZoneList<int> assigned_indexes_;
Zone* zone_;
- RemovableSimulate removable_ : 2;
- bool done_with_replay_ : 1;
+ uint32_t bit_field_;
#ifdef DEBUG
Handle<JSFunction> closure_;
@@ -2742,11 +2762,13 @@ class HCheckMaps FINAL : public HTemplateInstruction<2> {
return new(zone) HCheckMaps(value, maps, typecheck);
}
- bool IsStabilityCheck() const { return is_stability_check_; }
+ bool IsStabilityCheck() const {
+ return IsStabilityCheckField::decode(bit_field_);
+ }
void MarkAsStabilityCheck() {
- maps_are_stable_ = true;
- has_migration_target_ = false;
- is_stability_check_ = true;
+ bit_field_ = MapsAreStableField::encode(true) |
+ HasMigrationTargetField::encode(false) |
+ IsStabilityCheckField::encode(true);
ClearChangesFlag(kNewSpacePromotion);
ClearDependsOnFlag(kElementsKind);
ClearDependsOnFlag(kMaps);
@@ -2770,9 +2792,13 @@ class HCheckMaps FINAL : public HTemplateInstruction<2> {
const UniqueSet<Map>* maps() const { return maps_; }
void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
- bool maps_are_stable() const { return maps_are_stable_; }
+ bool maps_are_stable() const {
+ return MapsAreStableField::decode(bit_field_);
+ }
- bool HasMigrationTarget() const { return has_migration_target_; }
+ bool HasMigrationTarget() const {
+ return HasMigrationTargetField::decode(bit_field_);
+ }
virtual HValue* Canonicalize() OVERRIDE;
@@ -2804,9 +2830,11 @@ class HCheckMaps FINAL : public HTemplateInstruction<2> {
private:
HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
- : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
- has_migration_target_(false), is_stability_check_(false),
- maps_are_stable_(maps_are_stable) {
+ : HTemplateInstruction<2>(HType::HeapObject()),
+ maps_(maps),
+ bit_field_(HasMigrationTargetField::encode(false) |
+ IsStabilityCheckField::encode(false) |
+ MapsAreStableField::encode(maps_are_stable)) {
DCHECK_NE(0, maps->size());
SetOperandAt(0, value);
// Use the object value for the dependency.
@@ -2818,9 +2846,11 @@ class HCheckMaps FINAL : public HTemplateInstruction<2> {
}
HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
- : HTemplateInstruction<2>(HType::HeapObject()), maps_(maps),
- has_migration_target_(false), is_stability_check_(false),
- maps_are_stable_(true) {
+ : HTemplateInstruction<2>(HType::HeapObject()),
+ maps_(maps),
+ bit_field_(HasMigrationTargetField::encode(false) |
+ IsStabilityCheckField::encode(false) |
+ MapsAreStableField::encode(true)) {
DCHECK_NE(0, maps->size());
SetOperandAt(0, value);
// Use the object value for the dependency if NULL is passed.
@@ -2831,16 +2861,22 @@ class HCheckMaps FINAL : public HTemplateInstruction<2> {
SetDependsOnFlag(kElementsKind);
for (int i = 0; i < maps->size(); ++i) {
Handle<Map> map = maps->at(i).handle();
- if (map->is_migration_target()) has_migration_target_ = true;
- if (!map->is_stable()) maps_are_stable_ = false;
+ if (map->is_migration_target()) {
+ bit_field_ = HasMigrationTargetField::update(bit_field_, true);
+ }
+ if (!map->is_stable()) {
+ bit_field_ = MapsAreStableField::update(bit_field_, false);
+ }
}
- if (has_migration_target_) SetChangesFlag(kNewSpacePromotion);
+ if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
}
+ class HasMigrationTargetField : public BitField<bool, 0, 1> {};
+ class IsStabilityCheckField : public BitField<bool, 1, 1> {};
+ class MapsAreStableField : public BitField<bool, 2, 1> {};
+
const UniqueSet<Map>* maps_;
- bool has_migration_target_ : 1;
- bool is_stability_check_ : 1;
- bool maps_are_stable_ : 1;
+ uint32_t bit_field_;
};
@@ -3537,29 +3573,26 @@ class HConstant FINAL : public HTemplateInstruction<0> {
isolate->factory()->NewNumber(double_value_, TENURED));
}
AllowDeferredHandleDereference smi_check;
- DCHECK(has_int32_value_ || !object_.handle()->IsSmi());
+ DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
return object_.handle();
}
bool IsSpecialDouble() const {
- return has_double_value_ &&
+ return HasDoubleValue() &&
(bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
FixedDoubleArray::is_the_hole_nan(double_value_) ||
std::isnan(double_value_));
}
bool NotInNewSpace() const {
- return is_not_in_new_space_;
+ return IsNotInNewSpaceField::decode(bit_field_);
}
bool ImmortalImmovable() const;
bool IsCell() const {
- return instance_type_ == CELL_TYPE || instance_type_ == PROPERTY_CELL_TYPE;
- }
-
- bool IsMap() const {
- return instance_type_ == MAP_TYPE;
+ InstanceType instance_type = GetInstanceType();
+ return instance_type == CELL_TYPE || instance_type == PROPERTY_CELL_TYPE;
}
virtual Representation RequiredInputRepresentation(int index) OVERRIDE {
@@ -3579,13 +3612,17 @@ class HConstant FINAL : public HTemplateInstruction<0> {
HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
- bool HasInteger32Value() const { return has_int32_value_; }
+ bool HasInteger32Value() const {
+ return HasInt32ValueField::decode(bit_field_);
+ }
int32_t Integer32Value() const {
DCHECK(HasInteger32Value());
return int32_value_;
}
- bool HasSmiValue() const { return has_smi_value_; }
- bool HasDoubleValue() const { return has_double_value_; }
+ bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
+ bool HasDoubleValue() const {
+ return HasDoubleValueField::decode(bit_field_);
+ }
double DoubleValue() const {
DCHECK(HasDoubleValue());
return double_value_;
@@ -3597,7 +3634,7 @@ class HConstant FINAL : public HTemplateInstruction<0> {
return object_.IsInitialized() &&
object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
}
- bool HasNumberValue() const { return has_double_value_; }
+ bool HasNumberValue() const { return HasDoubleValue(); }
int32_t NumberValueAsInteger32() const {
DCHECK(HasNumberValue());
// Irrespective of whether a numeric HConstant can be safely
@@ -3606,38 +3643,42 @@ class HConstant FINAL : public HTemplateInstruction<0> {
return int32_value_;
}
bool HasStringValue() const {
- if (has_double_value_ || has_int32_value_) return false;
+ if (HasNumberValue()) return false;
DCHECK(!object_.handle().is_null());
- return instance_type_ < FIRST_NONSTRING_TYPE;
+ return GetInstanceType() < FIRST_NONSTRING_TYPE;
}
Handle<String> StringValue() const {
DCHECK(HasStringValue());
return Handle<String>::cast(object_.handle());
}
bool HasInternalizedStringValue() const {
- return HasStringValue() && StringShape(instance_type_).IsInternalized();
+ return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
}
bool HasExternalReferenceValue() const {
- return has_external_reference_value_;
+ return HasExternalReferenceValueField::decode(bit_field_);
}
ExternalReference ExternalReferenceValue() const {
return external_reference_value_;
}
bool HasBooleanValue() const { return type_.IsBoolean(); }
- bool BooleanValue() const { return boolean_value_; }
- bool IsUndetectable() const { return is_undetectable_; }
- InstanceType GetInstanceType() const { return instance_type_; }
+ bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
+ bool IsUndetectable() const {
+ return IsUndetectableField::decode(bit_field_);
+ }
+ InstanceType GetInstanceType() const {
+ return InstanceTypeField::decode(bit_field_);
+ }
- bool HasMapValue() const { return instance_type_ == MAP_TYPE; }
+ bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
Unique<Map> MapValue() const {
DCHECK(HasMapValue());
return Unique<Map>::cast(GetUnique());
}
bool HasStableMapValue() const {
- DCHECK(HasMapValue() || !has_stable_map_value_);
- return has_stable_map_value_;
+ DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
+ return HasStableMapValueField::decode(bit_field_);
}
bool HasObjectMap() const { return !object_map_.IsNull(); }
@@ -3647,11 +3688,11 @@ class HConstant FINAL : public HTemplateInstruction<0> {
}
virtual intptr_t Hashcode() OVERRIDE {
- if (has_int32_value_) {
+ if (HasInteger32Value()) {
return static_cast<intptr_t>(int32_value_);
- } else if (has_double_value_) {
+ } else if (HasDoubleValue()) {
return static_cast<intptr_t>(bit_cast<int64_t>(double_value_));
- } else if (has_external_reference_value_) {
+ } else if (HasExternalReferenceValue()) {
return reinterpret_cast<intptr_t>(external_reference_value_.address());
} else {
DCHECK(!object_.handle().is_null());
@@ -3660,7 +3701,7 @@ class HConstant FINAL : public HTemplateInstruction<0> {
}
virtual void FinalizeUniqueness() OVERRIDE {
- if (!has_double_value_ && !has_external_reference_value_) {
+ if (!HasDoubleValue() && !HasExternalReferenceValue()) {
DCHECK(!object_.handle().is_null());
object_ = Unique<Object>(object_.handle());
}
@@ -3676,21 +3717,21 @@ class HConstant FINAL : public HTemplateInstruction<0> {
virtual bool DataEquals(HValue* other) OVERRIDE {
HConstant* other_constant = HConstant::cast(other);
- 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_ &&
+ if (HasInteger32Value()) {
+ return other_constant->HasInteger32Value() &&
+ int32_value_ == other_constant->int32_value_;
+ } else if (HasDoubleValue()) {
+ return other_constant->HasDoubleValue() &&
bit_cast<int64_t>(double_value_) ==
bit_cast<int64_t>(other_constant->double_value_);
- } else if (has_external_reference_value_) {
- return other_constant->has_external_reference_value_ &&
- external_reference_value_ ==
- other_constant->external_reference_value_;
+ } else if (HasExternalReferenceValue()) {
+ return other_constant->HasExternalReferenceValue() &&
+ external_reference_value_ ==
+ other_constant->external_reference_value_;
} else {
- if (other_constant->has_int32_value_ ||
- other_constant->has_double_value_ ||
- other_constant->has_external_reference_value_) {
+ if (other_constant->HasInteger32Value() ||
+ other_constant->HasDoubleValue() ||
+ other_constant->HasExternalReferenceValue()) {
return false;
}
DCHECK(!object_.handle().is_null());
@@ -3735,6 +3776,25 @@ class HConstant FINAL : public HTemplateInstruction<0> {
virtual bool IsDeletable() const OVERRIDE { return true; }
+ // If object_ is a map, this indicates whether the map is stable.
+ class HasStableMapValueField : public BitField<bool, 0, 1> {};
+
+ // We store the HConstant in the most specific form safely possible.
+ // These flags tell us if the respective member fields hold valid, safe
+ // representations of the constant. More specific flags imply more general
+ // flags, but not the converse (i.e. smi => int32 => double).
+ class HasSmiValueField : public BitField<bool, 1, 1> {};
+ class HasInt32ValueField : public BitField<bool, 2, 1> {};
+ class HasDoubleValueField : public BitField<bool, 3, 1> {};
+
+ class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
+ class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
+ class BooleanValueField : public BitField<bool, 6, 1> {};
+ class IsUndetectableField : public BitField<bool, 7, 1> {};
+
+ static const InstanceType kUnknownInstanceType = FILLER_TYPE;
+ class InstanceTypeField : public BitField<InstanceType, 8, 8> {};
+
// If this is a numerical constant, object_ either points to the
// HeapObject the constant originated from or is null. If the
// constant is non-numeric, object_ always points to a valid
@@ -3744,27 +3804,11 @@ class HConstant FINAL : public HTemplateInstruction<0> {
// If object_ is a heap object, this points to the stable map of the object.
Unique<Map> object_map_;
- // If object_ is a map, this indicates whether the map is stable.
- bool has_stable_map_value_ : 1;
+ uint32_t bit_field_;
- // 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_smi_value_ : 1;
- bool has_int32_value_ : 1;
- bool has_double_value_ : 1;
- bool has_external_reference_value_ : 1;
- bool is_not_in_new_space_ : 1;
- bool boolean_value_ : 1;
- bool is_undetectable_: 1;
int32_t int32_value_;
double double_value_;
ExternalReference external_reference_value_;
-
- static const InstanceType kUnknownInstanceType = FILLER_TYPE;
- InstanceType instance_type_;
};
@@ -5312,6 +5356,12 @@ class HParameter FINAL : public HTemplateInstruction<0> {
return Representation::None();
}
+ virtual Representation KnownOptimalRepresentation() OVERRIDE {
+ // If a parameter is an input to a phi, that phi should not
+ // choose any more optimistic representation than Tagged.
+ return Representation::Tagged();
+ }
+
DECLARE_CONCRETE_INSTRUCTION(Parameter)
private:
@@ -6739,8 +6789,8 @@ class HLoadKeyed FINAL
kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
};
- STATIC_ASSERT((kBitsForElementsKind + kBitsForBaseOffset +
- kBitsForIsDehoisted) <= sizeof(uint32_t)*8);
+ STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
+ kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
class ElementsKindField:
public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
@@ -6845,7 +6895,8 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
} else if (field_representation().IsDouble()) {
return field_representation();
} else if (field_representation().IsSmi()) {
- if (SmiValuesAre32Bits() && store_mode_ == STORE_TO_INITIALIZED_ENTRY) {
+ if (SmiValuesAre32Bits() &&
+ store_mode() == STORE_TO_INITIALIZED_ENTRY) {
return Representation::Integer32();
}
return field_representation();
@@ -6870,8 +6921,10 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
HObjectAccess access() const { return access_; }
HValue* dominator() const { return dominator_; }
- bool has_transition() const { return has_transition_; }
- StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
+ bool has_transition() const { return HasTransitionField::decode(bit_field_); }
+ StoreFieldOrKeyedMode store_mode() const {
+ return StoreModeField::decode(bit_field_);
+ }
Handle<Map> transition_map() const {
if (has_transition()) {
@@ -6885,7 +6938,7 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
void SetTransition(HConstant* transition) {
DCHECK(!has_transition()); // Only set once.
SetOperandAt(2, transition);
- has_transition_ = true;
+ bit_field_ = HasTransitionField::update(bit_field_, true);
SetChangesFlag(kMaps);
}
@@ -6936,14 +6989,12 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
}
private:
- HStoreNamedField(HValue* obj,
- HObjectAccess access,
- HValue* val,
+ HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
: access_(access),
dominator_(NULL),
- has_transition_(false),
- store_mode_(store_mode) {
+ bit_field_(HasTransitionField::encode(false) |
+ StoreModeField::encode(store_mode)) {
// Stores to a non existing in-object property are allowed only to the
// newly allocated objects (via HAllocate or HInnerAllocatedObject).
DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
@@ -6954,10 +7005,12 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
access.SetGVNFlags(this, STORE);
}
+ class HasTransitionField : public BitField<bool, 0, 1> {};
+ class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
+
HObjectAccess access_;
HValue* dominator_;
- bool has_transition_ : 1;
- StoreFieldOrKeyedMode store_mode_ : 1;
+ uint32_t bit_field_;
};
@@ -7024,7 +7077,7 @@ class HStoreKeyed FINAL
}
DCHECK_EQ(index, 2);
- return RequiredValueRepresentation(elements_kind_, store_mode_);
+ return RequiredValueRepresentation(elements_kind(), store_mode());
}
static Representation RequiredValueRepresentation(
@@ -7065,7 +7118,8 @@ class HStoreKeyed FINAL
if (IsUninitialized()) {
return Representation::None();
}
- Representation r = RequiredValueRepresentation(elements_kind_, store_mode_);
+ Representation r =
+ RequiredValueRepresentation(elements_kind(), store_mode());
// For fast object elements kinds, don't assume anything.
if (r.IsTagged()) return Representation::None();
return r;
@@ -7074,22 +7128,26 @@ class HStoreKeyed FINAL
HValue* elements() const { return OperandAt(0); }
HValue* key() const { return OperandAt(1); }
HValue* value() const { return OperandAt(2); }
- bool value_is_smi() const {
- return IsFastSmiElementsKind(elements_kind_);
+ bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
+ StoreFieldOrKeyedMode store_mode() const {
+ return StoreModeField::decode(bit_field_);
+ }
+ ElementsKind elements_kind() const OVERRIDE {
+ return ElementsKindField::decode(bit_field_);
}
- StoreFieldOrKeyedMode store_mode() const { return store_mode_; }
- ElementsKind elements_kind() const OVERRIDE { return elements_kind_; }
uint32_t base_offset() const { return base_offset_; }
bool TryIncreaseBaseOffset(uint32_t increase_by_value) OVERRIDE;
HValue* GetKey() OVERRIDE { return key(); }
void SetKey(HValue* key) OVERRIDE { SetOperandAt(1, key); }
- bool IsDehoisted() const OVERRIDE { return is_dehoisted_; }
+ bool IsDehoisted() const OVERRIDE {
+ return IsDehoistedField::decode(bit_field_);
+ }
void SetDehoisted(bool is_dehoisted) OVERRIDE {
- is_dehoisted_ = is_dehoisted;
+ bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
}
- bool IsUninitialized() { return is_uninitialized_; }
+ bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
void SetUninitialized(bool is_uninitialized) {
- is_uninitialized_ = is_uninitialized;
+ bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
}
bool IsConstantHoleStore() {
@@ -7125,18 +7183,17 @@ class HStoreKeyed FINAL
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
private:
- HStoreKeyed(HValue* obj, HValue* key, HValue* val,
- ElementsKind elements_kind,
+ HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind,
StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
int offset = kDefaultKeyedHeaderOffsetSentinel)
- : elements_kind_(elements_kind),
- base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
- ? GetDefaultHeaderSizeForElementsKind(elements_kind)
- : offset),
- is_dehoisted_(false),
- is_uninitialized_(false),
- store_mode_(store_mode),
- dominator_(NULL) {
+ : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
+ ? GetDefaultHeaderSizeForElementsKind(elements_kind)
+ : offset),
+ bit_field_(IsDehoistedField::encode(false) |
+ IsUninitializedField::encode(false) |
+ StoreModeField::encode(store_mode) |
+ ElementsKindField::encode(elements_kind)),
+ dominator_(NULL) {
SetOperandAt(0, obj);
SetOperandAt(1, key);
SetOperandAt(2, val);
@@ -7168,11 +7225,13 @@ class HStoreKeyed FINAL
}
}
- ElementsKind elements_kind_;
+ class IsDehoistedField : public BitField<bool, 0, 1> {};
+ class IsUninitializedField : public BitField<bool, 1, 1> {};
+ class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
+ class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
+
uint32_t base_offset_;
- bool is_dehoisted_ : 1;
- bool is_uninitialized_ : 1;
- StoreFieldOrKeyedMode store_mode_: 1;
+ uint32_t bit_field_;
HValue* dominator_;
};
@@ -7496,23 +7555,25 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral)
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
- bool pretenure() const { return pretenure_; }
- bool has_no_literals() const { return has_no_literals_; }
- bool is_arrow() const { return IsArrowFunction(kind_); }
- bool is_generator() const { return IsGeneratorFunction(kind_); }
- bool is_concise_method() const { return IsConciseMethod(kind_); }
- FunctionKind kind() const { return kind_; }
- StrictMode strict_mode() const { return strict_mode_; }
+ bool pretenure() const { return PretenureField::decode(bit_field_); }
+ bool has_no_literals() const {
+ return HasNoLiteralsField::decode(bit_field_);
+ }
+ bool is_arrow() const { return IsArrowFunction(kind()); }
+ bool is_generator() const { return IsGeneratorFunction(kind()); }
+ bool is_concise_method() const { return IsConciseMethod(kind()); }
+ FunctionKind kind() const { return FunctionKindField::decode(bit_field_); }
+ StrictMode strict_mode() const { return StrictModeField::decode(bit_field_); }
private:
HFunctionLiteral(HValue* context, Handle<SharedFunctionInfo> shared,
bool pretenure)
: HTemplateInstruction<1>(HType::JSObject()),
shared_info_(shared),
- kind_(shared->kind()),
- pretenure_(pretenure),
- has_no_literals_(shared->num_literals() == 0),
- strict_mode_(shared->strict_mode()) {
+ bit_field_(FunctionKindField::encode(shared->kind()) |
+ PretenureField::encode(pretenure) |
+ HasNoLiteralsField::encode(shared->num_literals() == 0) |
+ StrictModeField::encode(shared->strict_mode())) {
SetOperandAt(0, context);
set_representation(Representation::Tagged());
SetChangesFlag(kNewSpacePromotion);
@@ -7520,11 +7581,13 @@ class HFunctionLiteral FINAL : public HTemplateInstruction<1> {
virtual bool IsDeletable() const OVERRIDE { return true; }
+ class FunctionKindField : public BitField<FunctionKind, 0, 3> {};
+ class PretenureField : public BitField<bool, 3, 1> {};
+ class HasNoLiteralsField : public BitField<bool, 4, 1> {};
+ class StrictModeField : public BitField<StrictMode, 5, 1> {};
+
Handle<SharedFunctionInfo> shared_info_;
- FunctionKind kind_;
- bool pretenure_ : 1;
- bool has_no_literals_ : 1;
- StrictMode strict_mode_;
+ uint32_t bit_field_;
};
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 58c124fe6..b638857cc 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -10,14 +10,11 @@
namespace v8 {
namespace internal {
-CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
- const char* name,
- const char* name_prefix,
- const char* resource_name,
- int line_number,
- int column_number)
- : tag_(tag),
- builtin_id_(Builtins::builtin_count),
+CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, const char* name,
+ const char* name_prefix, const char* resource_name,
+ int line_number, int column_number)
+ : bit_field_(TagField::encode(tag) |
+ BuiltinIdField::encode(Builtins::builtin_count)),
name_prefix_(name_prefix),
name_(name),
resource_name_(resource_name),
@@ -26,7 +23,7 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
shared_id_(0),
script_id_(v8::UnboundScript::kNoScriptId),
no_frame_ranges_(NULL),
- bailout_reason_(kEmptyBailoutReason) { }
+ bailout_reason_(kEmptyBailoutReason) {}
bool CodeEntry::is_js_function_tag(Logger::LogEventsAndTags tag) {
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 6017f12dc..4607156a4 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -143,7 +143,7 @@ CodeEntry::~CodeEntry() {
uint32_t CodeEntry::GetCallUid() const {
- uint32_t hash = ComputeIntegerHash(tag_, v8::internal::kZeroHashSeed);
+ uint32_t hash = ComputeIntegerHash(tag(), v8::internal::kZeroHashSeed);
if (shared_id_ != 0) {
hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_),
v8::internal::kZeroHashSeed);
@@ -164,20 +164,18 @@ uint32_t CodeEntry::GetCallUid() const {
bool CodeEntry::IsSameAs(CodeEntry* entry) const {
- return this == entry
- || (tag_ == entry->tag_
- && shared_id_ == entry->shared_id_
- && (shared_id_ != 0
- || (name_prefix_ == entry->name_prefix_
- && name_ == entry->name_
- && resource_name_ == entry->resource_name_
- && line_number_ == entry->line_number_)));
+ return this == entry ||
+ (tag() == entry->tag() && shared_id_ == entry->shared_id_ &&
+ (shared_id_ != 0 ||
+ (name_prefix_ == entry->name_prefix_ && name_ == entry->name_ &&
+ resource_name_ == entry->resource_name_ &&
+ line_number_ == entry->line_number_)));
}
void CodeEntry::SetBuiltinId(Builtins::Name id) {
- tag_ = Logger::BUILTIN_TAG;
- builtin_id_ = id;
+ bit_field_ = TagField::update(bit_field_, Logger::BUILTIN_TAG);
+ bit_field_ = BuiltinIdField::update(bit_field_, id);
}
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 5ebb92bba..f78beb041 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -55,7 +55,7 @@ class CodeEntry {
int column_number = v8::CpuProfileNode::kNoColumnNumberInfo);
~CodeEntry();
- bool is_js_function() const { return is_js_function_tag(tag_); }
+ bool is_js_function() const { return is_js_function_tag(tag()); }
const char* name_prefix() const { return name_prefix_; }
bool has_name_prefix() const { return name_prefix_[0] != '\0'; }
const char* name() const { return name_; }
@@ -78,7 +78,9 @@ class CodeEntry {
}
void SetBuiltinId(Builtins::Name id);
- Builtins::Name builtin_id() const { return builtin_id_; }
+ Builtins::Name builtin_id() const {
+ return BuiltinIdField::decode(bit_field_);
+ }
uint32_t GetCallUid() const;
bool IsSameAs(CodeEntry* entry) const;
@@ -88,8 +90,11 @@ class CodeEntry {
static const char* const kEmptyBailoutReason;
private:
- Logger::LogEventsAndTags tag_ : 8;
- Builtins::Name builtin_id_ : 8;
+ class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {};
+ class BuiltinIdField : public BitField<Builtins::Name, 8, 8> {};
+ Logger::LogEventsAndTags tag() const { return TagField::decode(bit_field_); }
+
+ uint32_t bit_field_;
const char* name_prefix_;
const char* name_;
const char* resource_name_;
diff --git a/src/runtime/runtime-array.cc b/src/runtime/runtime-array.cc
index c3a6d80ec..523d8f5fa 100644
--- a/src/runtime/runtime-array.cc
+++ b/src/runtime/runtime-array.cc
@@ -104,19 +104,19 @@ class ArrayConcatVisitor {
storage_(Handle<FixedArray>::cast(
isolate->global_handles()->Create(*storage))),
index_offset_(0u),
- fast_elements_(fast_elements),
- exceeds_array_limit_(false) {}
+ bit_field_(FastElementsField::encode(fast_elements) |
+ ExceedsLimitField::encode(false)) {}
~ArrayConcatVisitor() { clear_storage(); }
void visit(uint32_t i, Handle<Object> elm) {
if (i > JSObject::kMaxElementCount - index_offset_) {
- exceeds_array_limit_ = true;
+ set_exceeds_array_limit(true);
return;
}
uint32_t index = index_offset_ + i;
- if (fast_elements_) {
+ if (fast_elements()) {
if (index < static_cast<uint32_t>(storage_->length())) {
storage_->set(index, *elm);
return;
@@ -128,7 +128,7 @@ class ArrayConcatVisitor {
SetDictionaryMode();
// Fall-through to dictionary mode.
}
- DCHECK(!fast_elements_);
+ DCHECK(!fast_elements());
Handle<SeededNumberDictionary> dict(
SeededNumberDictionary::cast(*storage_));
Handle<SeededNumberDictionary> result =
@@ -149,21 +149,23 @@ class ArrayConcatVisitor {
// If the initial length estimate was off (see special case in visit()),
// but the array blowing the limit didn't contain elements beyond the
// provided-for index range, go to dictionary mode now.
- if (fast_elements_ &&
+ if (fast_elements() &&
index_offset_ >
static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
SetDictionaryMode();
}
}
- bool exceeds_array_limit() { return exceeds_array_limit_; }
+ bool exceeds_array_limit() const {
+ return ExceedsLimitField::decode(bit_field_);
+ }
Handle<JSArray> ToArray() {
Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
Handle<Object> length =
isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Handle<Map> map = JSObject::GetElementsTransitionMap(
- array, fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
+ array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
array->set_map(*map);
array->set_length(*length);
array->set_elements(*storage_);
@@ -173,7 +175,7 @@ class ArrayConcatVisitor {
private:
// Convert storage to dictionary mode.
void SetDictionaryMode() {
- DCHECK(fast_elements_);
+ DCHECK(fast_elements());
Handle<FixedArray> current_storage(*storage_);
Handle<SeededNumberDictionary> slow_storage(
SeededNumberDictionary::New(isolate_, current_storage->length()));
@@ -191,7 +193,7 @@ class ArrayConcatVisitor {
}
clear_storage();
set_storage(*slow_storage);
- fast_elements_ = false;
+ set_fast_elements(false);
}
inline void clear_storage() {
@@ -203,13 +205,23 @@ class ArrayConcatVisitor {
Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage));
}
+ class FastElementsField : public BitField<bool, 0, 1> {};
+ class ExceedsLimitField : public BitField<bool, 1, 1> {};
+
+ bool fast_elements() const { return FastElementsField::decode(bit_field_); }
+ void set_fast_elements(bool fast) {
+ bit_field_ = FastElementsField::update(bit_field_, fast);
+ }
+ void set_exceeds_array_limit(bool exceeds) {
+ bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
+ }
+
Isolate* isolate_;
Handle<FixedArray> storage_; // Always a global handle.
// Index after last seen index. Always less than or equal to
// JSObject::kMaxElementCount.
uint32_t index_offset_;
- bool fast_elements_ : 1;
- bool exceeds_array_limit_ : 1;
+ uint32_t bit_field_;
};
diff --git a/src/scanner.cc b/src/scanner.cc
index 8062faa24..e63239d6e 100644
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -245,6 +245,8 @@ bool Scanner::SkipWhiteSpace() {
while (true) {
while (true) {
+ // The unicode cache accepts unsigned inputs.
+ if (c0_ < 0) break;
// Advance as long as character is a WhiteSpace or LineTerminator.
// Remember if the latter is the case.
if (unicode_cache_->IsLineTerminator(c0_)) {
@@ -365,7 +367,7 @@ Token::Value Scanner::SkipMultiLineComment() {
while (c0_ >= 0) {
uc32 ch = c0_;
Advance();
- if (unicode_cache_->IsLineTerminator(ch)) {
+ if (c0_ >= 0 && unicode_cache_->IsLineTerminator(ch)) {
// Following ECMA-262, section 7.4, a comment containing
// a newline will make the comment count as a line-terminator.
has_multiline_comment_before_next_ = true;
@@ -625,14 +627,14 @@ void Scanner::Scan() {
break;
default:
- if (unicode_cache_->IsIdentifierStart(c0_)) {
+ if (c0_ < 0) {
+ token = Token::EOS;
+ } else if (unicode_cache_->IsIdentifierStart(c0_)) {
token = ScanIdentifierOrKeyword();
} else if (IsDecimalDigit(c0_)) {
token = ScanNumber(false);
} else if (SkipWhiteSpace()) {
token = Token::WHITESPACE;
- } else if (c0_ < 0) {
- token = Token::EOS;
} else {
token = Select(Token::ILLEGAL);
}
@@ -674,7 +676,7 @@ bool Scanner::ScanEscape() {
Advance();
// Skip escaped newlines.
- if (unicode_cache_->IsLineTerminator(c)) {
+ if (c0_ >= 0 && unicode_cache_->IsLineTerminator(c)) {
// Allow CR+LF newlines in multiline string literals.
if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
// Allow LF+CR newlines in multiline string literals.
@@ -871,7 +873,8 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
// not be an identifier start or a decimal digit; see ECMA-262
// section 7.8.3, page 17 (note that we read only one decimal digit
// if the value is 0).
- if (IsDecimalDigit(c0_) || unicode_cache_->IsIdentifierStart(c0_))
+ if (IsDecimalDigit(c0_) ||
+ (c0_ >= 0 && unicode_cache_->IsIdentifierStart(c0_)))
return Token::ILLEGAL;
literal.Complete();
@@ -1039,7 +1042,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
AddLiteralChar(first_char);
// Scan the rest of the identifier characters.
- while (unicode_cache_->IsIdentifierPart(c0_)) {
+ while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
if (c0_ != '\\') {
uc32 next_char = c0_;
Advance();
@@ -1067,7 +1070,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal) {
// Scan the rest of the identifier characters.
- while (unicode_cache_->IsIdentifierPart(c0_)) {
+ while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier part characters.
@@ -1106,10 +1109,10 @@ bool Scanner::ScanRegExpPattern(bool seen_equal) {
}
while (c0_ != '/' || in_character_class) {
- if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+ if (c0_ < 0 || unicode_cache_->IsLineTerminator(c0_)) return false;
if (c0_ == '\\') { // Escape sequence.
AddLiteralCharAdvance();
- if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+ if (c0_ < 0 || unicode_cache_->IsLineTerminator(c0_)) return false;
AddLiteralCharAdvance();
// If the escape allows more characters, i.e., \x??, \u????, or \c?,
// only "safe" characters are allowed (letters, digits, underscore),
@@ -1156,7 +1159,7 @@ bool Scanner::ScanLiteralUnicodeEscape() {
bool Scanner::ScanRegExpFlags() {
// Scan regular expression flags.
LiteralScope literal(this);
- while (unicode_cache_->IsIdentifierPart(c0_)) {
+ while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
if (c0_ != '\\') {
AddLiteralCharAdvance();
} else {
diff --git a/src/unicode-inl.h b/src/unicode-inl.h
index d47ee3e0c..0f78d39e0 100644
--- a/src/unicode-inl.h
+++ b/src/unicode-inl.h
@@ -13,7 +13,7 @@ namespace unibrow {
template <class T, int s> bool Predicate<T, s>::get(uchar code_point) {
CacheEntry entry = entries_[code_point & kMask];
- if (entry.code_point_ == code_point) return entry.value_;
+ if (entry.code_point() == code_point) return entry.value();
return CalculateValue(code_point);
}
diff --git a/src/unicode.h b/src/unicode.h
index 1af6170fc..166681426 100644
--- a/src/unicode.h
+++ b/src/unicode.h
@@ -7,6 +7,7 @@
#include <sys/types.h>
#include "src/globals.h"
+#include "src/utils.h"
/**
* \file
* Definitions and convenience functions for working with unicode.
@@ -28,16 +29,26 @@ class Predicate {
public:
inline Predicate() { }
inline bool get(uchar c);
+
private:
friend class Test;
bool CalculateValue(uchar c);
- struct CacheEntry {
- inline CacheEntry() : code_point_(0), value_(0) { }
+ class CacheEntry {
+ public:
+ inline CacheEntry()
+ : bit_field_(CodePointField::encode(0) | ValueField::encode(0)) {}
inline CacheEntry(uchar code_point, bool value)
- : code_point_(code_point),
- value_(value) { }
- uchar code_point_ : 21;
- bool value_ : 1;
+ : bit_field_(CodePointField::encode(code_point) |
+ ValueField::encode(value)) {}
+
+ uchar code_point() const { return CodePointField::decode(bit_field_); }
+ bool value() const { return ValueField::decode(bit_field_); }
+
+ private:
+ class CodePointField : public v8::internal::BitField<uchar, 0, 21> {};
+ class ValueField : public v8::internal::BitField<bool, 21, 1> {};
+
+ uint32_t bit_field_;
};
static const int kSize = size;
static const int kMask = kSize - 1;
diff --git a/src/utils.h b/src/utils.h
index dcefa4407..d5685c982 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -230,6 +230,14 @@ class BitFieldBase {
};
+template <class T, int shift, int size>
+class BitField8 : public BitFieldBase<T, shift, size, uint8_t> {};
+
+
+template <class T, int shift, int size>
+class BitField16 : public BitFieldBase<T, shift, size, uint16_t> {};
+
+
template<class T, int shift, int size>
class BitField : public BitFieldBase<T, shift, size, uint32_t> { };
diff --git a/src/version.cc b/src/version.cc
index c348bc0a2..6b9481c55 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 30
-#define BUILD_NUMBER 35
+#define BUILD_NUMBER 36
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index 723f0e8c8..8bd03e69d 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -202,7 +202,7 @@
'math-floor-of-div-nosudiv': [PASS, SLOW, ['arch not in [arm, arm64, android_arm, android_arm64]', SKIP]],
# Too slow for slow variants.
- 'asm/embenchen/*': [PASS, FAST_VARIANTS]
+ 'asm/embenchen/*': [PASS, FAST_VARIANTS],
}], # ALWAYS
##############################################################################
@@ -245,6 +245,9 @@
'math-floor-of-div': [PASS, NO_VARIANTS],
'unicodelctest': [PASS, NO_VARIANTS],
'unicodelctest-no-optimization': [PASS, NO_VARIANTS],
+
+ # Too slow for gc stress.
+ 'asm/embenchen/box2d': [SKIP],
}], # 'gc_stress == True'
##############################################################################
@@ -296,6 +299,8 @@
'array-reduce': [PASS, SLOW],
'array-sort': [PASS, SLOW],
'array-splice': [PASS, SLOW],
+ 'asm/embenchen/box2d': [PASS, TIMEOUT],
+ 'asm/embenchen/lua_binarytrees': [PASS, TIMEOUT],
'bit-not': [PASS, SLOW],
'compiler/alloc-number': [PASS, SLOW],
'compiler/osr-assert': [PASS, SLOW],
diff --git a/test/mjsunit/regress/regress-assignment-in-test-context.js b/test/mjsunit/regress/regress-assignment-in-test-context.js
new file mode 100644
index 000000000..bc4098554
--- /dev/null
+++ b/test/mjsunit/regress/regress-assignment-in-test-context.js
@@ -0,0 +1,20 @@
+// Copyright 2014 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.
+
+// Flags: --allow-natives-syntax --always-opt
+// Flags: --turbo-filter=* --turbo-deoptimization
+
+function assertEquals() {}
+
+function f(o) {
+ if (o.setterProperty = 0) {
+ return 1;
+ }
+ return 2;
+}
+
+function deopt() { %DeoptimizeFunction(f); }
+
+assertEquals(2,
+ f(Object.defineProperty({}, "setterProperty", { set: deopt })));
diff --git a/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc b/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
index f5891d24f..0b3a0f5a4 100644
--- a/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
+++ b/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
@@ -161,12 +161,12 @@ const MachInst1 kAddSubOneInstructions[] = {
const IntCmp kCmpInstructions[] = {
{{&RawMachineAssembler::WordEqual, "WordEqual", kMipsCmp, kMachInt16}, 1U},
{{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMipsCmp, kMachInt16},
- 2U},
+ 1U},
{{&RawMachineAssembler::Word32Equal, "Word32Equal", kMipsCmp, kMachInt32},
1U},
{{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMipsCmp,
kMachInt32},
- 2U},
+ 1U},
{{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMipsCmp,
kMachInt32},
1U},
@@ -779,10 +779,9 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kMipsTst, s[0]->arch_opcode());
+ EXPECT_EQ(kMipsCmp, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kEqual, s[0]->flags_condition());
@@ -792,10 +791,9 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kMipsTst, s[0]->arch_opcode());
+ EXPECT_EQ(kMipsCmp, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kEqual, s[0]->flags_condition());
diff --git a/tools/push-to-trunk/merge_to_branch.py b/tools/push-to-trunk/merge_to_branch.py
index 927e504f7..da9d3101a 100755
--- a/tools/push-to-trunk/merge_to_branch.py
+++ b/tools/push-to-trunk/merge_to_branch.py
@@ -32,6 +32,9 @@ import sys
from common_includes import *
+def IsSvnNumber(rev):
+ return rev.isdigit() and len(rev) < 8
+
class Preparation(Step):
MESSAGE = "Preparation."
@@ -72,24 +75,21 @@ class SearchArchitecturePorts(Step):
self._options.revisions))
port_revision_list = []
for revision in self["full_revision_list"]:
- # Search for commits which matches the "Port rXXX" pattern.
+ # Search for commits which matches the "Port XXX" pattern.
git_hashes = self.GitLog(reverse=True, format="%H",
- grep="Port r%d" % int(revision),
+ grep="Port %s" % revision,
branch=self.vc.RemoteMasterBranch())
for git_hash in git_hashes.splitlines():
- svn_revision = self.vc.GitSvn(git_hash, self.vc.RemoteMasterBranch())
- if not svn_revision: # pragma: no cover
- self.Die("Cannot determine svn revision for %s" % git_hash)
revision_title = self.GitLog(n=1, format="%s", git_hash=git_hash)
# Is this revision included in the original revision list?
- if svn_revision in self["full_revision_list"]:
- print("Found port of r%s -> r%s (already included): %s"
- % (revision, svn_revision, revision_title))
+ if git_hash in self["full_revision_list"]:
+ print("Found port of %s -> %s (already included): %s"
+ % (revision, git_hash, revision_title))
else:
- print("Found port of r%s -> r%s: %s"
- % (revision, svn_revision, revision_title))
- port_revision_list.append(svn_revision)
+ print("Found port of %s -> %s: %s"
+ % (revision, git_hash, revision_title))
+ port_revision_list.append(git_hash)
# Do we find any port?
if len(port_revision_list) > 0:
@@ -99,16 +99,10 @@ class SearchArchitecturePorts(Step):
self["full_revision_list"].extend(port_revision_list)
-class FindGitRevisions(Step):
- MESSAGE = "Find the git revisions associated with the patches."
+class CreateCommitMessage(Step):
+ MESSAGE = "Create commit message."
def RunStep(self):
- self["patch_commit_hashes"] = []
- for revision in self["full_revision_list"]:
- next_hash = self.vc.SvnGit(revision, self.vc.RemoteMasterBranch())
- if not next_hash: # pragma: no cover
- self.Die("Cannot determine git hash for r%s" % revision)
- self["patch_commit_hashes"].append(next_hash)
# Stringify: [123, 234] -> "r123, r234"
self["revision_list"] = ", ".join(map(lambda s: "r%s" % s,
@@ -117,29 +111,38 @@ class FindGitRevisions(Step):
if not self["revision_list"]: # pragma: no cover
self.Die("Revision list is empty.")
+ if self._options.revert and not self._options.revert_bleeding_edge:
+ action_text = "Rollback of %s"
+ else:
+ action_text = "Merged %s"
+
# The commit message title is added below after the version is specified.
- self["new_commit_msg"] = ""
+ msg_pieces = [
+ "\n".join(action_text % s for s in self["full_revision_list"]),
+ ]
+ msg_pieces.append("\n\n")
- for commit_hash in self["patch_commit_hashes"]:
+ for commit_hash in self["full_revision_list"]:
patch_merge_desc = self.GitLog(n=1, format="%s", git_hash=commit_hash)
- self["new_commit_msg"] += "%s\n\n" % patch_merge_desc
+ msg_pieces.append("%s\n\n" % patch_merge_desc)
bugs = []
- for commit_hash in self["patch_commit_hashes"]:
+ for commit_hash in self["full_revision_list"]:
msg = self.GitLog(n=1, git_hash=commit_hash)
- for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg,
- re.M):
- bugs.extend(map(lambda s: s.strip(), bug.split(",")))
+ for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg, re.M):
+ bugs.extend(s.strip() for s in bug.split(","))
bug_aggregate = ",".join(sorted(filter(lambda s: s and s != "none", bugs)))
if bug_aggregate:
- self["new_commit_msg"] += "BUG=%s\nLOG=N\n" % bug_aggregate
+ msg_pieces.append("BUG=%s\nLOG=N\n" % bug_aggregate)
+
+ self["new_commit_msg"] = "".join(msg_pieces)
class ApplyPatches(Step):
MESSAGE = "Apply patches for selected revisions."
def RunStep(self):
- for commit_hash in self["patch_commit_hashes"]:
+ for commit_hash in self["full_revision_list"]:
print("Applying patch for %s to %s..."
% (commit_hash, self["merge_to_branch"]))
patch = self.GitGetPatch(commit_hash)
@@ -189,17 +192,14 @@ class CommitLocal(Step):
def RunStep(self):
# Add a commit message title.
- if self._options.revert:
- if not self._options.revert_bleeding_edge:
- title = ("Version %s (rollback of %s)"
- % (self["version"], self["revision_list"]))
- else:
- title = "Revert %s." % self["revision_list"]
+ if self._options.revert and self._options.revert_bleeding_edge:
+ # TODO(machenbach): Find a better convention if multiple patches are
+ # reverted in one CL.
+ self["commit_title"] = "Revert on master"
else:
- title = ("Version %s (merged %s)"
- % (self["version"], self["revision_list"]))
- self["commit_title"] = title
- self["new_commit_msg"] = "%s\n\n%s" % (title, self["new_commit_msg"])
+ self["commit_title"] = "Version %s (cherry-pick)" % self["version"]
+ self["new_commit_msg"] = "%s\n\n%s" % (self["commit_title"],
+ self["new_commit_msg"])
TextToFile(self["new_commit_msg"], self.Config("COMMITMSG_FILE"))
self.GitCommit(file_name=self.Config("COMMITMSG_FILE"))
@@ -275,6 +275,17 @@ class MergeToBranch(ScriptsBase):
options.bypass_upload_hooks = True
# CC ulan to make sure that fixes are merged to Google3.
options.cc = "ulan@chromium.org"
+
+ # Thd old git-svn workflow is deprecated for this script.
+ assert options.vc_interface != "git_svn"
+
+ # Make sure to use git hashes in the new workflows.
+ for revision in options.revisions:
+ if (IsSvnNumber(revision) or
+ (revision[0:1] == "r" and IsSvnNumber(revision[1:]))):
+ print "Please provide full git hashes of the patches to merge."
+ print "Got: %s" % revision
+ return False
return True
def _Config(self):
@@ -292,7 +303,7 @@ class MergeToBranch(ScriptsBase):
Preparation,
CreateBranch,
SearchArchitecturePorts,
- FindGitRevisions,
+ CreateCommitMessage,
ApplyPatches,
PrepareVersion,
IncrementVersion,
diff --git a/tools/push-to-trunk/releases.py b/tools/push-to-trunk/releases.py
index 53648a618..2090c00fe 100755
--- a/tools/push-to-trunk/releases.py
+++ b/tools/push-to-trunk/releases.py
@@ -33,10 +33,18 @@ PUSH_MSG_GIT_RE = re.compile(r".* \(based on ([a-fA-F0-9]+)\)$")
# (old and new format).
MERGE_MESSAGE_RE = re.compile(r"^.*[M|m]erged (.+)(\)| into).*$", re.M)
+CHERRY_PICK_TITLE_GIT_RE = re.compile(r"^.* \(cherry\-pick\)\.?$")
+
+# New git message for cherry-picked CLs. One message per line.
+MERGE_MESSAGE_GIT_RE = re.compile(r"^Merged ([a-fA-F0-9]+)\.?$")
+
# Expression for retrieving reverted patches from a commit message (old and
# new format).
ROLLBACK_MESSAGE_RE = re.compile(r"^.*[R|r]ollback of (.+)(\)| in).*$", re.M)
+# New git message for reverted CLs. One message per line.
+ROLLBACK_MESSAGE_GIT_RE = re.compile(r"^Rollback of ([a-fA-F0-9]+)\.?$")
+
# Expression for retrieving the code review link.
REVIEW_LINK_RE = re.compile(r"^Review URL: (.+)$", re.M)
@@ -143,6 +151,18 @@ class RetrieveV8Releases(Step):
patches = "-%s" % patches
return patches
+ def GetMergedPatchesGit(self, body):
+ patches = []
+ for line in body.splitlines():
+ patch = MatchSafe(MERGE_MESSAGE_GIT_RE.match(line))
+ if patch:
+ patches.append(patch)
+ patch = MatchSafe(ROLLBACK_MESSAGE_GIT_RE.match(line))
+ if patch:
+ patches.append("-%s" % patch)
+ return ", ".join(patches)
+
+
def GetReleaseDict(
self, git_hash, bleeding_edge_rev, bleeding_edge_git, branch, version,
patches, cl_body):
@@ -185,7 +205,10 @@ class RetrieveV8Releases(Step):
patches = ""
if self["patch"] != "0":
version += ".%s" % self["patch"]
- patches = self.GetMergedPatches(body)
+ if CHERRY_PICK_TITLE_GIT_RE.match(body.splitlines()[0]):
+ patches = self.GetMergedPatchesGit(body)
+ else:
+ patches = self.GetMergedPatches(body)
title = self.GitLog(n=1, format="%s", git_hash=git_hash)
bleeding_edge_revision = self.GetBleedingEdgeFromPush(title)
diff --git a/tools/push-to-trunk/test_scripts.py b/tools/push-to-trunk/test_scripts.py
index f31c491dc..41cc97f77 100644
--- a/tools/push-to-trunk/test_scripts.py
+++ b/tools/push-to-trunk/test_scripts.py
@@ -503,7 +503,7 @@ class ScriptTest(unittest.TestCase):
Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""),
])
args = ["--branch", "candidates", "--vc-interface", "git_read_svn_write",
- "12345"]
+ "ab12345"]
self._state["version"] = "tag_name"
self._state["commit_title"] = "Title"
self.assertRaises(Exception,
@@ -1225,137 +1225,13 @@ deps = {
return lambda: self.assertEquals(patch,
FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"]))
- msg = """Version 3.22.5.1 (merged r12345, r23456, r34567, r45678, r56789)
+ msg = """Version 3.22.5.1 (cherry-pick)
-Title4
-
-Title2
-
-Title3
-
-Title1
-
-Revert "Something"
-
-BUG=123,234,345,456,567,v8:123
-LOG=N
-"""
-
- def VerifySVNCommit():
- commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
- self.assertEquals(msg, commit)
- version = FileToText(
- os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
- self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
- self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
- self.assertTrue(re.search(r"#define PATCH_LEVEL\s+1", version))
- self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
-
- self.Expect([
- Cmd("git status -s -uno", ""),
- Cmd("git status -s -b -uno", "## some_branch\n"),
- Cmd("git svn fetch", ""),
- Cmd("git branch", " branch1\n* branch2\n"),
- Cmd("git new-branch %s --upstream svn/trunk" % TEST_CONFIG["BRANCHNAME"],
- ""),
- Cmd(("git log --format=%H --grep=\"Port r12345\" "
- "--reverse svn/bleeding_edge"),
- "hash1\nhash2"),
- Cmd("git svn find-rev hash1 svn/bleeding_edge", "45678"),
- Cmd("git log -1 --format=%s hash1", "Title1"),
- Cmd("git svn find-rev hash2 svn/bleeding_edge", "23456"),
- Cmd("git log -1 --format=%s hash2", "Title2"),
- Cmd(("git log --format=%H --grep=\"Port r23456\" "
- "--reverse svn/bleeding_edge"),
- ""),
- Cmd(("git log --format=%H --grep=\"Port r34567\" "
- "--reverse svn/bleeding_edge"),
- "hash3"),
- Cmd("git svn find-rev hash3 svn/bleeding_edge", "56789"),
- Cmd("git log -1 --format=%s hash3", "Title3"),
- RL("Y"), # Automatically add corresponding ports (34567, 56789)?
- Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
- # Simulate svn being down which stops the script.
- Cmd("git svn find-rev r23456 svn/bleeding_edge", None),
- # Restart script in the failing step.
- Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
- Cmd("git svn find-rev r23456 svn/bleeding_edge", "hash2"),
- Cmd("git svn find-rev r34567 svn/bleeding_edge", "hash3"),
- Cmd("git svn find-rev r45678 svn/bleeding_edge", "hash1"),
- Cmd("git svn find-rev r56789 svn/bleeding_edge", "hash5"),
- Cmd("git log -1 --format=%s hash4", "Title4"),
- Cmd("git log -1 --format=%s hash2", "Title2"),
- Cmd("git log -1 --format=%s hash3", "Title3"),
- Cmd("git log -1 --format=%s hash1", "Title1"),
- Cmd("git log -1 --format=%s hash5", "Revert \"Something\""),
- Cmd("git log -1 hash4", "Title4\nBUG=123\nBUG=234"),
- Cmd("git log -1 hash2", "Title2\n BUG = v8:123,345"),
- Cmd("git log -1 hash3", "Title3\nLOG=n\nBUG=567, 456"),
- Cmd("git log -1 hash1", "Title1\nBUG="),
- Cmd("git log -1 hash5", "Revert \"Something\"\nBUG=none"),
- Cmd("git log -1 -p hash4", "patch4"),
- Cmd(("git apply --index --reject \"%s\"" %
- TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
- "", cb=VerifyPatch("patch4")),
- Cmd("git log -1 -p hash2", "patch2"),
- Cmd(("git apply --index --reject \"%s\"" %
- TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
- "", cb=VerifyPatch("patch2")),
- Cmd("git log -1 -p hash3", "patch3"),
- Cmd(("git apply --index --reject \"%s\"" %
- TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
- "", cb=VerifyPatch("patch3")),
- Cmd("git log -1 -p hash1", "patch1"),
- Cmd(("git apply --index --reject \"%s\"" %
- TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
- "", cb=VerifyPatch("patch1")),
- Cmd("git log -1 -p hash5", "patch5\n"),
- Cmd(("git apply --index --reject \"%s\"" %
- TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
- "", cb=VerifyPatch("patch5\n")),
- Cmd("git apply --index --reject \"%s\"" % extra_patch, ""),
- RL("Y"), # Automatically increment patch level?
- Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], ""),
- RL("reviewer@chromium.org"), # V8 reviewer.
- Cmd("git cl upload --send-mail -r \"reviewer@chromium.org\" "
- "--bypass-hooks --cc \"ulan@chromium.org\"", ""),
- Cmd("git checkout -f %s" % TEST_CONFIG["BRANCHNAME"], ""),
- RL("LGTM"), # Enter LGTM for V8 CL.
- Cmd("git cl presubmit", "Presubmit successfull\n"),
- Cmd("git cl dcommit -f --bypass-hooks", "Closing issue\n",
- cb=VerifySVNCommit),
- Cmd("git svn fetch", ""),
- Cmd("git rebase svn/trunk", ""),
- Cmd("git svn tag 3.22.5.1 -m \"Tagging version 3.22.5.1\"", ""),
- Cmd("git checkout -f some_branch", ""),
- Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
- ])
-
- # r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS
- # ports of r12345. r56789 is the MIPS port of r34567.
- args = ["-f", "-p", extra_patch, "--branch", "trunk",
- "--vc-interface", "git_svn", "12345", "23456", "34567"]
-
- # The first run of the script stops because of the svn being down.
- self.assertRaises(GitFailedException,
- lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
-
- # Test that state recovery after restarting the script works.
- args += ["-s", "4"]
- MergeToBranch(TEST_CONFIG, self).Run(args)
-
- def testMergeToBranchNewGit(self):
- TEST_CONFIG["ALREADY_MERGING_SENTINEL_FILE"] = self.MakeEmptyTempFile()
- TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
- self.WriteFakeVersionFile(build=5)
- os.environ["EDITOR"] = "vi"
- extra_patch = self.MakeEmptyTempFile()
-
- def VerifyPatch(patch):
- return lambda: self.assertEquals(patch,
- FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"]))
-
- msg = """Version 3.22.5.1 (merged r12345, r23456, r34567, r45678, r56789)
+Merged ab12345
+Merged ab23456
+Merged ab34567
+Merged ab45678
+Merged ab56789
Title4
@@ -1389,59 +1265,49 @@ LOG=N
Cmd("git branch", " branch1\n* branch2\n"),
Cmd("git new-branch %s --upstream origin/candidates" %
TEST_CONFIG["BRANCHNAME"], ""),
- Cmd(("git log --format=%H --grep=\"Port r12345\" "
+ Cmd(("git log --format=%H --grep=\"Port ab12345\" "
"--reverse origin/master"),
- "hash1\nhash2"),
- Cmd("git svn find-rev hash1 origin/master", "45678"),
- Cmd("git log -1 --format=%s hash1", "Title1"),
- Cmd("git svn find-rev hash2 origin/master", "23456"),
- Cmd("git log -1 --format=%s hash2", "Title2"),
- Cmd(("git log --format=%H --grep=\"Port r23456\" "
+ "ab45678\nab23456"),
+ Cmd("git log -1 --format=%s ab45678", "Title1"),
+ Cmd("git log -1 --format=%s ab23456", "Title2"),
+ Cmd(("git log --format=%H --grep=\"Port ab23456\" "
"--reverse origin/master"),
""),
- Cmd(("git log --format=%H --grep=\"Port r34567\" "
+ Cmd(("git log --format=%H --grep=\"Port ab34567\" "
"--reverse origin/master"),
- "hash3"),
- Cmd("git svn find-rev hash3 origin/master", "56789"),
- Cmd("git log -1 --format=%s hash3", "Title3"),
- RL("Y"), # Automatically add corresponding ports (34567, 56789)?
- Cmd("git svn find-rev r12345 origin/master",
- "Partial-rebuilding bla\nDone rebuilding blub\nhash4"),
- # Simulate svn being down which stops the script.
- Cmd("git svn find-rev r23456 origin/master", None),
+ "ab56789"),
+ Cmd("git log -1 --format=%s ab56789", "Title3"),
+ RL("Y"), # Automatically add corresponding ports (ab34567, ab56789)?
+ # Simulate git being down which stops the script.
+ Cmd("git log -1 --format=%s ab12345", None),
# Restart script in the failing step.
- Cmd("git svn find-rev r12345 origin/master", "hash4"),
- Cmd("git svn find-rev r23456 origin/master", "hash2"),
- Cmd("git svn find-rev r34567 origin/master", "hash3"),
- Cmd("git svn find-rev r45678 origin/master", "hash1"),
- Cmd("git svn find-rev r56789 origin/master", "hash5"),
- Cmd("git log -1 --format=%s hash4", "Title4"),
- Cmd("git log -1 --format=%s hash2", "Title2"),
- Cmd("git log -1 --format=%s hash3", "Title3"),
- Cmd("git log -1 --format=%s hash1", "Title1"),
- Cmd("git log -1 --format=%s hash5", "Revert \"Something\""),
- Cmd("git log -1 hash4", "Title4\nBUG=123\nBUG=234"),
- Cmd("git log -1 hash2", "Title2\n BUG = v8:123,345"),
- Cmd("git log -1 hash3", "Title3\nLOG=n\nBUG=567, 456"),
- Cmd("git log -1 hash1", "Title1\nBUG="),
- Cmd("git log -1 hash5", "Revert \"Something\"\nBUG=none"),
- Cmd("git log -1 -p hash4", "patch4"),
+ Cmd("git log -1 --format=%s ab12345", "Title4"),
+ Cmd("git log -1 --format=%s ab23456", "Title2"),
+ Cmd("git log -1 --format=%s ab34567", "Title3"),
+ Cmd("git log -1 --format=%s ab45678", "Title1"),
+ Cmd("git log -1 --format=%s ab56789", "Revert \"Something\""),
+ Cmd("git log -1 ab12345", "Title4\nBUG=123\nBUG=234"),
+ Cmd("git log -1 ab23456", "Title2\n BUG = v8:123,345"),
+ Cmd("git log -1 ab34567", "Title3\nLOG=n\nBUG=567, 456"),
+ Cmd("git log -1 ab45678", "Title1\nBUG="),
+ Cmd("git log -1 ab56789", "Revert \"Something\"\nBUG=none"),
+ Cmd("git log -1 -p ab12345", "patch4"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
"", cb=VerifyPatch("patch4")),
- Cmd("git log -1 -p hash2", "patch2"),
+ Cmd("git log -1 -p ab23456", "patch2"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
"", cb=VerifyPatch("patch2")),
- Cmd("git log -1 -p hash3", "patch3"),
+ Cmd("git log -1 -p ab34567", "patch3"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
"", cb=VerifyPatch("patch3")),
- Cmd("git log -1 -p hash1", "patch1"),
+ Cmd("git log -1 -p ab45678", "patch1"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
"", cb=VerifyPatch("patch1")),
- Cmd("git log -1 -p hash5", "patch5\n"),
+ Cmd("git log -1 -p ab56789", "patch5\n"),
Cmd(("git apply --index --reject \"%s\"" %
TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
"", cb=VerifyPatch("patch5\n")),
@@ -1458,12 +1324,12 @@ LOG=N
cb=VerifySVNCommit),
Cmd("git fetch", ""),
Cmd("git log -1 --format=%H --grep=\""
- "Version 3.22.5.1 (merged r12345, r23456, r34567, r45678, r56789)"
+ "Version 3.22.5.1 (cherry-pick)"
"\" origin/candidates",
""),
Cmd("git fetch", ""),
Cmd("git log -1 --format=%H --grep=\""
- "Version 3.22.5.1 (merged r12345, r23456, r34567, r45678, r56789)"
+ "Version 3.22.5.1 (cherry-pick)"
"\" origin/candidates",
"hsh_to_tag"),
Cmd("git tag 3.22.5.1 hsh_to_tag", ""),
@@ -1472,12 +1338,12 @@ LOG=N
Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
])
- # r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS
- # ports of r12345. r56789 is the MIPS port of r34567.
+ # ab12345 and ab34567 are patches. ab23456 (included) and ab45678 are the
+ # MIPS ports of ab12345. ab56789 is the MIPS port of ab34567.
args = ["-f", "-p", extra_patch, "--branch", "candidates",
- "--vc-interface", "git_read_svn_write", "12345", "23456", "34567"]
+ "ab12345", "ab23456", "ab34567"]
- # The first run of the script stops because of the svn being down.
+ # The first run of the script stops because of git being down.
self.assertRaises(GitFailedException,
lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
@@ -1569,7 +1435,9 @@ git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b
Cmd("git checkout -f hash_234 -- %s" % VERSION_FILE, "",
cb=ResetVersion(3, 1, 1)),
Cmd("git log -1 --format=%B hash_234",
- "Version 3.3.1.1 (merged 12)\n\nReview URL: fake.com\n"),
+ "Version 3.3.1.1 (cherry-pick).\n\n"
+ "Merged abc12.\n\n"
+ "Review URL: fake.com\n"),
Cmd("git log -1 --format=%s hash_234", ""),
Cmd("git svn find-rev hash_234", "234"),
Cmd("git log -1 --format=%ci hash_234", "18:15"),
@@ -1655,7 +1523,7 @@ git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b
"3.28.40,master,22624,4567,\r\n"
"3.22.3,candidates,345,3456:4566,\r\n"
"3.21.2,3.21,123,,\r\n"
- "3.3.1.1,3.3,234,,12\r\n")
+ "3.3.1.1,3.3,234,,abc12\r\n")
self.assertEquals(csv, FileToText(csv_output))
expected_json = [
@@ -1718,7 +1586,7 @@ git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b
{
"revision": "234",
"revision_git": "hash_234",
- "patches_merged": "12",
+ "patches_merged": "abc12",
"bleeding_edge": "",
"bleeding_edge_git": "",
"version": "3.3.1.1",
diff --git a/tools/run-tests.py b/tools/run-tests.py
index dc73a4035..20f36798a 100755
--- a/tools/run-tests.py
+++ b/tools/run-tests.py
@@ -44,6 +44,7 @@ import time
from testrunner.local import execution
from testrunner.local import progress
from testrunner.local import testsuite
+from testrunner.local.testsuite import VARIANT_FLAGS
from testrunner.local import utils
from testrunner.local import verbose
from testrunner.network import network_execution
@@ -83,13 +84,6 @@ TIMEOUT_DEFAULT = 60
TIMEOUT_SCALEFACTOR = {"debug" : 4,
"release" : 1 }
-# Use this to run several variants of the tests.
-VARIANT_FLAGS = {
- "default": [],
- "stress": ["--stress-opt", "--always-opt"],
- "turbofan": ["--turbo-asm", "--turbo-filter=*", "--always-opt"],
- "nocrankshaft": ["--nocrankshaft"]}
-
VARIANTS = ["default", "stress", "turbofan", "nocrankshaft"]
MODE_FLAGS = {
diff --git a/tools/testrunner/local/testsuite.py b/tools/testrunner/local/testsuite.py
index 24161f388..6ff97b34b 100644
--- a/tools/testrunner/local/testsuite.py
+++ b/tools/testrunner/local/testsuite.py
@@ -34,6 +34,17 @@ from . import statusfile
from . import utils
from ..objects import testcase
+# Use this to run several variants of the tests.
+VARIANT_FLAGS = {
+ "default": [],
+ "stress": ["--stress-opt", "--always-opt"],
+ "turbofan": ["--turbo-asm", "--turbo-filter=*", "--always-opt"],
+ "nocrankshaft": ["--nocrankshaft"]}
+
+FAST_VARIANT_FLAGS = [
+ f for v, f in VARIANT_FLAGS.iteritems() if v in ["default", "turbofan"]
+]
+
class TestSuite(object):
@staticmethod
@@ -82,7 +93,7 @@ class TestSuite(object):
if testcase.outcomes and statusfile.OnlyStandardVariant(testcase.outcomes):
return [[]]
if testcase.outcomes and statusfile.OnlyFastVariants(testcase.outcomes):
- return filter(lambda v: v in ["default", "turbofan"], default_flags)
+ return filter(lambda flags: flags in FAST_VARIANT_FLAGS, default_flags)
return default_flags
def DownloadData(self):
diff --git a/tools/whitespace.txt b/tools/whitespace.txt
index 19a732534..55592a925 100644
--- a/tools/whitespace.txt
+++ b/tools/whitespace.txt
@@ -5,4 +5,4 @@ Try to write something funny. And please don't add trailing whitespace.
A Smi walks into a bar and says:
"I'm so deoptimized today!"
The doubles heard this and started to unbox.
-The Smi looked at them when a crazy v8-autoroll account showed up.......
+The Smi looked at them when a crazy v8-autoroll account showed up........