diff options
author | Android Chromium Automerger <chromium-automerger@android> | 2014-11-06 12:27:01 +0000 |
---|---|---|
committer | Android Chromium Automerger <chromium-automerger@android> | 2014-11-06 12:27:01 +0000 |
commit | 1be894bddf75cd9c7c7fb70be799509a9bb5db67 (patch) | |
tree | c7a2c40173c3580552bf9be3f44d0f03dc34c253 | |
parent | d07e97064dabc32fba2092ff45db7d74a2cf650b (diff) | |
parent | bb795f939b910c87673062e98640d11a20fe258d (diff) | |
download | v8-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
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; @@ -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........ |